Merge branch 'master' into 20211121-incremental-installation

This commit is contained in:
Bartosz Polaczyk
2021-12-02 08:56:26 +01:00
29 changed files with 206 additions and 104 deletions
+2 -1
View File
@@ -5,4 +5,5 @@
DerivedData
/.swiftpm/
releases
tmp/
tmp/
.idea/
+1
View File
@@ -5,6 +5,7 @@ disabled_rules:
- superfluous_disable_command # Disabled since we disable some rules pre-emptively to avoid issues in the future
- todo # Temporarily disabled. We have too many right now hiding real issues :(
- nesting # Does not make sense anymore since Swift 4 uses nested `CodingKeys` enums for example
- trailing_dot_in_comments # Triggers warnings for generated file headers
opt_in_rules:
- anyobject_protocol
+1 -1
View File
@@ -372,7 +372,7 @@ Head over to our [cocoapods-plugin](cocoapods-plugin/README.md) docs to see how
## Limitations
* Swift Package Manager (SPM) projects are not supported
* Swift Package Manager (SPM) dependencies are not supported. _Because SPM does not allow customizing Build Settings, XCRemoteCache cannot specify `clang` and `swiftc` wrappers that control if the local compilation should be skipped (cache hit) or not (cache miss)_
* Filenames with `_vers.c` suffix are reserved and cannot be used as a source file
* All compilation files should be referenced via the git repo root. Referencing `/AbsolutePath/someOther.swift` or `../../someOther.swift` that resolve to the location outside of the git repo root is prohibited.
+1 -1
View File
@@ -28,7 +28,7 @@ task :lint => [:prepare] do
puts 'Run linting'
system("swiftformat --lint --config .swiftformat --cache ignore .") or abort "swiftformat failure" if SWIFTFORMAT_ENABLED
system("swiftlint lint --config .swiftlint.yml") or abort "swiftlint failure" if SWIFTLINT_ENABLED
system("swiftlint lint --config .swiftlint.yml --strict") or abort "swiftlint failure" if SWIFTLINT_ENABLED
end
task :autocorrect => [:prepare] do
@@ -40,7 +40,7 @@ class ThinningDiskSwiftcProductsGenerator: SwiftcProductsGenerator {
destinationSwiftmodulePaths = Dictionary(
uniqueKeysWithValues: SwiftmoduleFileExtension.SwiftmoduleExtensions
.map { ext, _ in
switch (ext) {
switch ext {
case .swiftsourceinfo:
let dest = modulePathDir.appendingPathComponent("Project")
.appendingPathComponent(moduleName)
@@ -55,6 +55,7 @@ class Prebuild {
self.artifactConsumerPrebuildPlugins = artifactConsumerPrebuildPlugins
}
// swiftlint:disable:next function_body_length
public func perform() throws -> PrebuildResult {
guard case .available(let commit) = context.remoteCommit else {
return .incompatible
@@ -129,7 +129,10 @@ public class XCPrebuild {
algorithm: MD5Algorithm()
)
let organizer = ZipArtifactOrganizer(targetTempDir: context.targetTempDir, fileManager: fileManager)
let compilationHistoryOrganizer = CompilationHistoryFileOrganizer(context.compilationHistoryFile, fileManager: fileManager)
let compilationHistoryOrganizer = CompilationHistoryFileOrganizer(
context.compilationHistoryFile,
fileManager: fileManager
)
let metaReader = JsonMetaReader(fileAccessor: fileManager)
var consumerPlugins: [ArtifactConsumerPrebuildPlugin] = []
@@ -79,6 +79,7 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
/// Generates source of the cc wrapper
// swiftlint:disable line_length
// swiftlint:disable:next function_body_length
private func buildWrapperSource(clangCommand: String, markerFilename: String, commitSha: String) -> String {
return """
@@ -516,5 +517,5 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
#pragma GCC diagnostic pop
}
"""
} // swiftlint:disable:next file_length
}
} // swiftlint:disable:next file_length line_length
} // swiftlint:enable line_length
@@ -56,7 +56,7 @@ class FileLLDBInitPatcher: LLDBInitPatcher {
}
private func findIndices(in collection: [String], value: String) -> [Int] {
collection.enumerated().reduce([]) { (result, line) -> [Int] in
collection.enumerated().reduce([]) { result, line -> [Int] in
if line.element == Self.preambleString {
return result + [line.offset]
}
@@ -75,7 +75,7 @@ class FileLLDBInitPatcher: LLDBInitPatcher {
var contentLines = originalContentLines
let preambleIndices = findIndices(in: contentLines, value: Self.preambleString)
if preambleIndices.count > 0 {
if !preambleIndices.isEmpty {
let firstLLDBCommandIndex = preambleIndices[0] + 1
if firstLLDBCommandIndex >= contentLines.count {
// corrupted file, append the script line at the bottom
@@ -64,6 +64,7 @@ public class XCIntegrate {
self.output = output
}
// swiftlint:disable:next function_body_length
public func main() {
do {
let env = ProcessInfo.processInfo.environment
@@ -114,7 +115,7 @@ public class XCIntegrate {
let integrator = XcodeProjIntegrate(
project: context.projectPath,
mode:context.mode,
mode: context.mode,
binaries: context.binaries,
configurationIncludeOracle: configurationOracle,
targetIncludeOracle: targetOracle,
@@ -114,7 +114,9 @@ struct XcodeProjIntegrate: Integrate {
markPhase = PBXShellScriptBuildPhase(
name: "\(Self.BuildStepPrefix)RemoteCache_mark",
inputPaths: [binaries.prepare.path],
shellScript: "\"$SCRIPT_INPUT_FILE_0\" mark --configuration \"$CONFIGURATION\" --platform \"$PLATFORM_NAME\""
shellScript:
"\"$SCRIPT_INPUT_FILE_0\" mark " +
"--configuration \"$CONFIGURATION\" --platform \"$PLATFORM_NAME\""
)
}
@@ -129,6 +131,7 @@ struct XcodeProjIntegrate: Integrate {
try encodedYAML.write(to: configOverrideLocation, atomically: false, encoding: .utf8)
}
// swiftlint:disable:next function_body_length
func run() throws {
let outputFile = output ?? projectURL
let projectRoot = projectURL.deletingLastPathComponent()
@@ -100,7 +100,7 @@ struct XcodeSettingsCFlags: XcodeSettingsFlags {
case (.some(let existing), _):
var flagsComponents: [String] = existing.split(separator: " ").map(String.init)
// remove (if exists)
let existingFlagIndex = flagsComponents.firstIndex { (component) -> Bool in
let existingFlagIndex = flagsComponents.firstIndex { component -> Bool in
component.hasPrefix("\(Self.prefix)\(key)=")
}
if let index = existingFlagIndex {
@@ -38,6 +38,7 @@ public class XCPrepareMark {
self.commit = commit
}
// swiftlint:disable:next function_body_length
public func main() {
let env = ProcessInfo.processInfo.environment
let fileManager = FileManager.default
@@ -101,7 +101,10 @@ public class XCSwiftc {
objcHeaderOutput: context.objcHeaderOutput,
diskCopier: HardLinkDiskCopier(fileManager: fileManager)
)
let allInvocationsStorage = ExistingFileStorage(storageFile: context.invocationHistoryFile, command: swiftcCommand)
let allInvocationsStorage = ExistingFileStorage(
storageFile: context.invocationHistoryFile,
command: swiftcCommand
)
// When fallbacking to local compilation do not call historical `swiftc` invocations
// The current fallback invocation already compiles all files in a target
let invocationStorage = FilteredInvocationStorage(
@@ -94,10 +94,11 @@ public struct XCRemoteCacheConfig: Encodable {
var focusedTargets: [String] = []
/// Disable cache for http requests to fecth metadata and download artifacts
var disableHttpCache: Bool = false
/// Path, relative to $TARGET_TEMP_DIR which gathers all compilation commands that should be executed if a target
/// switches to local compilation. Example: A new `.swift` file invalidates remote artifact and triggers local compilation
/// When that happens, all previously skipped clang build steps need to be eventually called locally - this file lists
/// all these commands.
/// Path, relative to $TARGET_TEMP_DIR which gathers all compilation commands that should be e
/// xecuted if a target switches to local compilation.
/// Example: A new `.swift` file invalidates remote arXcodeProjIntegrate.swifttifact and triggers local compilation
/// When that happens, all previously skipped clang build steps
/// need to be eventually called locally - this file lists all these commands.
var compilationHistoryFile: String = "history.compile"
/// Timeout for remote response data interval (in seconds). If an interval between data chunks is
/// longer than a timeout, a request fails
@@ -124,6 +125,7 @@ public struct XCRemoteCacheConfig: Encodable {
extension XCRemoteCacheConfig {
/// Merges existing config with the other config and returns a final result
/// `other` scheme overrides existing configuration
// swiftlint:disable:next function_body_length
func merged(with scheme: ConfigFileScheme) -> XCRemoteCacheConfig {
var merge = self
merge.mode = scheme.mode ?? mode
@@ -35,9 +35,22 @@ struct AWSV4Signature {
request.setValue((request.httpBody ?? Data()).sha256(), forHTTPHeaderField: "x-amz-content-sha256")
let canonicalRequest = CanonicalRequest(request: request)
let stringToSign = StringToSign(region: region, service: service, canonicalRequestHash: canonicalRequest.hash, date: date)
let awsV4SigningKey = AWSV4SigningKey(secretAccessKey: secretKey, region: region, service: service, date: date)
let signature = HMAC.calcHMAC(keyArray: awsV4SigningKey.value, value: stringToSign.value).map { String(format: "%02hhx", $0) }.joined()
let stringToSign = StringToSign(
region: region,
service: service,
canonicalRequestHash: canonicalRequest.hash,
date: date
)
let awsV4SigningKey = AWSV4SigningKey(
secretAccessKey: secretKey,
region: region,
service: service,
date: date
)
let signature = HMAC.calcHMAC(
keyArray: awsV4SigningKey.value,
value: stringToSign.value
).map { String(format: "%02hhx", $0) }.joined()
let authValue =
"AWS4-HMAC-SHA256 " +
@@ -52,7 +52,14 @@ struct HMAC {
private static func calcHMAC(keyUnsafeBytes: UnsafeRawBufferPointer, value: String, out: UnsafeMutableRawPointer!) {
value.data(using: .utf8)!.withUnsafeBytes { value in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyUnsafeBytes.baseAddress, Int(keyUnsafeBytes.count), value.baseAddress, Int(value.count), out)
CCHmac(
CCHmacAlgorithm(kCCHmacAlgSHA256),
keyUnsafeBytes.baseAddress,
Int(keyUnsafeBytes.count),
value.baseAddress,
Int(value.count),
out
)
}
}
}
@@ -28,8 +28,8 @@ protocol CacheHitLogger {
/// Logs target hit or miss, based on an action of a build
class ActionSpecificCacheHitLogger: CacheHitLogger {
private let statsLogger: StatsLogger
private let hitCounter: XCRemoteCacheStatistics.Counter
private let missCounter: XCRemoteCacheStatistics.Counter
private let hitCounter: XCRemoteCacheStatistics.Counter?
private let missCounter: XCRemoteCacheStatistics.Counter?
init(action: BuildActionType, statsLogger: StatsLogger) {
self.statsLogger = statsLogger
@@ -37,19 +37,24 @@ class ActionSpecificCacheHitLogger: CacheHitLogger {
case .index:
hitCounter = .indexingTargetHitCount
missCounter = .indexingTargetMissCount
case .unknown:
fallthrough
case .build:
hitCounter = .targetCacheHit
missCounter = .targetCacheMiss
case .unknown:
hitCounter = nil
missCounter = nil
}
}
func logHit() throws {
try statsLogger.log(hitCounter)
if let hitCounter = hitCounter {
try statsLogger.log(hitCounter)
}
}
func logMiss() throws {
try statsLogger.log(missCounter)
if let missCounter = missCounter {
try statsLogger.log(missCounter)
}
}
}
@@ -31,6 +31,7 @@ class ArtifactSwiftProductsBuilderImplTests: FileXCTestCase {
private var builder: ArtifactSwiftProductsBuilderImpl!
override func setUpWithError() throws {
try super.setUpWithError()
let rootDir = try prepareTempDir()
moduleDir = rootDir.appendingPathComponent("Products")
swiftmoduleFile = moduleDir.appendingPathComponent("MyModule.swiftmodule")
@@ -47,24 +48,41 @@ class ArtifactSwiftProductsBuilderImplTests: FileXCTestCase {
func testIncludesRequiredSwiftmoduleFiles() throws {
try fileManager.spt_createFile(swiftmoduleFile, content: "swiftmodule")
try fileManager.spt_createFile(swiftmoduleDocFile, content: "swiftdoc")
let builderSwiftmoduleDir = builder.buildingArtifactSwiftModulesLocation().appendingPathComponent("arm64")
let expectedBuildedSwiftmoduleFile = builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftmodule")
let expectedBuildedSwiftmoduledocFile = builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftdoc")
let builderSwiftmoduleDir =
builder
.buildingArtifactSwiftModulesLocation()
.appendingPathComponent("arm64")
let expectedBuildedSwiftmoduleFile =
builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftmodule")
let expectedBuildedSwiftmoduledocFile =
builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftdoc")
try builder.includeModuleDefinitionsToTheArtifact(arch: "arm64", moduleURL: swiftmoduleFile)
XCTAssertEqual(fileManager.contents(atPath: expectedBuildedSwiftmoduleFile.path), "swiftmodule".data(using: .utf8))
XCTAssertEqual(fileManager.contents(atPath: expectedBuildedSwiftmoduledocFile.path), "swiftdoc".data(using: .utf8))
XCTAssertEqual(
fileManager.contents(atPath: expectedBuildedSwiftmoduleFile.path),
"swiftmodule".data(using: .utf8)
)
XCTAssertEqual(
fileManager.contents(atPath: expectedBuildedSwiftmoduledocFile.path),
"swiftdoc".data(using: .utf8)
)
}
func testIncludesAllSwiftmoduleFiles() throws {
try fileManager.spt_createEmptyFile(swiftmoduleFile)
try fileManager.spt_createEmptyFile(swiftmoduleDocFile)
try fileManager.spt_createEmptyFile(swiftmoduleSourceInfoFile)
let builderSwiftmoduleDir = builder.buildingArtifactSwiftModulesLocation().appendingPathComponent("arm64")
let expectedBuildedSwiftmoduleFile = builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftmodule")
let expectedBuildedSwiftmoduledocFile = builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftdoc")
let expectedBuildedSwiftSourceInfoFile = builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftsourceinfo")
let builderSwiftmoduleDir =
builder
.buildingArtifactSwiftModulesLocation()
.appendingPathComponent("arm64")
let expectedBuildedSwiftmoduleFile =
builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftmodule")
let expectedBuildedSwiftmoduledocFile =
builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftdoc")
let expectedBuildedSwiftSourceInfoFile =
builderSwiftmoduleDir.appendingPathComponent("MyModule.swiftsourceinfo")
try builder.includeModuleDefinitionsToTheArtifact(arch: "arm64", moduleURL: swiftmoduleFile)
@@ -74,6 +92,11 @@ class ArtifactSwiftProductsBuilderImplTests: FileXCTestCase {
}
func testFailsIncludingWhenMissingRequiredSwiftmoduleFiles() throws {
XCTAssertThrowsError(try builder.includeModuleDefinitionsToTheArtifact(arch: "arm64", moduleURL: swiftmoduleFile))
XCTAssertThrowsError(
try builder.includeModuleDefinitionsToTheArtifact(
arch: "arm64",
moduleURL: swiftmoduleFile
)
)
}
}
@@ -28,6 +28,7 @@ class FileLLDBInitPatcherTests: XCTestCase {
private var patcher: FileLLDBInitPatcher!
override func setUp() {
super.setUp()
accessor = FileAccessorFake(mode: .normal)
patcher = FileLLDBInitPatcher(
file: lldbInitPath,
@@ -21,8 +21,8 @@
import XCTest
class SwiftcFilemapInputEditorTests: FileXCTestCase {
private let sampleInfo = SwiftCompilationInfo(info: SwiftModuleCompilationInfo(
private let sampleInfo = SwiftCompilationInfo(
info: SwiftModuleCompilationInfo(
dependencies: nil,
swiftDependencies: "/"
), files: [])
@@ -65,17 +65,19 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
}
}
"""#.data(using: .utf8)!
let expectedInfo = SwiftCompilationInfo(info: SwiftModuleCompilationInfo(
dependencies: "/master.d",
swiftDependencies: "/master.swiftdeps"
), files: [
SwiftFileCompilationInfo(
file: "/file1.swift",
dependencies: "/file1.d",
object: "/file1.o",
swiftDependencies: "/file1.swiftdeps"
let expectedInfo = SwiftCompilationInfo(
info: SwiftModuleCompilationInfo(
dependencies: "/master.d",
swiftDependencies: "/master.swiftdeps"
),
])
files: [
SwiftFileCompilationInfo(
file: "/file1.swift",
dependencies: "/file1.d",
object: "/file1.o",
swiftDependencies: "/file1.swiftdeps"
),
])
try fileManager.spt_writeToFile(atPath: inputFile.path, contents: infoContentData)
let readInfo = try editor.read()
@@ -93,17 +95,18 @@ class SwiftcFilemapInputEditorTests: FileXCTestCase {
}
func testWritingSavesContentWithOptionalParameters() throws {
let extendedInfo = SwiftCompilationInfo(info: SwiftModuleCompilationInfo(
dependencies: "/master.d",
swiftDependencies: "/master.swiftdeps"
), files: [
SwiftFileCompilationInfo(
file: "/file1.swift",
dependencies: "/file1.d",
object: "/file1.o",
swiftDependencies: "/file1.swiftdeps"
),
])
let extendedInfo = SwiftCompilationInfo(
info: SwiftModuleCompilationInfo(
dependencies: "/master.d",
swiftDependencies: "/master.swiftdeps"
), files: [
SwiftFileCompilationInfo(
file: "/file1.swift",
dependencies: "/file1.d",
object: "/file1.o",
swiftDependencies: "/file1.swiftdeps"
),
])
try editor.write(extendedInfo)
@@ -277,7 +277,9 @@ class SwiftcTests: FileXCTestCase {
let artifactObjCHeader = URL(fileURLWithPath: "/cachedArtifact/include/archTest/Target-Swift.h")
let artifactSwiftmodule = URL(fileURLWithPath: "/cachedArtifact/swiftmodule/archTest/Target.swiftmodule")
let artifactSwiftdoc = URL(fileURLWithPath: "/cachedArtifact/swiftmodule/archTest/Target.swiftdoc")
let artifactSwiftSourceInfo = URL(fileURLWithPath: "/cachedArtifact/swiftmodule/archTest/Target.swiftsourceinfo")
let artifactSwiftSourceInfo = URL(
fileURLWithPath: "/cachedArtifact/swiftmodule/archTest/Target.swiftsourceinfo"
)
artifactOrganizer = ArtifactOrganizerFake(artifactRoot: artifactRoot)
let swiftc = Swiftc(
@@ -457,5 +459,5 @@ class SwiftcTests: FileXCTestCase {
)
XCTAssertNoThrow(try swiftc.mockCompilation())
}
} // swiftlint:disable:next file_length
}
@@ -27,6 +27,7 @@ class FileFingerprintSyncerTests: FileXCTestCase {
private var swiftmoduleDir: URL!
override func setUpWithError() throws {
try super.setUpWithError()
syncer = FileFingerprintSyncer(
fingerprintOverrideExtension: "md5",
dirAccessor: fileManager,
@@ -27,6 +27,7 @@ class TargetDependenciesReaderTests: XCTestCase {
private var reader: TargetDependenciesReader!
override func setUp() {
super.setUp()
dirAccessor = DirAccessorFake()
/// A Factory that builds a faked dependency reader that returns a single dependency,
/// a basename of the input .d file and the ".swift" extension
@@ -27,6 +27,7 @@ class CopyDiskCopierTests: FileXCTestCase {
private var emptySourceFile: URL!
override func setUpWithError() throws {
try super.setUpWithError()
workingDir = try prepareTempDir()
emptySourceFile = workingDir.appendingPathComponent("source")
try fileManager.spt_writeToFile(atPath: emptySourceFile.path, contents: Data())
@@ -26,6 +26,7 @@ class FilteredInvocationStorageTests: XCTestCase {
var storage: FilteredInvocationStorage!
override func setUp() {
super.setUp()
storage = FilteredInvocationStorage(storage: underlyingStorage, retrieveIgnoredCommands: ["to_ignore"])
}
@@ -28,6 +28,7 @@ class InvocationFileStorageTests: FileXCTestCase {
private var storage: ExistingFileStorage!
override func setUpWithError() throws {
try super.setUpWithError()
file = try prepareTempDir().appendingPathComponent("file.history")
try fileManager.spt_createEmptyFile(file)
storage = ExistingFileStorage(storageFile: file, command: command)
@@ -25,6 +25,7 @@ class ActionSpecificCacheHitLoggerTests: FileXCTestCase {
private var coordinator: StatsCoordinator!
override func setUp() {
super.setUp()
coordinator = InMemoryStatsCoordinator()
}
@@ -46,17 +46,17 @@ module CocoapodsXCRemoteCacheModifier
@@configuration = c
end
def self.set_configuration_default_values(user_proj_directory)
def self.set_configuration_default_values
default_values = {
'mode' => 'consumer',
'enabled' => true,
'xcrc_location' => "#{user_proj_directory}/XCRC",
'xcrc_location' => "XCRC",
'exclude_build_configurations' => [],
'check_build_configuration' => 'Debug',
'check_platform' => 'iphonesimulator',
'modify_lldb_init' => true,
'xccc_file' => "#{user_proj_directory}/#{BIN_DIR}/xccc",
'remote_commit_file' => "#{user_proj_directory}/#{BIN_DIR}/arc.rc",
'xccc_file' => "#{BIN_DIR}/xccc",
'remote_commit_file' => "#{BIN_DIR}/arc.rc",
'exclude_targets' => [],
}
@@configuration.merge! default_values.select { |k, v| !@@configuration.key?(k) }
@@ -89,61 +89,81 @@ module CocoapodsXCRemoteCacheModifier
@@configuration.select { |key, value| !CUSTOM_CONFIGURATION_KEYS.include?(key) }
end
def self.enable_xcremotecache(target, user_proj_directory, xc_location, xc_cc_path, mode, exclude_build_configurations, check_build_configuration, check_platform, final_target)
target.build_configurations.each do |config|
# apply only for relevant Configurations
next if exclude_build_configurations.include?(config.name)
if mode == 'consumer'
config.build_settings['CC'] = [xc_cc_path]
end
config.build_settings['SWIFT_EXEC'] = ["#{xc_location}/xcswiftc"]
config.build_settings['LIBTOOL'] = ["#{xc_location}/xclibtool"]
config.build_settings['LD'] = ["#{xc_location}/xcld"]
config.build_settings['XCREMOTE_CACHE_FAKE_SRCROOT'] = FAKE_SRCROOT
add_cflags!(config.build_settings, '-fdebug-prefix-map', "#{user_proj_directory}=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
add_swiftflags!(config.build_settings, '-debug-prefix-map', "#{user_proj_directory}=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
def self.enable_xcremotecache(target, xc_location, xc_cc_path, mode, exclude_build_configurations, final_target)
target.build_configurations.each do |config|
# apply only for relevant Configurations
next if exclude_build_configurations.include?(config.name)
if mode == 'consumer'
config.build_settings['CC'] = ["$SRCROOT/#{xc_cc_path}"]
end
config.build_settings['SWIFT_EXEC'] = ["$SRCROOT/#{xc_location}/xcswiftc"]
config.build_settings['LIBTOOL'] = ["$SRCROOT/#{xc_location}/xclibtool"]
config.build_settings['LD'] = ["$SRCROOT/#{xc_location}/xcld"]
# User project is not generated from scratch (contrary to `Pods`), delete all previous XCRemoteCache phases
target.build_phases.delete_if {|phase|
# Some phases (e.g. PBXSourcesBuildPhase) don't have strict name check respond_to?
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC]")
end
}
config.build_settings['XCREMOTE_CACHE_FAKE_SRCROOT'] = FAKE_SRCROOT
add_cflags!(config.build_settings, '-fdebug-prefix-map', "$(SRCROOT:dir:standardizepath)=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
add_swiftflags!(config.build_settings, '-debug-prefix-map', "$(SRCROOT:dir:standardizepath)=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
end
# Prebuild
if mode == 'consumer'
prebuild_script = target.new_shell_script_build_phase("[XCRC] Prebuild")
existing_prebuild_script = target.build_phases.detect do |phase|
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC] Prebuild")
end
end
prebuild_script = existing_prebuild_script || target.new_shell_script_build_phase("[XCRC] Prebuild")
prebuild_script.shell_script = "\"$SCRIPT_INPUT_FILE_0\""
prebuild_script.input_paths = ["#{xc_location}/xcprebuild"]
prebuild_script.input_paths = ["$SRCROOT/#{xc_location}/xcprebuild"]
prebuild_script.output_paths = [
"$(TARGET_TEMP_DIR)/rc.enabled",
"$(TARGET_TEMP_DIR)/rc.enabled",
"$(DWARF_DSYM_FOLDER_PATH)/$(DWARF_DSYM_FILE_NAME)"
]
prebuild_script.dependency_file = "$(TARGET_TEMP_DIR)/prebuild.d"
# Move prebuild (last element) to the first position (to make it real 'prebuild')
target.build_phases.rotate!(-1)
target.build_phases.rotate!(-1) if existing_prebuild_script.nil?
elsif mode == 'producer'
# Delete existing prebuild build phase (to support switching between modes)
target.build_phases.delete_if do |phase|
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC] Prebuild")
end
end
end
# Postbuild
postbuild_script = target.new_shell_script_build_phase("[XCRC] Postbuild")
existing_postbuild_script = target.build_phases.detect do |phase|
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC] Postbuild")
end
end
postbuild_script = existing_postbuild_script || target.new_shell_script_build_phase("[XCRC] Postbuild")
postbuild_script.shell_script = "\"$SCRIPT_INPUT_FILE_0\""
postbuild_script.input_paths = ["#{xc_location}/xcpostbuild"]
postbuild_script.input_paths = ["$SRCROOT/#{xc_location}/xcpostbuild"]
postbuild_script.output_paths = [
"$(TARGET_BUILD_DIR)/$(MODULES_FOLDER_PATH)/$(PRODUCT_MODULE_NAME).swiftmodule/$(PLATFORM_PREFERRED_ARCH).swiftmodule.md5",
"$(TARGET_BUILD_DIR)/$(MODULES_FOLDER_PATH)/$(PRODUCT_MODULE_NAME).swiftmodule/$(PLATFORM_PREFERRED_ARCH).swiftmodule.md5",
"$(TARGET_BUILD_DIR)/$(MODULES_FOLDER_PATH)/$(PRODUCT_MODULE_NAME).swiftmodule/$(PLATFORM_PREFERRED_ARCH)-$(LLVM_TARGET_TRIPLE_VENDOR)-$(SWIFT_PLATFORM_TARGET_PREFIX)$(LLVM_TARGET_TRIPLE_SUFFIX).swiftmodule.md5"
]
postbuild_script.dependency_file = "$(TARGET_TEMP_DIR)/postbuild.d"
# Mark a sha as ready for a given platform and configuration when building the final_target
if mode == 'producer' && target.name == final_target
mark_script = target.new_shell_script_build_phase("[XCRC] Mark")
existing_mark_script = target.build_phases.detect do |phase|
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC] Mark")
end
end
mark_script = existing_mark_script || target.new_shell_script_build_phase("[XCRC] Mark")
mark_script.shell_script = "\"$SCRIPT_INPUT_FILE_0\" mark --configuration $CONFIGURATION --platform $PLATFORM_NAME"
mark_script.input_paths = ["#{xc_location}/xcprepare"]
mark_script.input_paths = ["$SRCROOT/#{xc_location}/xcprepare"]
else
# Delete existing mark build phase (to support switching between modes or changing the final target)
target.build_phases.delete_if do |phase|
if phase.respond_to?(:name)
phase.name != nil && phase.name.start_with?("[XCRC] Mark")
end
end
end
end
@@ -251,6 +271,7 @@ module CocoapodsXCRemoteCacheModifier
# Returns the content (array of lines) of the lldbinit with stripped XCRemoteCache rewrite
def self.clean_lldbinit_content(lldbinit_path)
all_lines = []
return all_lines unless File.exist?(lldbinit_path)
File.open(lldbinit_path) { |file|
while(line = file.gets) != nil
line = line.strip
@@ -290,7 +311,7 @@ module CocoapodsXCRemoteCacheModifier
begin
user_proj_directory = File.dirname(user_project.path)
set_configuration_default_values(user_proj_directory)
set_configuration_default_values
unless @@configuration['enabled']
Pod::UI.puts "[XCRC] XCRemoteCache disabled"
@@ -310,8 +331,12 @@ module CocoapodsXCRemoteCacheModifier
check_build_configuration = @@configuration['check_build_configuration']
check_platform = @@configuration['check_platform']
xccc_location_absolute = "#{user_proj_directory}/#{xccc_location}"
xcrc_location_absolute = "#{user_proj_directory}/#{xcrc_location}"
remote_commit_file_absolute = "#{user_proj_directory}/#{remote_commit_file}"
# Download XCRC
download_xcrc_if_needed(xcrc_location)
download_xcrc_if_needed(xcrc_location_absolute)
# Save .rcinfo
save_rcinfo(generate_rcinfo(), user_proj_directory)
@@ -320,8 +345,8 @@ module CocoapodsXCRemoteCacheModifier
Dir.mkdir(BIN_DIR) unless File.exist?(BIN_DIR)
# Remove previous xccc & arc.rc
File.delete(remote_commit_file) if File.exist?(remote_commit_file)
File.delete(xccc_location) if File.exist?(xccc_location)
File.delete(remote_commit_file_absolute) if File.exist?(remote_commit_file_absolute)
File.delete(xccc_location_absolute) if File.exist?(xccc_location_absolute)
# Prepare XCRC
@@ -333,7 +358,7 @@ module CocoapodsXCRemoteCacheModifier
next if target.name.start_with?("Pods-")
next if target.name.end_with?("Tests")
next if exclude_targets.include?(target.name)
enable_xcremotecache(target, user_proj_directory, xcrc_location, xccc_location, mode, exclude_build_configurations, check_build_configuration, check_platform, final_target)
enable_xcremotecache(target, "../#{xcrc_location}", "../#{xccc_location}", mode, exclude_build_configurations, final_target)
end
# Create .rcinfo into `Pods` directory as that .xcodeproj reads configuration from .xcodeproj location
@@ -347,7 +372,7 @@ module CocoapodsXCRemoteCacheModifier
# Enabled/disable XCRemoteCache for the main (user) project
begin
prepare_result = YAML.load`#{xcrc_location}/xcprepare --configuration #{check_build_configuration} --platform #{check_platform}`
prepare_result = YAML.load`#{xcrc_location_absolute}/xcprepare --configuration #{check_build_configuration} --platform #{check_platform}`
unless prepare_result['result'] || mode != 'consumer'
# Uninstall the XCRemoteCache for the consumer mode
disable_xcremotecache(user_project)
@@ -364,7 +389,7 @@ module CocoapodsXCRemoteCacheModifier
# Attach XCRC to the app targets
user_project.targets.each do |target|
next if exclude_targets.include?(target.name)
enable_xcremotecache(target, user_proj_directory, xcrc_location, xccc_location, mode, exclude_build_configurations, check_build_configuration, check_platform, final_target)
enable_xcremotecache(target, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target)
end
# Set Target sourcemap