Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62b637bdaa | |||
| 0bca5e5bc4 | |||
| eb0d4b17b7 | |||
| d9ea5bfd49 | |||
| ee8bf69814 | |||
| 2c0f78056f | |||
| b6b17bdc8a | |||
| a387359930 | |||
| 456233b90e | |||
| d6f6e2e9bc | |||
| a35bd0b394 | |||
| def131f2a0 | |||
| ccda424791 | |||
| 6715824195 | |||
| c4e08d4288 | |||
| a2067f8dfe | |||
| 253e9597bd | |||
| 4a93f944fd |
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,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.8"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user