Compare commits

...

32 Commits

Author SHA1 Message Date
Bartosz Polaczyk ef3a88c6ec Merge pull request #122 from polac24/20220418-derived
Fix building target dependencies list with custom DERIVED_FILE_DIR
2022-04-19 09:32:43 +02:00
Bartosz Polaczyk 95f95be29e Identify custom DerivedData under sources dir 2022-04-18 09:07:36 +02:00
Bartosz Polaczyk 4d12800096 Skip all DerivedData files in dependencies list 2022-04-18 09:04:17 +02:00
Bartosz Polaczyk fbb456b0e0 Merge pull request #121 from cezarsignori/csignori/rc_derived_files_dir
Set auto-generated Swift header under DERIVED_FILES_DIR as irrelevant dependency
2022-04-18 08:57:44 +02:00
Cezar Signori a321ea3362 Set auto-generated Swift header under DERIVED_FILES_DIR as irrelevant dependency 2022-04-14 14:20:30 +02:00
Bartosz Polaczyk 963e6858ee Merge pull request #117 from polac24/20220411-loop-configs
Load extra configuration in a chain
2022-04-12 22:31:46 +02:00
Bartosz Polaczyk f9999a402f Merge pull request #118 from polac24/20220412-bump-cocoapods
Bump CocoaPods plugin to 0.0.9
2022-04-12 22:25:42 +02:00
Bartosz Polaczyk dbfe1dd8d4 Bump CocoaPods plugin to 0.0.9 2022-04-12 15:44:52 +02:00
Bartosz Polaczyk def12fab6f Merge pull request #116 from samuelsainz/bugfix/prebuild-phase-order
Fix error that moves the Prebuild phase script after the source phase
2022-04-12 00:01:12 +02:00
Bartosz Polaczyk 6fee69f081 Fix linter 2022-04-11 20:10:43 +02:00
Bartosz Polaczyk b74bafa5d7 Cleanup tests 2022-04-11 19:53:33 +02:00
Bartosz Polaczyk 33de361317 Add Readme docs 2022-04-11 19:40:00 +02:00
Bartosz Polaczyk 0aeb5aee36 Allow importing extra config multiple times 2022-04-11 19:37:36 +02:00
Samuel Sainz 8682731f30 Fix error that moves the Prebuild phase script after the source build phase 2022-04-11 11:03:15 -03:00
Bartosz Polaczyk 62b637bdaa Merge pull request #113 from polac24/cocoapods-bump-008
Bump cocoapods plugin version 0.0.8
2022-04-04 09:27:19 +02:00
Bartosz Polaczyk 0bca5e5bc4 Bump cocoapods plugin version 0.0.8 2022-04-04 08:14:06 +02:00
Bartosz Polaczyk eb0d4b17b7 Merge pull request #95 from polac24/20220226-pch-suport
Switch to local PCH headers compilation
2022-04-01 08:41:39 +02:00
Bartosz Polaczyk d9ea5bfd49 Apply suggestions from code review
Co-authored-by: Aleksander Grzyb <aleksander.grzyb@gmail.com>
2022-04-01 08:24:07 +02:00
Bartosz Polaczyk ee8bf69814 Add comments 2022-03-31 22:09:55 +02:00
Bartosz Polaczyk 2c0f78056f Merge branch 'master' into 20220226-pch-suport 2022-03-31 22:03:10 +02:00
Bartosz Polaczyk b6b17bdc8a Merge pull request #111 from devMEremenko/integrate-aws-security-token
Integrate AWS Temporary Access Keys
2022-03-31 20:15:30 +02:00
Maxim Eremenko a387359930 Removed trailing_whitespace 2022-03-31 20:44:13 +03:00
Maxim Eremenko 456233b90e Update tests 2022-03-30 23:46:15 +03:00
Maxim Eremenko d6f6e2e9bc Integrate AWS Temporary Security Token 2022-03-30 23:21:22 +03:00
Bartosz Polaczyk a35bd0b394 Merge pull request #110 from samuelsainz/bugfix/mark-script_build-config-param
Adding quotes to the config param in the Mark script
2022-03-25 23:20:02 +01:00
Samuel Sainz def131f2a0 Fix config param in Mark script considering build configs with a space in the name 2022-03-25 17:40:17 -03:00
Bartosz Polaczyk ccda424791 Formatting 2022-02-28 22:55:04 +01:00
Bartosz Polaczyk 6715824195 Update Sources/XCRemoteCache/Commands/Prepare/CCWrapperBuilder.swift 2022-02-28 08:29:35 +01:00
Bartosz Polaczyk c4e08d4288 Remove limitation 2022-02-26 19:11:54 +01:00
Bartosz Polaczyk a2067f8dfe Add unit test 2022-02-26 18:37:56 +01:00
Bartosz Polaczyk 253e9597bd Force compilation success in xccc generation tests 2022-02-26 18:37:56 +01:00
Bartosz Polaczyk 4a93f944fd Fallback when compiling pch header 2022-02-26 16:03:54 +01:00
25 changed files with 245 additions and 39 deletions
+4 -2
View File
@@ -288,7 +288,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 | `[]` | ⬜️ |
@@ -308,6 +308,7 @@ _Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`,
| `prettify_meta_files` | A Boolean value that opts-in pretty JSON formatting for meta files | `false` | ⬜️ |
| `aws_secret_key` | Secret key for AWS V4 Signature Authorization. If this is set to a non-empty String - an Authentication Header will be added based on this and the other `aws_*` parameters.| `""` | ⬜️ |
| `aws_access_key` | Access key for AWS V4 Signature Authorization. | `""` | ⬜️ |
| `aws_security_token` | Temporary security token provided by the AWS Security Token Service. | `nil` | ⬜️ |
| `aws_region` | Region for AWS V4 Signature Authorization. E.g. `eu`. | `""` | ⬜️ |
| `aws_service` | Service for AWS V4 Signature Authorization. E.g. `storage`. | `""` | ⬜️ |
| `out_of_band_mappings` | A dictionary of files path remapping that should be applied to make it absolute path agnostic on a list of dependencies. Useful if a project refers files out of repo root, either compilation files or precompiled dependencies. Keys represent generic replacement and values are substrings that should be replaced. Example: for mapping `["COOL_LIBRARY": "/CoolLibrary"]` `/CoolLibrary/main.swift`will be represented as `$(COOL_LIBRARY)/main.swift`). Warning: remapping order is not-deterministic so avoid remappings with multiple matchings. | `[:]` | ⬜️ |
@@ -351,6 +352,8 @@ XCRemoteCache supports Amazon S3 and Google Cloud Storage buckets to be used as
To set it up use the configuration parameters `aws_secret_key`, `aws_access_key`, `aws_region`, and `aws_service` in the `.rcinfo` file. Specify the URL to the bucket in cache-addresses field in the same file.
XCRemoteCache also supports [AWS Temporary Access Keys](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#temporary-access-keys). Use additional `aws_security_token` parameter combined with `aws_secret_key`, `aws_access_key` to set it up. [This page](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) describes how to receive a security token.
Example
```yaml
...
@@ -411,7 +414,6 @@ Note: This setup is not recommended and may not be supported in future XCRemoteC
* 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.
* Using "Precompiled prefix headers" for Objective-C targets is not yet supported. [PR is welcome]
## FAQ
@@ -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
@@ -91,6 +92,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
@@ -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
@@ -114,6 +114,7 @@ public class XCPostbuild {
awsV4Signature = AWSV4Signature(
secretKey: config.AWSSecretKey,
accessKey: config.AWSAccessKey,
securityToken: config.AWSSecurityToken,
region: config.AWSRegion,
service: config.AWSService,
date: Date(timeIntervalSinceNow: 0)
@@ -170,6 +171,7 @@ public class XCPostbuild {
product: context.productsDir,
source: context.srcRoot,
intermediate: context.targetTempDir,
derivedFiles: context.derivedFilesDir,
bundle: context.bundleDir
)
// Override fingerprints for all produced '.swiftmodule' files
@@ -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 {
@@ -96,6 +96,7 @@ public class XCPrebuild {
awsV4Signature = AWSV4Signature(
secretKey: config.AWSSecretKey,
accessKey: config.AWSAccessKey,
securityToken: config.AWSSecurityToken,
region: config.AWSRegion,
service: config.AWSService,
date: Date(timeIntervalSinceNow: 0)
@@ -395,6 +395,8 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
const char *dependency_arg_name = "-MF";
const char *output_arg_name = "-o";
const char *serialize_diagnostics_arg_name = "--serialize-diagnostics";
const char *language_mode_arg_name = "-x";
const char *precompile_header_arg_value = "objective-c-header";
const char *clang_cmd = "\(clangCommand)";
const char *markerFile = "\(markerFilename)";
const char *compilationHistoryFile = "\(compilationHistoryFilename)";
@@ -409,6 +411,7 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
const char *output_file= NULL;
const char *input_file = NULL;
const char *diagnostics_file = NULL;
const char *language_mode = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], dependency_arg_name) == 0 && i < (argc - 1) ) {
@@ -429,6 +432,12 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
i += 1;
clang_args[i] = argv[i];
diagnostics_file = argv[i];
} if (strcmp(argv[i], language_mode_arg_name) == 0 && i < (argc - 1) ) {
// called with "-x path" pattern and not the last argument
clang_args[i] = argv[i];
i += 1;
clang_args[i] = argv[i];
language_mode = argv[i];
} else if (
isSuffixed(argv[i],".m") ||
isSuffixed(argv[i],".mm") ||
@@ -442,6 +451,7 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
) {
// a full list of extensions is taken from https://clang.llvm.org/docs/ClangFormatStyleOptions.html
// support for .m,.mm,.c,.cc,.cpp,.c++,.cxx input files
// .s and .S are assembly files
clang_args[i] = argv[i];
input_file = argv[i];
} else {
@@ -450,6 +460,14 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
}
}
// null-terminating the args array needed for local compilation fallback
clang_args[argc] = NULL;
// Verify mode. Even a target is cached, pch mode is not supported. Fallback to the local compilation
if (language_mode != NULL && strcmp(language_mode, precompile_header_arg_value) == 0) {
return execvp(clang_cmd, (char *const*) clang_args);
}
// Verify all input arguments
if (dependency_file == NULL) {
fprintf(stderr, "error: missing %s input\\n", dependency_arg_name);
@@ -520,8 +538,6 @@ class TemplateBasedCCWrapperBuilder: CCWrapperBuilder {
}
}
// null-terminating the args array
clang_args[argc] = NULL;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
/// execvp takes $PATH to consideration
@@ -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 {
@@ -78,6 +78,7 @@ public class XCPrepare {
awsV4Signature = AWSV4Signature(
secretKey: config.AWSSecretKey,
accessKey: config.AWSAccessKey,
securityToken: config.AWSSecurityToken,
region: config.AWSRegion,
service: config.AWSService,
date: Date(timeIntervalSinceNow: 0)
@@ -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 {
@@ -60,6 +60,7 @@ public class XCPrepareMark {
awsV4Signature = AWSV4Signature(
secretKey: config.AWSSecretKey,
accessKey: config.AWSAccessKey,
securityToken: config.AWSSecurityToken,
region: config.AWSRegion,
service: config.AWSService,
date: Date(timeIntervalSinceNow: 0)
@@ -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 {
@@ -118,6 +118,8 @@ public struct XCRemoteCacheConfig: Encodable {
var AWSSecretKey: String = ""
/// Access key for AWS V4 Signature
var AWSAccessKey: String = ""
/// Temporary security token provided by the AWS Security Token Service
var AWSSecurityToken: String?
/// Region for AWS V4 Signature (e.g. `eu`)
var AWSRegion: String = ""
/// Service for AWS V4 Signature (e.g. `storage`)
@@ -184,6 +186,7 @@ extension XCRemoteCacheConfig {
merge.prettifyMetaFiles = scheme.prettifyMetaFiles ?? prettifyMetaFiles
merge.AWSAccessKey = scheme.AWSAccessKey ?? AWSAccessKey
merge.AWSSecretKey = scheme.AWSSecretKey ?? AWSSecretKey
merge.AWSSecurityToken = scheme.AWSSecurityToken ?? AWSSecurityToken
merge.AWSRegion = scheme.AWSRegion ?? AWSRegion
merge.AWSService = scheme.AWSService ?? AWSService
merge.outOfBandMappings = scheme.outOfBandMappings ?? outOfBandMappings
@@ -247,6 +250,7 @@ struct ConfigFileScheme: Decodable {
let prettifyMetaFiles: Bool?
let AWSSecretKey: String?
let AWSAccessKey: String?
let AWSSecurityToken: String?
let AWSRegion: String?
let AWSService: String?
let outOfBandMappings: [String: String]?
@@ -293,6 +297,7 @@ struct ConfigFileScheme: Decodable {
case prettifyMetaFiles = "prettify_meta_files"
case AWSSecretKey = "aws_secret_key"
case AWSAccessKey = "aws_access_key"
case AWSSecurityToken = "aws_security_token"
case AWSRegion = "aws_region"
case AWSService = "aws_service"
case outOfBandMappings = "out_of_band_mappings"
@@ -311,31 +316,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()
@@ -343,7 +358,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,6 +27,7 @@ public struct Dependency: Equatable {
case source
case fingerprint
case intermediate
case derivedFile
// Product of the target itself
case ownProduct
case unknown
@@ -55,13 +56,15 @@ class DependencyProcessorImpl: DependencyProcessor {
private let productPath: String
private let sourcePath: String
private let intermediatePath: String
private let derivedFilesPath: String
private let bundlePath: 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?) {
xcodePath = xcode.path.dirPath()
productPath = product.path.dirPath()
sourcePath = source.path.dirPath()
intermediatePath = intermediate.path.dirPath()
derivedFilesPath = derivedFiles.path.dirPath()
bundlePath = bundle?.path.dirPath()
}
@@ -77,6 +80,8 @@ class DependencyProcessorImpl: DependencyProcessor {
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 +112,9 @@ 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`
let irrelevantDependenciesType: [Dependency.Kind] = [.xcode, .intermediate, .ownProduct, .derivedFile]
return !irrelevantDependenciesType.contains(dependency.type)
}
}
@@ -23,17 +23,21 @@ struct AWSV4Signature {
let secretKey: String
let accessKey: String
let securityToken: String?
let region: String
let service: String
let date: Date
func addSignatureHeaderTo(request: inout URLRequest) {
request.setValue(request.url?.host, forHTTPHeaderField: "host")
request.setValue(StringToSign.ISO8601BasicFormatter.string(from: date), forHTTPHeaderField: "x-amz-date")
request.setValue((request.httpBody ?? Data()).sha256(), forHTTPHeaderField: "x-amz-content-sha256")
if let securityToken = securityToken {
request.setValue(securityToken, forHTTPHeaderField: "x-amz-security-token")
}
let canonicalRequest = CanonicalRequest(request: request)
let stringToSign = StringToSign(
region: region,
@@ -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: "",
@@ -78,6 +79,7 @@ class PostbuildTests: FileXCTestCase {
product: "/Product",
source: "/Source",
intermediate: "/Intermediate",
derivedFiles: "/DerivedFiles",
bundle: nil
)
private var overrideManager = FingerprintOverrideManagerImpl(
@@ -47,7 +47,8 @@ class TemplateBasedCCWrapperBuilderTests: FileXCTestCase {
let app = appDir.appendingPathComponent("xccc")
try? fileManager.removeItem(at: appDir)
try? FileManager.default.createDirectory(at: appDir, withIntermediateDirectories: true, attributes: nil)
try? builder.compile(to: app, commitSha: commitSha)
// swiftlint:disable:next force_try
try! builder.compile(to: app, commitSha: commitSha)
return app
}()
@@ -332,11 +333,31 @@ class TemplateBasedCCWrapperBuilderTests: FileXCTestCase {
XCTAssertNotEqual(newFileOutputData, Data())
}
func testPCHCompilationFallbacks() throws {
// Marker is empty to mimic the new file scenario
let pchFile = directory.appendingPathComponent("input.pch")
createValidPCHFile(pchFile)
arguments = ["-x", "objective-c-header", "-MF", dependencyFile.path, "-o", outputFile.path, pchFile.path]
try shellExec(Self.xccc.path, args: arguments, inDir: directory.path)
XCTAssertTrue(fileManager.fileExists(atPath: outputFile.path))
}
/// Creates a simple C code in the location
private func createValidCFile(_ location: URL) {
fileManager.createFile(atPath: location.path, contents: "int main(){}".data(using: .utf8), attributes: nil)
}
/// Creates a simple PCH code in the location
private func createValidPCHFile(_ location: URL) {
fileManager.createFile(
atPath: location.path,
contents: "#import <Availability.h>".data(using: .utf8),
attributes: nil
)
}
/// Creates a C code that requires extra CUSTOM_STR clang macro to compile
private func createInvalidCFile(_ location: URL) {
fileManager.createFile(
@@ -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,6 +27,7 @@ class DependencyProcessorImplTests: FileXCTestCase {
product: "/Product",
source: "/Source",
intermediate: "/Intermediate",
derivedFiles: "/DerivedFiles",
bundle: "/Bundle"
)
@@ -37,6 +38,7 @@ class DependencyProcessorImplTests: FileXCTestCase {
product: "/",
source: "/",
intermediate: "/Intermediate",
derivedFiles: "/DerivedFiles",
bundle: nil
)
@@ -53,6 +55,7 @@ class DependencyProcessorImplTests: FileXCTestCase {
product: "/",
source: "/",
intermediate: "/Intermediate",
derivedFiles: "/DerivedFiles",
bundle: "/Bundle"
)
@@ -62,6 +65,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,6 +149,7 @@ class DependencyProcessorImplTests: FileXCTestCase {
product: "/Product",
source: "/Source",
intermediate: intermediateDirReal,
derivedFiles: "/DerivedFiles",
bundle: "/Bundle"
)
@@ -158,6 +178,7 @@ class DependencyProcessorImplTests: FileXCTestCase {
product: "/Product",
source: sourceDirReal,
intermediate: "/Intermediate",
derivedFiles: "/DerivedFiles",
bundle: "/Bundle"
)
@@ -189,4 +210,21 @@ 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
)
XCTAssertEqual(
processor.process([derivedFile]),
[]
)
}
}
@@ -35,10 +35,12 @@ class AWSV4SignatureTest: XCTestCase {
let key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
let accessKey = "AKIDEXAMPLE"
let securityToken = "IQoJb3JpZ2luX2VjENv//////////wEaCXVzLWVhc3Q+bsHwqnovXtl/1JVe61XHMnAw3AIXwOAOxqMvhw=="
AWSV4Signature(
secretKey: key,
accessKey: accessKey,
securityToken: securityToken,
region: "us-east-1",
service: "iam",
date: Date(timeIntervalSince1970: 1_440_938_160)
@@ -49,8 +51,8 @@ class AWSV4SignatureTest: XCTestCase {
func testAuthHeaderContainsCorrectSignature() throws {
XCTAssertEqual(
"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, " +
"SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, " +
"Signature=dd479fa8a80364edf2119ec24bebde66712ee9c9cb2b0d92eb3ab9ccdc0c3947",
"SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-security-token, " +
"Signature=d26ab974bba1b248f041ea1120064e1fa672d6f06cac2cff42b38acea87b76e5",
request.allHTTPHeaderFields?["Authorization"]
)
}
@@ -203,6 +203,7 @@ class NetworkClientImplTests: XCTestCase {
let signature = AWSV4Signature(
secretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
accessKey: "AKIDEXAMPLE",
securityToken: "IQoJb3JpZ2luX2VjENv//////////wEaCXVzLWVhc3Q+bsHwqnovXtl/1JVe61XHMnAw3AIXwOAOxqMvhw==",
region: "us-east-1",
service: "iam",
date: Date(timeIntervalSince1970: 1_440_938_160)
@@ -213,8 +214,8 @@ class NetworkClientImplTests: XCTestCase {
XCTAssertEqual(
"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, " +
"SignedHeaders=host;x-amz-content-sha256;x-amz-date, " +
"Signature=acdb223475463b6ce711b063f199387a7a12bd638e4dccaaeb5efcbf159b6454",
"SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, " +
"Signature=e5578464567fb97fd26e871702e4ec4ff7d61cb87eb72a40d22b80e12da30c34",
try requests[0].allHTTPHeaderFields?["Authorization"].unwrap()
)
}
@@ -146,8 +146,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|
@@ -180,7 +182,7 @@ module CocoapodsXCRemoteCacheModifier
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.shell_script = "\"$SCRIPT_INPUT_FILE_0\" mark --configuration \"$CONFIGURATION\" --platform $PLATFORM_NAME"
mark_script.input_paths = ["$SRCROOT/#{srcroot_relative_xc_location}/xcprepare"]
else
# Delete existing mark build phase (to support switching between modes or changing the final target)
@@ -13,5 +13,5 @@
# limitations under the License.
module CocoapodsXcremotecache
VERSION = "0.0.7"
VERSION = "0.0.9"
end