Update to the latest version of VerifyNoBS

This commit is contained in:
Maurice Parker 2021-11-05 15:27:34 -05:00
parent 06eae25797
commit 0fe3ccbc11
3 changed files with 156 additions and 89 deletions

View File

@ -3760,7 +3760,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "xcrun -sdk macosx swiftc -target x86_64-macosx10.11 buildscripts/VerifyNoBuildSettings.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n\n\nif [ $? -ne 0 ]\nthen\n echo \"error: Build Setting were found in the project.pbxproj file. Most likely you didn't intend to change this file and should revert it.\"\n exit 1\nfi\n";
shellScript = "xcrun -sdk macosx swift buildscripts/VerifyNoBS.swift --xcode ${PROJECT_DIR}/${PROJECT_NAME}.xcodeproj/project.pbxproj\n";
};
/* End PBXShellScriptBuildPhase section */
@ -4742,8 +4742,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
PRODUCT_NAME = NetNewsWire;
};
name = Debug;
};
@ -4751,8 +4749,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
PRODUCT_NAME = NetNewsWire;
};
name = Release;
};

155
buildscripts/VerifyNoBS.swift Executable file
View File

@ -0,0 +1,155 @@
#!/usr/bin/swift
// This script is meant to be called from an Xcode run script build phase
// It verifies there are no buildSettings embedded in the Xcode project
// as it is preferable to have build settings specified in .xcconfig files
// How to use:
// Put this script in a folder called 'buildscripts' next to your xcode project
// Then, add a Run script build phase to one of your targets with this as the script
//
// xcrun -sdk macosx swift buildscripts/VerifyNoBS.swift --xcode ${PROJECT_DIR}/${PROJECT_NAME}.xcodeproj/project.pbxproj
//
import Darwin
import Foundation
/// A message with its file name and location
struct LocatedMessage {
let message: String
let fileUrl: URL
let line: Int
}
/// Utility to process the pbxproj file
struct BuildSettingsVerifier {
public enum ProcessXcodeprojResult {
case foundBuildSettings([LocatedMessage])
case error(String)
case success(String)
}
/// Mode to run the utility in. Mode defines the output format
public enum Mode {
/// Write errors to stderr
case cmd
/// Write errors to stdout in a format that is picked up by Xcode
case xcode
}
/// The mode to run in
let mode: Mode
/// The absolute file URL to the pbxproj file
let projUrl: URL
init(mode: Mode, projUrl: URL) {
self.mode = mode
self.projUrl = projUrl
}
/// Reports an error either to stderr or to stdout, depending on the mode
func reportError(message: String, fileUrl: URL? = nil, line: Int? = nil) {
switch mode {
case .cmd:
let stderr = FileHandle.standardError
if let data = "\(message)\n".data(using: String.Encoding.utf8, allowLossyConversion: false) {
stderr.write(data)
} else {
print("There was an error. Could not convert error message to printable string")
}
case .xcode:
var messageParts = [String]()
if let fileUrl = fileUrl {
messageParts.append("\(fileUrl.path):")
}
if let line = line {
messageParts.append("\(line): ")
}
messageParts.append("error: \(message)")
print(messageParts.joined())
}
}
/// Inspect the pbxproj file for non-empty buildSettings
func processXcodeprojAt(url: URL) -> ProcessXcodeprojResult {
let startTime = Date()
guard let xcodeproj = try? String(contentsOf: url, encoding: String.Encoding.utf8) else {
return .error("Failed to read xcodeproj contents from \(url)")
}
let lines = xcodeproj.components(separatedBy: CharacterSet.newlines)
print("Found \(lines.count) lines")
var locatedMessages: [LocatedMessage] = []
var inBuildSettingsBlock = false
for (lineIndex, nthLine) in lines.enumerated() {
if inBuildSettingsBlock {
if nthLine.range(of: "\\u007d[:space:]*;", options: .regularExpression) != nil {
inBuildSettingsBlock = false
} else if nthLine.range(of: "CODE_SIGN_IDENTITY") != nil {
} else {
let message = mode == .cmd ? " \(nthLine)\n" : "Setting '\(nthLine.trimmingCharacters(in: .whitespacesAndNewlines))' should be in an xcconfig file"
locatedMessages.append(LocatedMessage(
message: message,
fileUrl: url,
line: lineIndex + 1
))
}
} else {
if nthLine.range(of: "buildSettings[:space:]*=", options: .regularExpression) != nil {
inBuildSettingsBlock = true
}
}
}
let timeInterval = Date().timeIntervalSince(startTime)
print("Process took \(timeInterval) seconds")
if locatedMessages.count > 0 {
return .foundBuildSettings(locatedMessages)
}
return .success(":-)")
}
public func verify() -> Int32 {
print("Verifying there are no build settings...")
let result = processXcodeprojAt(url: projUrl)
switch result {
case .error(let str):
reportError(message: "Error verifying build settings: \(str)")
return EXIT_FAILURE
case .foundBuildSettings(let locatedMessages):
reportError(message: "Found build settings in project file")
for msg in locatedMessages {
reportError(message: msg.message, fileUrl: msg.fileUrl, line: msg.line)
}
return EXIT_FAILURE
case .success:
print("No build settings found in project file")
return EXIT_SUCCESS
}
}
}
var commandLineArgs = CommandLine.arguments.dropFirst()
//print("processArgs were \(commandLineArgs)")
if commandLineArgs.count < 1 {
print("Usage: \(#file) [--xcode] /path/to/Project.xcodeproj/project.pbxproj")
exit(EXIT_FAILURE)
} else {
let xcodeProjFilePath = commandLineArgs.removeLast()
let mode: BuildSettingsVerifier.Mode = commandLineArgs.count > 0 && commandLineArgs.last == "--xcode" ? .xcode : .cmd
let myUrl = URL(fileURLWithPath: xcodeProjFilePath)
let verifier = BuildSettingsVerifier(mode: mode, projUrl: myUrl)
let exitCode = verifier.verify()
exit(exitCode)
}

View File

@ -1,84 +0,0 @@
#!/usr/bin/swift
// This script is originally from github.com/olofhellman/VerifyNoBS
// The idea is that all build settings should be kept in .xcconfig files,
// rather than in the xcode pbxproj file inside an Xcode project bundle
// Having the script run as part of a regular build ensures that the project file
// doesn't accidentally accumulate build settings
import Darwin
import Foundation
func reportError(message: String) {
print("error message was \(message)")
let stderr = FileHandle.standardError
if let data = message.data(using: String.Encoding.utf8, allowLossyConversion: false) {
stderr.write(data)
} else {
print("there was an error. script \"VerifyNoBuildSettings\" could not convert error message to printable string")
}
}
public enum ProcessXcodeprojResult {
case FoundBuildSettings([String])
case Error(String)
case OK(String)
}
public func processXcodeprojAt(url: URL) -> ProcessXcodeprojResult {
let startTime = Date()
guard let xcodeproj = try? String(contentsOf: url, encoding: String.Encoding.utf8) else {
return .Error("script \"VerifyNoBuildSettings\" failed making xcodeproj from url")
}
let lines = xcodeproj.components(separatedBy: CharacterSet.newlines)
print ("found \(lines.count) lines")
var badLines: [String] = []
var inBuildSettingsBlock = false
for nthLine in lines {
if inBuildSettingsBlock {
if let _ = nthLine.range(of:"\\u007d[:space:]*;", options: .regularExpression) {
inBuildSettingsBlock = false
} else if let _ = nthLine.range(of:"CODE_SIGN_IDENTITY") {
} else if let _ = nthLine.range(of:"PRODUCT_NAME") {
} else {
badLines.append(nthLine)
}
} else {
if let _ = nthLine.range(of:"buildSettings[:space:]*=", options: .regularExpression) {
inBuildSettingsBlock = true
}
}
}
let timeInterval = Date().timeIntervalSince(startTime)
print ("process took \(timeInterval) seconds")
if (badLines.count > 0) {
return .FoundBuildSettings(badLines)
}
return .OK(":-)")
}
print("Verifying no buildSettings...")
let commandLineArgs = CommandLine.arguments
print("processArgs were \(commandLineArgs)")
let xcodeprojfilepath = commandLineArgs[1]
let myUrl = URL(fileURLWithPath:xcodeprojfilepath)
let result = processXcodeprojAt(url: myUrl)
switch result {
case .Error(let str):
reportError (message: "error script \"VerifyNoBuildSettings\" encountered an error: \(str)")
exit(EXIT_FAILURE)
case .FoundBuildSettings(let badLines):
reportError (message: "script \"VerifyNoBuildSettings\" found build settings in the project file:")
for badLine in badLines {
reportError (message: " \(badLine)\n")
}
exit(EXIT_FAILURE)
case .OK:
print ("script \"VerifyNoBuildSettings\" verified the project contained no buildSettings")
exit(EXIT_SUCCESS)
}