Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75bef0baf6 | |||
| 03671e71b7 | |||
| 91505a59d2 | |||
| 59c1d999b1 | |||
| ba58c1c21e | |||
| 96ce18bc31 | |||
| 30e49ef7bc | |||
| d46f09c6dd | |||
| 2fdf6c39e2 | |||
| 064b22a2d1 | |||
| ddeffe75d6 | |||
| 181997e3d2 | |||
| 1d6ac2c171 | |||
| 3dfd6e296f | |||
| c39b286222 | |||
| a55a4547ac | |||
| 51c2007c5b | |||
| fc092fc4e3 | |||
| 3f9596f6e6 | |||
| 15f4ee7eab | |||
| a6325db0a5 | |||
| cfa4fbd070 | |||
| c573ced4f4 | |||
| 0c2afc15fc | |||
| 586e8df56e | |||
| ef3a88c6ec | |||
| 95f95be29e | |||
| 4d12800096 | |||
| fbb456b0e0 | |||
| a321ea3362 | |||
| 963e6858ee | |||
| f9999a402f | |||
| dbfe1dd8d4 | |||
| def12fab6f | |||
| 6fee69f081 | |||
| b74bafa5d7 | |||
| 33de361317 | |||
| 0aeb5aee36 | |||
| 8682731f30 |
@@ -13,9 +13,9 @@ jobs:
|
||||
args: --strict
|
||||
|
||||
macOS:
|
||||
runs-on: macOS-latest
|
||||
runs-on: macos-12
|
||||
env:
|
||||
XCODE_VERSION: ${{ '13.1' }}
|
||||
XCODE_VERSION: ${{ '13.3.1' }}
|
||||
steps:
|
||||
- name: Select Xcode
|
||||
run: "sudo xcode-select -s /Applications/Xcode_$XCODE_VERSION.app"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: macos-12
|
||||
env:
|
||||
XCODE_VERSION: ${{ '13.3.1' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Select Xcode
|
||||
run: "sudo xcode-select -s /Applications/Xcode_$XCODE_VERSION.app"
|
||||
- name: "Generate documentation"
|
||||
run: "swift package --allow-writing-to-directory ./docs generate-documentation --target XCRemoteCache --disable-indexing --transform-for-static-hosting --output-path ./docs --hosting-base-path XCRemoteCache/"
|
||||
- name: Deploy GH-pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs
|
||||
keep_files: false
|
||||
@@ -6,9 +6,9 @@ on:
|
||||
jobs:
|
||||
macOS:
|
||||
name: Add macOS binaries to release
|
||||
runs-on: macOS-latest
|
||||
runs-on: macos-12
|
||||
env:
|
||||
XCODE_VERSION: ${{ '13.1' }}
|
||||
XCODE_VERSION: ${{ '13.3.1' }}
|
||||
steps:
|
||||
- name: Select Xcode
|
||||
run: "sudo xcode-select -s /Applications/Xcode_$XCODE_VERSION.app"
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
"version": "0.0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftDocCPlugin",
|
||||
"repositoryURL": "https://github.com/apple/swift-docc-plugin",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "3303b164430d9a7055ba484c8ead67a52f7b74f6",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "XcodeProj",
|
||||
"repositoryURL": "https://github.com/tuist/XcodeProj.git",
|
||||
|
||||
@@ -17,6 +17,7 @@ let package = Package(
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"),
|
||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.1"),
|
||||
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.7.1"),
|
||||
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
||||
@@ -8,6 +8,7 @@ _XCRemoteCache is a remote cache tool for Xcode projects. It reuses target artif
|
||||
[](https://github.com/spotify/XCRemoteCache/workflows/CI/badge.svg)
|
||||
[](LICENSE)
|
||||
[](https://slackin.spotify.com)
|
||||
[](https://github.com/spotify/XCRemoteCache/workflows/Docs/badge.svg)
|
||||
|
||||
- [How and Why?](#how-and-why)
|
||||
* [Accurate target input files](#accurate-target-input-files)
|
||||
@@ -288,7 +289,7 @@ _Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`,
|
||||
| `cache_commit_history` | Number of historical git commits to look for cache artifacts | `10` | ⬜️ |
|
||||
| `source_root` | Source root of the Xcode project | `""` | ⬜️ |
|
||||
| `fingerprint_override_extension` | Fingerprint override extension (sample override `Module.swiftmodule/x86_64.swiftmodule.md5`) | `md5` | ⬜️ |
|
||||
| `extra_configuration_file` | Configuration file that overrides project configuration | `user.rcinfo` | ⬜️ |
|
||||
| `extra_configuration_file` | Configuration file that overrides project configuration (this property can be overriden multiple times in different files to chain extra configuration files) | `user.rcinfo` | ⬜️ |
|
||||
| `publishing_sha` | Custom commit sha to publish artifact (producer only) | `nil` | ⬜️ |
|
||||
| `artifact_maximum_age` | Maximum age in days HTTP response should be locally cached before being evicted | `30` | ⬜️ |
|
||||
| `custom_fingerprint_envs` | Extra ENV keys that should be convoluted into the environment fingerprint | `[]` | ⬜️ |
|
||||
@@ -315,6 +316,7 @@ _Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`,
|
||||
| `disable_certificate_verification` | A Boolean value that opts-in SSL certificate validation is disabled | `false` | ⬜️ |
|
||||
| `disable_vfs_overlay` | A feature flag to disable virtual file system overlay support (temporary) | `false` | ⬜️ |
|
||||
| `custom_rewrite_envs` | A list of extra ENVs that should be used as placeholders in the dependency list. ENV rewrite process is optimistic - does nothing if an ENV is not defined in the pre/postbuild process. | `[]` | ⬜️ |
|
||||
| `irrelevant_dependencies_paths` | Regexes of files that should not be included in a list of dependencies. Warning! Add entries here with caution - excluding dependencies that are relevant might lead to a target overcaching. The regex can match either partially or fully the filepath, e.g. `\\.modulemap$` will exclude all `.modulemap` files. | `[]` | ⬜️ |
|
||||
|
||||
## Backend cache server
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class XCLibtoolCreateUniversalBinary: XCLibtoolLogic {
|
||||
let config: XCRemoteCacheConfig
|
||||
do {
|
||||
let srcRoot: URL = URL(fileURLWithPath: fileManager.currentDirectoryPath)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileManager: fileManager)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileReader: fileManager)
|
||||
.readConfiguration()
|
||||
} catch {
|
||||
errorLog("Libtool initialization failed with error: \(error). Fallbacking to libtool")
|
||||
|
||||
@@ -40,6 +40,7 @@ public struct PostbuildContext {
|
||||
var mode: Mode
|
||||
var targetName: String
|
||||
var targetTempDir: URL
|
||||
var derivedFilesDir: URL
|
||||
/// Location where all compilation outputs (.o) are placed
|
||||
var compilationTempDir: URL
|
||||
var configuration: String
|
||||
@@ -82,6 +83,8 @@ public struct PostbuildContext {
|
||||
/// location of the json file that define virtual files system overlay
|
||||
/// (mappings of the virtual location file -> local file path)
|
||||
let overlayHeadersPath: URL
|
||||
/// Regexes of files that should not be included in the dependency list
|
||||
let irrelevantDependenciesPaths: [String]
|
||||
}
|
||||
|
||||
extension PostbuildContext {
|
||||
@@ -91,6 +94,7 @@ extension PostbuildContext {
|
||||
let targetNameValue: String = try env.readEnv(key: "TARGET_NAME")
|
||||
targetName = targetNameValue
|
||||
targetTempDir = try env.readEnv(key: "TARGET_TEMP_DIR")
|
||||
derivedFilesDir = try env.readEnv(key: "DERIVED_FILE_DIR")
|
||||
let archs: [String] = try env.readEnv(key: "ARCHS").split(separator: " ").map(String.init)
|
||||
guard let firstArch = archs.first, !firstArch.isEmpty else {
|
||||
throw PostbuildContextError.missingArchitecture
|
||||
@@ -133,5 +137,6 @@ extension PostbuildContext {
|
||||
modeMarkerPath = config.modeMarkerPath
|
||||
/// Note: The file has yaml extension, even it is in the json format
|
||||
overlayHeadersPath = targetTempDir.appendingPathComponent("all-product-headers.yaml")
|
||||
irrelevantDependenciesPaths = config.irrelevantDependenciesPaths
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class XCPostbuild {
|
||||
let context: PostbuildContext
|
||||
let cacheHitLogger: CacheHitLogger
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
context = try PostbuildContext(config, env: env)
|
||||
updateProcessTag(context.targetName)
|
||||
let counterFactory: FileStatsCoordinator.CountersFactory = { file, count in
|
||||
@@ -171,7 +171,9 @@ public class XCPostbuild {
|
||||
product: context.productsDir,
|
||||
source: context.srcRoot,
|
||||
intermediate: context.targetTempDir,
|
||||
bundle: context.bundleDir
|
||||
derivedFiles: context.derivedFilesDir,
|
||||
bundle: context.bundleDir,
|
||||
skippedRegexes: context.irrelevantDependenciesPaths
|
||||
)
|
||||
// Override fingerprints for all produced '.swiftmodule' files
|
||||
let fingerprintOverrideManager = FingerprintOverrideManagerImpl(
|
||||
|
||||
@@ -29,7 +29,7 @@ public class XCPrebuild {
|
||||
let config: XCRemoteCacheConfig
|
||||
let context: PrebuildContext
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
context = try PrebuildContext(config, env: env)
|
||||
updateProcessTag(context.targetName)
|
||||
} catch {
|
||||
@@ -78,6 +78,10 @@ public class XCPrebuild {
|
||||
exit(0)
|
||||
}
|
||||
|
||||
let compilationHistoryOrganizer = CompilationHistoryFileOrganizer(
|
||||
context.compilationHistoryFile,
|
||||
fileManager: fileManager
|
||||
)
|
||||
do {
|
||||
let envFingerprint = try EnvironmentFingerprintGenerator(
|
||||
configuration: config,
|
||||
@@ -148,10 +152,6 @@ public class XCPrebuild {
|
||||
algorithm: MD5Algorithm()
|
||||
)
|
||||
let organizer = ZipArtifactOrganizer(targetTempDir: context.targetTempDir, fileManager: fileManager)
|
||||
let compilationHistoryOrganizer = CompilationHistoryFileOrganizer(
|
||||
context.compilationHistoryFile,
|
||||
fileManager: fileManager
|
||||
)
|
||||
let metaReader = JsonMetaReader(fileAccessor: fileManager)
|
||||
var consumerPlugins: [ArtifactConsumerPrebuildPlugin] = []
|
||||
|
||||
@@ -189,7 +189,6 @@ public class XCPrebuild {
|
||||
case .compatible(localDependencies: let dependencies):
|
||||
// TODO: pass `allowedInputFiles` observed in the build time
|
||||
try modeController.enable(allowedInputFiles: dependencies, dependencies: dependencies)
|
||||
compilationHistoryOrganizer.reset()
|
||||
}
|
||||
} catch {
|
||||
disableRemoteCache(
|
||||
@@ -197,6 +196,7 @@ public class XCPrebuild {
|
||||
errorMessage: "Prebuild step failed with error: \(error)"
|
||||
)
|
||||
}
|
||||
compilationHistoryOrganizer.reset()
|
||||
}
|
||||
|
||||
private func disableRemoteCache(modeController: PhaseCacheModeController, errorMessage: String?) {
|
||||
|
||||
@@ -74,7 +74,7 @@ public class XCIntegrate {
|
||||
let binariesDir = commandURL.deletingLastPathComponent()
|
||||
|
||||
let srcRoot: URL = URL(fileURLWithPath: projectPath).deletingLastPathComponent()
|
||||
let config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileManager: fileManager)
|
||||
let config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileReader: fileManager)
|
||||
.readConfiguration()
|
||||
|
||||
let context = try IntegrateContext(
|
||||
|
||||
@@ -32,7 +32,7 @@ public class XCConfig {
|
||||
let fileManager = FileManager.default
|
||||
let config: XCRemoteCacheConfig
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
} catch {
|
||||
exit(1, "FATAL: Prepare initialization failed with error: \(error)")
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class XCPrepare {
|
||||
var context: PrepareContext
|
||||
let xcodeVersion: String
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
context = try PrepareContext(config, offline: offline)
|
||||
xcodeVersion = try customXcodeBuildNumber ?? XcodeProbeImpl(shell: shellGetStdout).read().buildVersion
|
||||
} catch {
|
||||
|
||||
@@ -46,7 +46,7 @@ public class XCPrepareMark {
|
||||
let context: PrepareMarkContext
|
||||
let xcodeVersion: String
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
context = try PrepareMarkContext(config)
|
||||
xcodeVersion = try xcode ?? XcodeProbeImpl(shell: shellGetStdout).read().buildVersion
|
||||
} catch {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class XCStats {
|
||||
let config: XCRemoteCacheConfig
|
||||
let context: XCStatsContext
|
||||
do {
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileManager: fileManager).readConfiguration()
|
||||
config = try XCRemoteCacheConfigReader(env: env, fileReader: fileManager).readConfiguration()
|
||||
try context = XCStatsContext(config, fileManager: fileManager)
|
||||
} catch {
|
||||
exit(1, "FATAL: Prepare initialization failed with error: \(error)")
|
||||
|
||||
@@ -70,7 +70,7 @@ public class XCCreateBinary {
|
||||
let config: XCRemoteCacheConfig
|
||||
do {
|
||||
let srcRoot: URL = URL(fileURLWithPath: fileManager.currentDirectoryPath)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileManager: fileManager)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileReader: fileManager)
|
||||
.readConfiguration()
|
||||
} catch {
|
||||
errorLog("\(stepDescription) initialization failed with error: \(error). Fallbacking to \(fallbackCommand)")
|
||||
|
||||
@@ -70,7 +70,7 @@ public class XCSwiftc {
|
||||
let context: SwiftcContext
|
||||
do {
|
||||
let srcRoot: URL = URL(fileURLWithPath: fileManager.currentDirectoryPath)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileManager: fileManager)
|
||||
config = try XCRemoteCacheConfigReader(srcRootPath: srcRoot.path, fileReader: fileManager)
|
||||
.readConfiguration()
|
||||
context = try SwiftcContext(config: config, input: inputArgs)
|
||||
} catch {
|
||||
|
||||
@@ -138,6 +138,11 @@ public struct XCRemoteCacheConfig: Encodable {
|
||||
/// A list of extra ENVs that should be used as placeholders in the dependency list
|
||||
/// ENV rewrite process is optimistic - does nothing if an ENV is not defined in the pre/postbuild process
|
||||
var customRewriteEnvs: [String] = []
|
||||
/// Regexes of files that should not be included in a list of dependencies. Warning! Add entries here
|
||||
/// with caution - excluding dependencies that are relevant might lead to a target overcaching
|
||||
/// Note: The regex can match either partially or fully the filepath, e.g. `\\.modulemap$` will exclude
|
||||
/// all `.modulemap` files
|
||||
var irrelevantDependenciesPaths: [String] = []
|
||||
}
|
||||
|
||||
extension XCRemoteCacheConfig {
|
||||
@@ -193,6 +198,7 @@ extension XCRemoteCacheConfig {
|
||||
merge.disableCertificateVerification = scheme.disableCertificateVerification ?? disableCertificateVerification
|
||||
merge.disableVFSOverlay = scheme.disableVFSOverlay ?? disableVFSOverlay
|
||||
merge.customRewriteEnvs = scheme.customRewriteEnvs ?? customRewriteEnvs
|
||||
merge.irrelevantDependenciesPaths = scheme.irrelevantDependenciesPaths ?? irrelevantDependenciesPaths
|
||||
return merge
|
||||
}
|
||||
|
||||
@@ -257,6 +263,7 @@ struct ConfigFileScheme: Decodable {
|
||||
let disableCertificateVerification: Bool?
|
||||
let disableVFSOverlay: Bool?
|
||||
let customRewriteEnvs: [String]?
|
||||
let irrelevantDependenciesPaths: [String]?
|
||||
|
||||
// Yams library doesn't support encoding strategy, see https://github.com/jpsim/Yams/issues/84
|
||||
enum CodingKeys: String, CodingKey {
|
||||
@@ -304,6 +311,7 @@ struct ConfigFileScheme: Decodable {
|
||||
case disableCertificateVerification = "disable_certificate_verification"
|
||||
case disableVFSOverlay = "disable_vfs_overlay"
|
||||
case customRewriteEnvs = "custom_rewrite_envs"
|
||||
case irrelevantDependenciesPaths = "irrelevant_dependencies_paths"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,31 +324,41 @@ class XCRemoteCacheConfigReader {
|
||||
/// Name of the configuration file, required in $(SRCROOT) location
|
||||
private static let configurationFile = ".rcinfo"
|
||||
private let srcRoot: String
|
||||
private let fileManager: FileManager
|
||||
private let fileReader: FileReader
|
||||
private lazy var yamlDecorer = YAMLDecoder(encoding: .utf8)
|
||||
|
||||
init(env: [String: String], fileManager: FileManager) throws {
|
||||
init(env: [String: String], fileReader: FileReader) throws {
|
||||
let explicitSrcRoot: String? = env.readEnv(key: "SRCROOT")
|
||||
srcRoot = explicitSrcRoot ?? fileManager.currentDirectoryPath
|
||||
self.fileManager = fileManager
|
||||
srcRoot = explicitSrcRoot ?? FileManager.default.currentDirectoryPath
|
||||
self.fileReader = fileReader
|
||||
}
|
||||
|
||||
init(srcRootPath srcRoot: String, fileManager: FileManager) {
|
||||
init(srcRootPath srcRoot: String, fileReader: FileReader) {
|
||||
self.srcRoot = srcRoot
|
||||
self.fileManager = fileManager
|
||||
self.fileReader = fileReader
|
||||
}
|
||||
|
||||
// Reads the final configuration by loading all extra configs
|
||||
// until reaching a config that doesn't override `extraConfigurationFile`
|
||||
func readConfiguration() throws -> XCRemoteCacheConfig {
|
||||
let rootURL = URL(fileURLWithPath: srcRoot)
|
||||
let configURL = URL(fileURLWithPath: Self.configurationFile, relativeTo: rootURL)
|
||||
let userConfigs = try readUserConfig(configURL)
|
||||
var config = XCRemoteCacheConfig(sourceRoot: srcRoot).merged(with: userConfigs)
|
||||
let extraConfURL = URL(fileURLWithPath: config.extraConfigurationFile, relativeTo: rootURL)
|
||||
do {
|
||||
let extraConfig = try readUserConfig(extraConfURL)
|
||||
config = config.merged(with: extraConfig)
|
||||
} catch {
|
||||
infoLog("Extra config override failed with \(error). Skipping extra configuration")
|
||||
var extraConfURL = URL(fileURLWithPath: config.extraConfigurationFile, relativeTo: rootURL)
|
||||
var visitedFiles = Set([configURL])
|
||||
while !visitedFiles.contains(extraConfURL) {
|
||||
do {
|
||||
let extraConfig = try readUserConfig(extraConfURL)
|
||||
debugLog("Reading extra configuration from \(extraConfURL)")
|
||||
config = config.merged(with: extraConfig)
|
||||
visitedFiles.insert(extraConfURL)
|
||||
// Advance extra configuration
|
||||
extraConfURL = URL(fileURLWithPath: config.extraConfigurationFile, relativeTo: rootURL)
|
||||
} catch {
|
||||
infoLog("Extra config override failed with \(error). Skipping extra configuration")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return try config.verifyAndApplyDefaults()
|
||||
@@ -348,7 +366,7 @@ class XCRemoteCacheConfigReader {
|
||||
|
||||
/// Reads user configuration from a file
|
||||
private func readUserConfig(_ file: URL) throws -> ConfigFileScheme {
|
||||
let configurationContent = fileManager.contents(atPath: file.path)
|
||||
let configurationContent = try fileReader.contents(atPath: file.path)
|
||||
guard let configurationData = configurationContent else {
|
||||
throw XCRemoteCacheConfigReaderError.missingConfigurationFile(file)
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@ public struct Dependency: Equatable {
|
||||
case source
|
||||
case fingerprint
|
||||
case intermediate
|
||||
case derivedFile
|
||||
// Product of the target itself
|
||||
case ownProduct
|
||||
// User-excluded path
|
||||
case userExcluded
|
||||
case unknown
|
||||
}
|
||||
|
||||
@@ -55,14 +58,18 @@ class DependencyProcessorImpl: DependencyProcessor {
|
||||
private let productPath: String
|
||||
private let sourcePath: String
|
||||
private let intermediatePath: String
|
||||
private let derivedFilesPath: String
|
||||
private let bundlePath: String?
|
||||
private let skippedRegexes: [String]
|
||||
|
||||
init(xcode: URL, product: URL, source: URL, intermediate: URL, bundle: URL?) {
|
||||
init(xcode: URL, product: URL, source: URL, intermediate: URL, derivedFiles: URL, bundle: URL?, skippedRegexes: [String]) {
|
||||
xcodePath = xcode.path.dirPath()
|
||||
productPath = product.path.dirPath()
|
||||
sourcePath = source.path.dirPath()
|
||||
intermediatePath = intermediate.path.dirPath()
|
||||
derivedFilesPath = derivedFiles.path.dirPath()
|
||||
bundlePath = bundle?.path.dirPath()
|
||||
self.skippedRegexes = skippedRegexes
|
||||
}
|
||||
|
||||
func process(_ files: [URL]) -> [Dependency] {
|
||||
@@ -73,10 +80,14 @@ class DependencyProcessorImpl: DependencyProcessor {
|
||||
private func classify(_ files: [URL]) -> [Dependency] {
|
||||
return files.map { file -> Dependency in
|
||||
let filePath = file.resolvingSymlinksInPath().path
|
||||
if filePath.hasPrefix(xcodePath) {
|
||||
if skippedRegexes.contains(where: { filePath.range(of: $0, options: .regularExpression) != nil }) {
|
||||
return Dependency(url: file, type: .userExcluded)
|
||||
} else if filePath.hasPrefix(xcodePath) {
|
||||
return Dependency(url: file, type: .xcode)
|
||||
} else if filePath.hasPrefix(intermediatePath) {
|
||||
return Dependency(url: file, type: .intermediate)
|
||||
} else if filePath.hasPrefix(derivedFilesPath) {
|
||||
return Dependency(url: file, type: .derivedFile)
|
||||
} else if let bundle = bundlePath, filePath.hasPrefix(bundle) {
|
||||
// If a target produces a bundle, explicitly classify all
|
||||
// of products to distinguish from other targets products
|
||||
@@ -107,7 +118,12 @@ class DependencyProcessorImpl: DependencyProcessor {
|
||||
// - All files in `*/Interemediates/*` - this file are created on-fly for a given target
|
||||
// - Some files may depend on its own product (e.g. .m may #include *-Swift.h) - we know products will match
|
||||
// because in case of a hit, these will be taken from the artifact
|
||||
let irrelevantDependenciesType: [Dependency.Kind] = [.xcode, .intermediate, .ownProduct]
|
||||
// - Customized DERIVED_FILE_DIR may change a directory of
|
||||
// derived files, which by default is under `*/Interemediates`
|
||||
// - User-specified (in .rcinfo) files to exclude
|
||||
let irrelevantDependenciesType: [Dependency.Kind] = [
|
||||
.xcode, .intermediate, .ownProduct, .derivedFile, .userExcluded,
|
||||
]
|
||||
return !irrelevantDependenciesType.contains(dependency.type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,16 @@ public class XCLDMain {
|
||||
i += 1
|
||||
}
|
||||
guard let outputInput = output, let filelistInput = filelist, let dependencyInfoInput = dependencyInfo else {
|
||||
exit(1, "Missing 'output' argument. Args: \(args)")
|
||||
let ldCommand = "clang"
|
||||
print("Fallbacking to compilation using \(ldCommand).")
|
||||
|
||||
let args = ProcessInfo().arguments
|
||||
let paramList = [ldCommand] + args.dropFirst()
|
||||
let cargs = paramList.map { strdup($0) } + [nil]
|
||||
execvp(ldCommand, cargs)
|
||||
|
||||
/// C-function `execv` returns only when the command fails
|
||||
exit(1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,8 +60,16 @@ public class XCSwiftcMain {
|
||||
let targetInputInput = target,
|
||||
let swiftFileListInput = swiftFileList
|
||||
else {
|
||||
print("Missing argument. Args: \(args)")
|
||||
exit(1)
|
||||
let swiftcCommand = "swiftc"
|
||||
print("Fallbacking to compilation using \(swiftcCommand).")
|
||||
|
||||
let args = ProcessInfo().arguments
|
||||
let paramList = [swiftcCommand] + args.dropFirst()
|
||||
let cargs = paramList.map { strdup($0) } + [nil]
|
||||
execvp(swiftcCommand, cargs)
|
||||
|
||||
/// C-function `execv` returns only when the command fails
|
||||
exit(1)
|
||||
}
|
||||
let swiftcArgsInput = SwiftcArgInput(
|
||||
objcHeaderOutput: objcHeaderOutputInput,
|
||||
|
||||
@@ -26,6 +26,7 @@ class PostbuildContextTests: FileXCTestCase {
|
||||
private static let SampleEnvs = [
|
||||
"TARGET_NAME": "TARGET_NAME",
|
||||
"TARGET_TEMP_DIR": "TARGET_TEMP_DIR",
|
||||
"DERIVED_FILE_DIR": "DERIVED_FILE_DIR",
|
||||
"ARCHS": "x86_64",
|
||||
"OBJECT_FILE_DIR_normal": "/OBJECT_FILE_DIR_normal" ,
|
||||
"CONFIGURATION": "CONFIGURATION",
|
||||
|
||||
@@ -27,6 +27,7 @@ class PostbuildTests: FileXCTestCase {
|
||||
mode: .producer,
|
||||
targetName: "",
|
||||
targetTempDir: "",
|
||||
derivedFilesDir: "",
|
||||
compilationTempDir: "",
|
||||
configuration: "",
|
||||
platform: "",
|
||||
@@ -53,7 +54,8 @@ class PostbuildTests: FileXCTestCase {
|
||||
thinnedTargets: [],
|
||||
action: .build,
|
||||
modeMarkerPath: "",
|
||||
overlayHeadersPath: ""
|
||||
overlayHeadersPath: "",
|
||||
irrelevantDependenciesPaths: []
|
||||
)
|
||||
private var network = RemoteNetworkClientImpl(
|
||||
NetworkClientFake(fileManager: .default),
|
||||
@@ -78,7 +80,9 @@ class PostbuildTests: FileXCTestCase {
|
||||
product: "/Product",
|
||||
source: "/Source",
|
||||
intermediate: "/Intermediate",
|
||||
bundle: nil
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: []
|
||||
)
|
||||
private var overrideManager = FingerprintOverrideManagerImpl(
|
||||
overridingFileExtensions: ["swiftmodule"],
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2022 Spotify AB.
|
||||
//
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
@testable import XCRemoteCache
|
||||
import XCTest
|
||||
|
||||
class XCRemoteCacheConfigReaderTests: XCTestCase {
|
||||
|
||||
private var fileReader: FileAccessorFake!
|
||||
private var reader: XCRemoteCacheConfigReader!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
fileReader = FileAccessorFake(mode: .normal)
|
||||
reader = XCRemoteCacheConfigReader(srcRootPath: "/", fileReader: fileReader)
|
||||
}
|
||||
|
||||
func testReadsFromExtraConfig() throws {
|
||||
try fileReader.write(toPath: "/.rcinfo", contents: "cache_addresses: [test]")
|
||||
|
||||
let config = try reader.readConfiguration()
|
||||
|
||||
XCTAssertEqual(config.cacheAddresses, ["test"])
|
||||
}
|
||||
|
||||
func testOverridesExtraConfigFromExtraFile() throws {
|
||||
try fileReader.write(toPath: "/.rcinfo", contents: "cache_addresses: [test]")
|
||||
try fileReader.write(toPath: "/user.rcinfo", contents: "cache_addresses: [user]")
|
||||
|
||||
let config = try reader.readConfiguration()
|
||||
|
||||
XCTAssertEqual(config.cacheAddresses, ["user"])
|
||||
}
|
||||
|
||||
func testReadsExtraConfigMultipleTimes() throws {
|
||||
try fileReader.write(toPath: "/.rcinfo", contents: "cache_addresses: [test]")
|
||||
try fileReader.write(toPath: "/user.rcinfo", contents: """
|
||||
cache_addresses: [user]
|
||||
extra_configuration_file: user2.rcinfo
|
||||
""")
|
||||
try fileReader.write(toPath: "/user2.rcinfo", contents: "cache_addresses: [user2]")
|
||||
|
||||
let config = try reader.readConfiguration()
|
||||
|
||||
XCTAssertEqual(config.cacheAddresses, ["user2"])
|
||||
}
|
||||
|
||||
func testBreaksImportingExtraConfigIfReachingALoop() throws {
|
||||
try fileReader.write(toPath: "/.rcinfo", contents: "cache_addresses: [test]")
|
||||
try fileReader.write(toPath: "/user.rcinfo", contents: """
|
||||
cache_addresses: [user]
|
||||
extra_configuration_file: .rcinfo
|
||||
""")
|
||||
|
||||
let config = try reader.readConfiguration()
|
||||
|
||||
XCTAssertEqual(config.cacheAddresses, ["user"])
|
||||
}
|
||||
|
||||
func testBreaksImportingExtraConfigIfFileDoesntExist() throws {
|
||||
try fileReader.write(toPath: "/.rcinfo", contents: "cache_addresses: [test]")
|
||||
try fileReader.write(toPath: "/user.rcinfo", contents: """
|
||||
cache_addresses: [user]
|
||||
extra_configuration_file: nonexisting.rcinfo
|
||||
""")
|
||||
|
||||
let config = try reader.readConfiguration()
|
||||
|
||||
XCTAssertEqual(config.cacheAddresses, ["user"])
|
||||
XCTAssertEqual(config.extraConfigurationFile, "nonexisting.rcinfo")
|
||||
}
|
||||
}
|
||||
@@ -27,17 +27,21 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
product: "/Product",
|
||||
source: "/Source",
|
||||
intermediate: "/Intermediate",
|
||||
bundle: "/Bundle"
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: "/Bundle",
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
func testIntermediateFileIsSkippedForProductAndSourceSubdirectory() {
|
||||
func testIntermediateFileIsskippedRegexesForProductAndSourceSubdirectory() {
|
||||
let intermediateFile: URL = "/Intermediate/some"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
bundle: nil
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
@@ -46,14 +50,16 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
)
|
||||
}
|
||||
|
||||
func testBundleFileIsSkippedForProductAndSourceSubdirectory() {
|
||||
func testBundleFileIsskippedRegexesForProductAndSourceSubdirectory() {
|
||||
let bundleFile: URL = "/Bundle/some"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
bundle: "/Bundle"
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: "/Bundle",
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
@@ -62,6 +68,22 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
)
|
||||
}
|
||||
|
||||
func testFiltersOutGeneratedSwiftHeaders() throws {
|
||||
let dependencies = processor.process([
|
||||
"/DerivedFiles/ModuleName-Swift.h",
|
||||
])
|
||||
|
||||
XCTAssertEqual(dependencies, [])
|
||||
}
|
||||
|
||||
func testFiltersOutDerivedFile() throws {
|
||||
let dependencies = processor.process([
|
||||
"/DerivedFiles/output.h",
|
||||
])
|
||||
|
||||
XCTAssertEqual(dependencies, [])
|
||||
}
|
||||
|
||||
func testFiltersOutProductModulemap() throws {
|
||||
let dependencies = processor.process([
|
||||
"/Product/some.modulemap",
|
||||
@@ -130,7 +152,9 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
product: "/Product",
|
||||
source: "/Source",
|
||||
intermediate: intermediateDirReal,
|
||||
bundle: "/Bundle"
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: "/Bundle",
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
let intermediateFileSymlink = createSymlink(
|
||||
@@ -158,7 +182,9 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
product: "/Product",
|
||||
source: sourceDirReal,
|
||||
intermediate: "/Intermediate",
|
||||
bundle: "/Bundle"
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: "/Bundle",
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
let sourceFileSymlink = createSymlink(
|
||||
@@ -189,4 +215,76 @@ class DependencyProcessorImplTests: FileXCTestCase {
|
||||
|
||||
return sourceDir.appendingPathComponent(filename)
|
||||
}
|
||||
|
||||
func testSkipsCustomizedDerivedDirFileUnderSources() {
|
||||
let derivedFile: URL = "/DerivedFiles/Module-Swift.h"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
processor.process([derivedFile]),
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
func testSkippsFilesWithFullMatch() {
|
||||
let source: URL = "/someFile.m"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: ["/someFile\\.m"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
processor.process([source]),
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
func testSkippsFilesWithPartialMatch() {
|
||||
let derivedModulemap: URL = "/module.modulemap"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/product",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: ["\\.modulemap$"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
processor.process([derivedModulemap]),
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
func testDoesntSkipFileIfInvalidRegex() {
|
||||
let source: URL = "/someFile.m"
|
||||
let processor = DependencyProcessorImpl(
|
||||
xcode: "/Xcode",
|
||||
product: "/product",
|
||||
source: "/",
|
||||
intermediate: "/Intermediate",
|
||||
derivedFiles: "/DerivedFiles",
|
||||
bundle: nil,
|
||||
skippedRegexes: ["\\"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
processor.process([source]),
|
||||
[.init(url: source, type: .source)]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ An object that is passed to the `xcremotecache` can contain all properties suppo
|
||||
| `xccc_file` | The path where should be placed the `xccc` binary (in the pod installation phase) | `{podfile_dir}/.rc/xccc` | ⬜️ |
|
||||
| `remote_commit_file` | The path of the file with the remote commit sha (in the pod installation phase) | `{podfile_dir}/.rc/arc.rc`| ⬜️ |
|
||||
| `prettify_meta_files` | A Boolean value that opts-in pretty JSON formatting for meta files | `false` | ⬜️ |
|
||||
| `fake_src_root` | An arbitrary source location shared between producers and consumers. Should be unique for a project. | `/xxxxxxxxxx` | ⬜️ |
|
||||
| `disable_certificate_verification` | A Boolean value that opts-in SSL certificate validation is disabled | `false` | ⬜️ |
|
||||
|
||||
## Uninstalling
|
||||
@@ -62,7 +63,3 @@ To fully uninstall the plugin, call:
|
||||
```bash
|
||||
gem uninstall cocoapods-xcremotecache
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
* When `generate_multiple_pod_projects` mode is enabled, only first-party targets are cached by XCRemoteCache (all dependencies are compiled locally).
|
||||
|
||||
@@ -24,12 +24,12 @@ module CocoapodsXCRemoteCacheModifier
|
||||
# Registers for CocoaPods plugin hooks
|
||||
module Hooks
|
||||
BIN_DIR = '.rc'
|
||||
FAKE_SRCROOT = "/#{'x' * 10 }"
|
||||
LLDB_INIT_COMMENT="#RemoteCacheCustomSourceMap"
|
||||
LLDB_INIT_PATH = "#{ENV['HOME']}/.lldbinit"
|
||||
FAT_ARCHIVE_NAME_INFIX = 'arm64-x86_64'
|
||||
XCRC_COOCAPODS_ROOT_KEY = 'XCRC_COOCAPODS_ROOT'
|
||||
|
||||
# List of plugins' user properties that should be copied to .rcinfo
|
||||
# List of plugins' user properties that should not be copied to .rcinfo
|
||||
CUSTOM_CONFIGURATION_KEYS = [
|
||||
'enabled',
|
||||
'xcrc_location',
|
||||
@@ -39,8 +39,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
'check_build_configuration',
|
||||
'check_platform',
|
||||
'modify_lldb_init',
|
||||
'prettify_meta_files',
|
||||
'disable_certificate_verification'
|
||||
'fake_src_root',
|
||||
]
|
||||
|
||||
class XCRemoteCache
|
||||
@@ -63,9 +62,15 @@ module CocoapodsXCRemoteCacheModifier
|
||||
'remote_commit_file' => "#{BIN_DIR}/arc.rc",
|
||||
'exclude_targets' => [],
|
||||
'prettify_meta_files' => false,
|
||||
'disable_certificate_verification' => false
|
||||
'fake_src_root' => "/#{'x' * 10 }",
|
||||
'disable_certificate_verification' => false,
|
||||
'custom_rewrite_envs' => []
|
||||
}
|
||||
@@configuration.merge! default_values.select { |k, v| !@@configuration.key?(k) }
|
||||
# Always include XCRC_COOCAPODS_ROOT_KEY in custom_rewrite_envs
|
||||
unless @@configuration['custom_rewrite_envs'].include?(XCRC_COOCAPODS_ROOT_KEY)
|
||||
@@configuration['custom_rewrite_envs'] << XCRC_COOCAPODS_ROOT_KEY
|
||||
end
|
||||
end
|
||||
|
||||
def self.validate_configuration()
|
||||
@@ -106,8 +111,10 @@ module CocoapodsXCRemoteCacheModifier
|
||||
# @param mode [String] mode name ('consumer', 'producer', 'producer-fast' etc.)
|
||||
# @param exclude_build_configurations [String[]] list of targets that should have disabled remote cache
|
||||
# @param final_target [String] name of target that should trigger marking
|
||||
def self.enable_xcremotecache(target, repo_distance, xc_location, xc_cc_path, mode, exclude_build_configurations, final_target)
|
||||
def self.enable_xcremotecache(target, repo_distance, xc_location, xc_cc_path, mode, exclude_build_configurations, final_target, fake_src_root)
|
||||
srcroot_relative_xc_location = parent_dir(xc_location, repo_distance)
|
||||
# location of the entrite CocoaPods project, relative to SRCROOT
|
||||
srcroot_relative_project_location = parent_dir('', repo_distance)
|
||||
|
||||
target.build_configurations.each do |config|
|
||||
# apply only for relevant Configurations
|
||||
@@ -121,8 +128,9 @@ module CocoapodsXCRemoteCacheModifier
|
||||
config.build_settings['LIBTOOL'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xclibtool"]
|
||||
config.build_settings['LD'] = ["$SRCROOT/#{srcroot_relative_xc_location}/xcld"]
|
||||
|
||||
config.build_settings['XCREMOTE_CACHE_FAKE_SRCROOT'] = FAKE_SRCROOT
|
||||
config.build_settings['XCREMOTE_CACHE_FAKE_SRCROOT'] = fake_src_root
|
||||
config.build_settings['XCRC_PLATFORM_PREFERRED_ARCH'] = ["$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(PLATFORM_PREFERRED_ARCH):dir:standardizepath:file:default=arm64)"]
|
||||
config.build_settings[XCRC_COOCAPODS_ROOT_KEY] = ["$SRCROOT/#{srcroot_relative_project_location}"]
|
||||
debug_prefix_map_replacement = '$(SRCROOT' + ':dir:standardizepath' * repo_distance + ')'
|
||||
add_cflags!(config.build_settings, '-fdebug-prefix-map', "#{debug_prefix_map_replacement}=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
|
||||
add_swiftflags!(config.build_settings, '-debug-prefix-map', "#{debug_prefix_map_replacement}=$(XCREMOTE_CACHE_FAKE_SRCROOT)")
|
||||
@@ -146,8 +154,10 @@ module CocoapodsXCRemoteCacheModifier
|
||||
prebuild_script.dependency_file = "$(TARGET_TEMP_DIR)/prebuild.d"
|
||||
|
||||
# Move prebuild (last element) to the position before compile sources phase (to make it real 'prebuild')
|
||||
compile_phase_index = target.build_phases.index(target.source_build_phase)
|
||||
target.build_phases.insert(compile_phase_index, target.build_phases.delete(prebuild_script))
|
||||
if !existing_prebuild_script
|
||||
compile_phase_index = target.build_phases.index(target.source_build_phase)
|
||||
target.build_phases.insert(compile_phase_index, target.build_phases.delete(prebuild_script))
|
||||
end
|
||||
elsif mode == 'producer' || mode == 'producer-fast'
|
||||
# Delete existing prebuild build phase (to support switching between modes)
|
||||
target.build_phases.delete_if do |phase|
|
||||
@@ -201,6 +211,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
# Remove Fake src root for ObjC & Swift
|
||||
config.build_settings.delete('XCREMOTE_CACHE_FAKE_SRCROOT')
|
||||
config.build_settings.delete('XCRC_PLATFORM_PREFERRED_ARCH')
|
||||
config.build_settings.delete(XCRC_COOCAPODS_ROOT_KEY)
|
||||
remove_cflags!(config.build_settings, '-fdebug-prefix-map')
|
||||
remove_swiftflags!(config.build_settings, '-debug-prefix-map')
|
||||
end
|
||||
@@ -306,7 +317,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
end
|
||||
|
||||
# Remove .lldbinit rewrite
|
||||
save_lldbinit_rewrite(nil) unless !@@configuration['modify_lldb_init']
|
||||
save_lldbinit_rewrite(nil,nil) unless !@@configuration['modify_lldb_init']
|
||||
end
|
||||
|
||||
# Returns the content (array of lines) of the lldbinit with stripped XCRemoteCache rewrite
|
||||
@@ -328,17 +339,17 @@ module CocoapodsXCRemoteCacheModifier
|
||||
end
|
||||
|
||||
# Append source rewrite command to the lldbinit content
|
||||
def self.add_lldbinit_rewrite(lines_content, user_proj_directory)
|
||||
def self.add_lldbinit_rewrite(lines_content, user_proj_directory,fake_src_root)
|
||||
all_lines = lines_content.clone
|
||||
all_lines << LLDB_INIT_COMMENT
|
||||
all_lines << "settings set target.source-map #{FAKE_SRCROOT} #{user_proj_directory}"
|
||||
all_lines << "settings set target.source-map #{fake_src_root} #{user_proj_directory}"
|
||||
all_lines << ""
|
||||
all_lines
|
||||
end
|
||||
|
||||
def self.save_lldbinit_rewrite(user_proj_directory)
|
||||
def self.save_lldbinit_rewrite(user_proj_directory,fake_src_root)
|
||||
lldbinit_lines = clean_lldbinit_content(LLDB_INIT_PATH)
|
||||
lldbinit_lines = add_lldbinit_rewrite(lldbinit_lines, user_proj_directory) unless user_proj_directory.nil?
|
||||
lldbinit_lines = add_lldbinit_rewrite(lldbinit_lines, user_proj_directory,fake_src_root) unless user_proj_directory.nil?
|
||||
File.write(LLDB_INIT_PATH, lldbinit_lines.join("\n"), mode: "w")
|
||||
end
|
||||
|
||||
@@ -370,6 +381,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
final_target = @@configuration['final_target']
|
||||
check_build_configuration = @@configuration['check_build_configuration']
|
||||
check_platform = @@configuration['check_platform']
|
||||
fake_src_root = @@configuration['fake_src_root']
|
||||
|
||||
xccc_location_absolute = "#{user_proj_directory}/#{xccc_location}"
|
||||
xcrc_location_absolute = "#{user_proj_directory}/#{xcrc_location}"
|
||||
@@ -401,7 +413,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, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target)
|
||||
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root)
|
||||
end
|
||||
|
||||
# Create .rcinfo into `Pods` directory as that .xcodeproj reads configuration from .xcodeproj location
|
||||
@@ -414,7 +426,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
next if target.source_build_phase.files_references.empty?
|
||||
next if target.name.end_with?("Tests")
|
||||
next if exclude_targets.include?(target.name)
|
||||
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target)
|
||||
enable_xcremotecache(target, 1, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root)
|
||||
end
|
||||
generated_project.save()
|
||||
end
|
||||
@@ -454,15 +466,15 @@ module CocoapodsXCRemoteCacheModifier
|
||||
# Attach XCRC to the app targets
|
||||
user_project.targets.each do |target|
|
||||
next if exclude_targets.include?(target.name)
|
||||
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target)
|
||||
enable_xcremotecache(target, 0, xcrc_location, xccc_location, mode, exclude_build_configurations, final_target,fake_src_root)
|
||||
end
|
||||
|
||||
# Set Target sourcemap
|
||||
if @@configuration['modify_lldb_init']
|
||||
save_lldbinit_rewrite(user_proj_directory)
|
||||
save_lldbinit_rewrite(user_proj_directory,fake_src_root)
|
||||
else
|
||||
Pod::UI.puts "[XCRC] lldbinit modification is disabled. Debugging may behave weirdly"
|
||||
Pod::UI.puts "[XCRC] put \"settings set target.source-map #{FAKE_SRCROOT} \#{your_project_directory}\" to your \".lldbinit\" "
|
||||
Pod::UI.puts "[XCRC] put \"settings set target.source-map #{fake_src_root} \#{your_project_directory}\" to your \".lldbinit\" "
|
||||
end
|
||||
|
||||
user_project.save()
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
# limitations under the License.
|
||||
|
||||
module CocoapodsXcremotecache
|
||||
VERSION = "0.0.8"
|
||||
VERSION = "0.0.12"
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
## Development - How to build
|
||||
|
||||
Generated [docs](https://spotify.github.io/XCRemoteCache/documentation/xcremotecache/).
|
||||
|
||||
### Building the library:
|
||||
|
||||
`CONFIG=Debug rake build`
|
||||
|
||||
Reference in New Issue
Block a user