Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9363e68d51 | |||
| 4af8156da5 | |||
| f086feb005 | |||
| d98d4cd0a3 | |||
| a38d445ae9 | |||
| 0436f6ae27 | |||
| be78959437 | |||
| cccae0d9f6 | |||
| e7d1e905cf | |||
| 20d53a1c71 | |||
| f4ba03d581 | |||
| 0e48d39818 | |||
| 3b30939f99 | |||
| e263cb6e25 | |||
| b805bf4a99 | |||
| fd7b68a344 | |||
| a63488a043 | |||
| 48bcdd8ce9 | |||
| 41dd1cae03 |
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: ⚠️ Bug Report
|
||||
about: Something isn't working as expected
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||
-->
|
||||
|
||||
**My integration setup**
|
||||
|
||||
[ ] CocoaPods cocoapods-xcremotecache plugin
|
||||
[ ] Automatic integration using `xcprepare integrate ...`
|
||||
[ ] Manual integration
|
||||
[ ] Carthage
|
||||
|
||||
**Expected/desired behavior**
|
||||
<!-- Describe what the desired behavior would be. -->
|
||||
|
||||
**Minimal reproduction of the problem with instructions**
|
||||
<!-- Please provide the *STEPS TO REPRODUCE*. -->
|
||||
|
||||
**Producer Logs**
|
||||
<!-- Capture logs from 10 minutes: `log show --predicate 'sender BEGINSWITH "xc"' --style compact --info --debug -last 10m` -->
|
||||
|
||||
<details>
|
||||
<pre> [REPLACE THIS WITH YOUR INFORMATION] </pre>
|
||||
</details>
|
||||
|
||||
**Consumer Logs**
|
||||
<!-- Capture logs from 10 minutes: `log show --predicate 'sender BEGINSWITH "xc"' --style compact --info --debug -last 10m` -->
|
||||
|
||||
<details>
|
||||
<pre> [REPLACE THIS WITH YOUR INFORMATION] </pre>
|
||||
</details>
|
||||
|
||||
**Pods/Carthage file**
|
||||
<!-- Delete if you don't use CocoaPods or Carthage -->
|
||||
|
||||
<details>
|
||||
<pre> [REPLACE THIS WITH YOUR INFORMATION] </pre>
|
||||
</details>
|
||||
|
||||
**Environment**
|
||||
|
||||
* **XCRemoteCache:** X.Y.Z
|
||||
* **cocoapods-xcremotecache:** X.Y.Z <!-- check with `gem list cocoapods-xcremotecache` >
|
||||
* **HTTP cache server:** ... <!-- e.g. demo docker, nginx, AWS etc. >
|
||||
* **Xcode:** X.Y.Z
|
||||
|
||||
**Post build stats**
|
||||
<!--
|
||||
To capture build statistics:
|
||||
* call `xcprepare stats --reset` (or `XCRC/xcprepare stats --reset` for CocoaPods)
|
||||
* Build a project in Xcode
|
||||
* `xcprepare stats` (or `XCRC/xcprepare stats` for CocoaPods)
|
||||
-->
|
||||
|
||||
<details>
|
||||
<pre> [REPLACE THIS WITH YOUR INFORMATION] </pre>
|
||||
</details>
|
||||
|
||||
**Others**
|
||||
<!-- Anything else relevant? Operating system version, , ... -->
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: 📕 Documentation Issue
|
||||
about: Suggestion for a change in a documentation
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||
-->
|
||||
|
||||
**A suggestion**
|
||||
<!-- Describe how could the documentation be improved. -->
|
||||
|
||||
**Which file, section, line**
|
||||
<!-- Provide a section it relates (if exist). -->
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: 🙏 Future Request
|
||||
about: Suggestion for an improvement, either behaviour or implementation
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||
-->
|
||||
|
||||
|
||||
**Expected/desired behavior**
|
||||
<!-- Describe what the desired behavior would be. -->
|
||||
|
||||
**Relevant integration setup**
|
||||
|
||||
[ ] CocoaPods cocoapods-xcremotecache plugin
|
||||
[ ] Automatic integration using `xcprepare integrate ...`
|
||||
[ ] Manual integration
|
||||
[ ] Carthage
|
||||
@@ -312,6 +312,7 @@ _Note that for the `producer` mode, the prebuild build phase and `xccc`, `xcld`,
|
||||
| `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. | `[:]` | ⬜️ |
|
||||
| `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` | ⬜️ |
|
||||
|
||||
## Backend cache server
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ class Postbuild {
|
||||
// Replace all local paths to the generic ones (e.g. $SRCROOT)
|
||||
let remappers = [remapper] + creatorPlugins.compactMap(\.customPathsRemapper)
|
||||
let remapper = DependenciesRemapperComposite(remappers)
|
||||
let abstractFingerprintFiles = remapper.replace(localPaths: dependencies.map(\.path))
|
||||
let abstractFingerprintFiles = try remapper.replace(localPaths: dependencies.map(\.path))
|
||||
// TODO: use `inputs` read by dependenciesReader
|
||||
var meta = MainArtifactMeta(
|
||||
dependencies: abstractFingerprintFiles,
|
||||
|
||||
@@ -145,18 +145,23 @@ public class XCPostbuild {
|
||||
fileDependeciesReaderFactory: fileReaderFactory,
|
||||
dirScanner: fileManager
|
||||
)
|
||||
// As the PostbuildContext assumes file location and filename (`all-product-headers.yaml`)
|
||||
// do not fail in case of a missing headers overlay file. In the future, all overlay files could be
|
||||
// captured from the swiftc invocation similarly is stored in the `history.compile` for the consumer mode.
|
||||
let overlayReader = JsonOverlayReader(
|
||||
context.overlayHeadersPath,
|
||||
mode: .bestEffort,
|
||||
fileReader: fileManager
|
||||
)
|
||||
let overlayRemapper = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
let pathRemapper = DependenciesRemapperComposite([overlayRemapper, envsRemapper])
|
||||
var remappers: [DependenciesRemapper] = []
|
||||
if !config.disableVFSOverlay {
|
||||
// As the PostbuildContext assumes file location and filename (`all-product-headers.yaml`)
|
||||
// do not fail in case of a missing headers overlay file. In the future, all overlay files could be
|
||||
// captured from the swiftc invocation similarly is stored in the `history.compile` for the consumer mode.
|
||||
let overlayReader = JsonOverlayReader(
|
||||
context.overlayHeadersPath,
|
||||
mode: .bestEffort,
|
||||
fileReader: fileManager
|
||||
)
|
||||
let overlayRemapper = OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
remappers.append(overlayRemapper)
|
||||
}
|
||||
remappers.append(envsRemapper)
|
||||
let pathRemapper = DependenciesRemapperComposite(remappers)
|
||||
let dependencyProcessor = DependencyProcessorImpl(
|
||||
xcode: context.xcodeDir,
|
||||
product: context.productsDir,
|
||||
|
||||
@@ -63,7 +63,7 @@ class Prebuild {
|
||||
do {
|
||||
let metaData = try networkClient.fetch(.meta(commit: commit))
|
||||
let meta = try metaReader.read(data: metaData)
|
||||
let localDependencies = remapper.replace(genericPaths: meta.dependencies).map(URL.init(fileURLWithPath:))
|
||||
let localDependencies = try remapper.replace(genericPaths: meta.dependencies).map(URL.init(fileURLWithPath:))
|
||||
let localFingerprint = try generateFingerprint(for: localDependencies)
|
||||
if localFingerprint.raw != meta.rawFingerprint {
|
||||
if context.forceCached {
|
||||
|
||||
@@ -120,17 +120,22 @@ public class XCPrebuild {
|
||||
envs: env,
|
||||
customMappings: config.outOfBandMappings
|
||||
)
|
||||
// As PrebuildContext assumes file location and its filename (`all-product-headers.yaml`)
|
||||
// do not fail in case of a missing headers overlay file.
|
||||
let overlayReader = JsonOverlayReader(
|
||||
context.overlayHeadersPath,
|
||||
mode: .bestEffort,
|
||||
fileReader: fileManager
|
||||
)
|
||||
let overlayRemapper = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
let pathRemapper = DependenciesRemapperComposite([overlayRemapper, envsRemapper])
|
||||
var remappers: [DependenciesRemapper] = []
|
||||
if !config.disableVFSOverlay {
|
||||
// As PrebuildContext assumes file location and its filename (`all-product-headers.yaml`)
|
||||
// do not fail in case of a missing headers overlay file.
|
||||
let overlayReader = JsonOverlayReader(
|
||||
context.overlayHeadersPath,
|
||||
mode: .bestEffort,
|
||||
fileReader: fileManager
|
||||
)
|
||||
let overlayRemapper = OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
remappers.append(overlayRemapper)
|
||||
}
|
||||
remappers.append(envsRemapper)
|
||||
let pathRemapper = DependenciesRemapperComposite(remappers)
|
||||
let filesFingerprintGenerator = FingerprintAccumulatorImpl(
|
||||
algorithm: MD5Algorithm(),
|
||||
fileManager: fileManager
|
||||
|
||||
@@ -227,11 +227,11 @@ struct XcodeProjIntegrate: Integrate {
|
||||
let previousRCPhases = target.buildPhases.filter(isRCPhase)
|
||||
target.buildPhases.removeAll(where: previousRCPhases.contains)
|
||||
|
||||
if target.buildPhases.map(\.buildPhase).contains(.sources) {
|
||||
if let sourceIndex = target.buildPhases.map(\.buildPhase).firstIndex(of: .sources) {
|
||||
// add (pre|post)build phases only when a target has some compilation steps
|
||||
// otherwise they make no sense (nothing to store in an artifact)
|
||||
pbxproj.add(object: prebuildPhase)
|
||||
target.buildPhases.insert(prebuildPhase, at: 0)
|
||||
target.buildPhases.insert(prebuildPhase, at: sourceIndex)
|
||||
pbxproj.add(object: postbuildPhase)
|
||||
target.buildPhases.append(postbuildPhase)
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ public struct XCRemoteCacheConfig: Encodable {
|
||||
var outOfBandMappings: [String: String] = [:]
|
||||
/// If true, SSL certificate validation is disabled
|
||||
var disableCertificateVerification: Bool = false
|
||||
/// A feature flag to disable virtual file system overlay support (temporary)
|
||||
var disableVFSOverlay: Bool = false
|
||||
}
|
||||
|
||||
extension XCRemoteCacheConfig {
|
||||
@@ -183,6 +185,7 @@ extension XCRemoteCacheConfig {
|
||||
merge.AWSService = scheme.AWSService ?? AWSService
|
||||
merge.outOfBandMappings = scheme.outOfBandMappings ?? outOfBandMappings
|
||||
merge.disableCertificateVerification = scheme.disableCertificateVerification ?? disableCertificateVerification
|
||||
merge.disableVFSOverlay = scheme.disableVFSOverlay ?? disableVFSOverlay
|
||||
return merge
|
||||
}
|
||||
|
||||
@@ -244,6 +247,7 @@ struct ConfigFileScheme: Decodable {
|
||||
let AWSService: String?
|
||||
let outOfBandMappings: [String: String]?
|
||||
let disableCertificateVerification: Bool?
|
||||
let disableVFSOverlay: Bool?
|
||||
|
||||
// Yams library doesn't support encoding strategy, see https://github.com/jpsim/Yams/issues/84
|
||||
enum CodingKeys: String, CodingKey {
|
||||
@@ -288,6 +292,7 @@ struct ConfigFileScheme: Decodable {
|
||||
case AWSService = "aws_service"
|
||||
case outOfBandMappings = "out_of_band_mappings"
|
||||
case disableCertificateVerification = "disable_certificate_verification"
|
||||
case disableVFSOverlay = "disable_vfs_overlay"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ import Foundation
|
||||
/// Replaces paths formats between generic (placeholders-based) and local
|
||||
protocol DependenciesRemapper {
|
||||
/// Replaces all generic paths (with placeholders) to a local paths
|
||||
func replace(genericPaths: [String]) -> [String]
|
||||
func replace(genericPaths: [String]) throws -> [String]
|
||||
/// Replaces all local paths to the generic dependencies paths
|
||||
func replace(localPaths: [String]) -> [String]
|
||||
func replace(localPaths: [String]) throws -> [String]
|
||||
}
|
||||
|
||||
class DependenciesRemapperComposite: DependenciesRemapper {
|
||||
@@ -34,15 +34,15 @@ class DependenciesRemapperComposite: DependenciesRemapper {
|
||||
self.remappers = remappers
|
||||
}
|
||||
|
||||
func replace(genericPaths: [String]) -> [String] {
|
||||
remappers.reversed().reduce(genericPaths) { prev, mapper in
|
||||
mapper.replace(genericPaths: prev)
|
||||
func replace(genericPaths: [String]) throws -> [String] {
|
||||
try remappers.reversed().reduce(genericPaths) { prev, mapper in
|
||||
try mapper.replace(genericPaths: prev)
|
||||
}
|
||||
}
|
||||
|
||||
func replace(localPaths: [String]) -> [String] {
|
||||
remappers.reduce(localPaths) { prev, mapper in
|
||||
mapper.replace(localPaths: prev)
|
||||
func replace(localPaths: [String]) throws -> [String] {
|
||||
try remappers.reduce(localPaths) { prev, mapper in
|
||||
try mapper.replace(localPaths: prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ final class StringDependenciesRemapper: DependenciesRemapper {
|
||||
self.mappings = mappings
|
||||
}
|
||||
|
||||
func replace(genericPaths: [String]) -> [String] {
|
||||
func replace(genericPaths: [String]) throws -> [String] {
|
||||
return genericPaths.map { path in
|
||||
let localPath = mappings.reversed().reduce(path) { prevPath, mapping in
|
||||
prevPath.replacingOccurrences(of: mapping.generic, with: mapping.local)
|
||||
@@ -68,7 +68,7 @@ final class StringDependenciesRemapper: DependenciesRemapper {
|
||||
}
|
||||
}
|
||||
|
||||
func replace(localPaths: [String]) -> [String] {
|
||||
func replace(localPaths: [String]) throws -> [String] {
|
||||
return localPaths.map { path in
|
||||
let result = mappings.reduce(path) { prevPath, mapping in
|
||||
prevPath.replacingOccurrences(of: mapping.local, with: mapping.generic)
|
||||
|
||||
@@ -20,20 +20,32 @@
|
||||
import Foundation
|
||||
|
||||
/// File paths remapper according the virtual file system mappings
|
||||
/// Warning: this class is not thread safe
|
||||
/// - Warning: this class is not thread safe
|
||||
class OverlayDependenciesRemapper: DependenciesRemapper {
|
||||
private var mappings: [OverlayMapping]
|
||||
private let overlayReader: OverlayReader
|
||||
private var mappings: [OverlayMapping]?
|
||||
|
||||
init(overlayReader: OverlayReader) throws {
|
||||
mappings = try overlayReader.provideMappings()
|
||||
init(overlayReader: OverlayReader) {
|
||||
self.overlayReader = overlayReader
|
||||
}
|
||||
|
||||
/// Lazily Reads mappings from a file
|
||||
/// - Warning: this function is not thread safe
|
||||
private func getMappings() throws -> [OverlayMapping] {
|
||||
guard let mappings = mappings else {
|
||||
let mappings = try overlayReader.provideMappings()
|
||||
self.mappings = mappings
|
||||
return mappings
|
||||
}
|
||||
return mappings
|
||||
}
|
||||
|
||||
private func mapPath(
|
||||
_ path: String,
|
||||
source: KeyPath<OverlayMapping,URL>,
|
||||
destination: KeyPath<OverlayMapping,URL>
|
||||
) -> String {
|
||||
guard let mapping = mappings.first(where: { $0[keyPath: source].path == path }) else {
|
||||
) throws -> String {
|
||||
guard let mapping = try getMappings().first(where: { $0[keyPath: source].path == path }) else {
|
||||
// TODO: support partial mappings, where a directory path can be replaced with some other directory
|
||||
// no direct mapping found
|
||||
return path
|
||||
@@ -41,15 +53,15 @@ class OverlayDependenciesRemapper: DependenciesRemapper {
|
||||
return mapping[keyPath: destination].path
|
||||
}
|
||||
|
||||
func replace(genericPaths: [String]) -> [String] {
|
||||
Set(genericPaths.map {
|
||||
mapPath($0, source: \.virtual, destination: \.local)
|
||||
}).sorted()
|
||||
func replace(genericPaths: [String]) throws -> [String] {
|
||||
try genericPaths.map {
|
||||
try mapPath($0, source: \.virtual, destination: \.local)
|
||||
}
|
||||
}
|
||||
|
||||
func replace(localPaths: [String]) -> [String] {
|
||||
Set(localPaths.map {
|
||||
mapPath($0, source: \.local, destination: \.virtual)
|
||||
}).sorted()
|
||||
func replace(localPaths: [String]) throws -> [String] {
|
||||
try localPaths.map {
|
||||
try mapPath($0, source: \.local, destination: \.virtual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,31 +95,39 @@ class JsonOverlayReader: OverlayReader {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let overlay: Overlay = try jsonDecoder.decode(Overlay.self, from: jsonContent)
|
||||
let mappings: [OverlayMapping] = try overlay.roots.reduce([]) { prev, root in
|
||||
switch root.type {
|
||||
case .directory:
|
||||
//iterate all contents
|
||||
let dir = URL(fileURLWithPath: root.name)
|
||||
let mappings: [OverlayMapping] = try root.contents.map { content in
|
||||
switch content.type {
|
||||
case .file:
|
||||
let virtual = dir.appendingPathComponent(content.name)
|
||||
let local = URL(fileURLWithPath: content.externalContents)
|
||||
return .init(virtual: virtual, local: local)
|
||||
case .directory:
|
||||
throw JsonOverlayReaderError.unsupportedFormat
|
||||
}
|
||||
let mappings: [OverlayMapping] = try overlay.roots.reduce([]) { prev, root in
|
||||
switch root.type {
|
||||
case .directory:
|
||||
//iterate all contents
|
||||
let dir = URL(fileURLWithPath: root.name)
|
||||
let mappings: [OverlayMapping] = try root.contents.map { content in
|
||||
switch content.type {
|
||||
case .file:
|
||||
let virtual = dir.appendingPathComponent(content.name)
|
||||
let local = URL(fileURLWithPath: content.externalContents)
|
||||
return .init(virtual: virtual, local: local)
|
||||
case .directory:
|
||||
throw JsonOverlayReaderError.unsupportedFormat
|
||||
}
|
||||
|
||||
}
|
||||
return prev + mappings
|
||||
case .file:
|
||||
throw JsonOverlayReaderError.unsupportedFormat
|
||||
}
|
||||
return prev + mappings
|
||||
case .file:
|
||||
throw JsonOverlayReaderError.unsupportedFormat
|
||||
}
|
||||
return mappings
|
||||
} catch {
|
||||
switch mode {
|
||||
case .strict:
|
||||
throw error
|
||||
case .bestEffort:
|
||||
printWarning("Overlay reader has failed with an error \(error). Best-effort mode - skipping an overlay.")
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
return mappings
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,52 +29,52 @@ class DependenciesRemapperCompositeTests: XCTestCase {
|
||||
StringDependenciesRemapper.Mapping(generic: "$(PWD)", local: "/pwd"),
|
||||
]
|
||||
|
||||
func testNoRemappersIsTransparent() {
|
||||
func testNoRemappersIsTransparent() throws {
|
||||
let remapper = DependenciesRemapperComposite([])
|
||||
|
||||
let genericPath = remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
let genericPath = try remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
|
||||
XCTAssertEqual(genericPath, ["/tmp/root/some.swift"])
|
||||
}
|
||||
|
||||
func testOneRemapperReplacesLocalPaths() {
|
||||
func testOneRemapperReplacesLocalPaths() throws {
|
||||
let remapper = DependenciesRemapperComposite([
|
||||
StringDependenciesRemapper(mappings: mappings1),
|
||||
])
|
||||
|
||||
let genericPath = remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
let genericPath = try remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
|
||||
XCTAssertEqual(genericPath, ["$(SRC_ROOT)/some.swift"])
|
||||
}
|
||||
|
||||
func testOneRemapperReplacesGenericPaths() {
|
||||
func testOneRemapperReplacesGenericPaths() throws {
|
||||
let remapper = DependenciesRemapperComposite([
|
||||
StringDependenciesRemapper(mappings: mappings1),
|
||||
])
|
||||
|
||||
let localPath = remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
let localPath = try remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
|
||||
XCTAssertEqual(localPath, ["/tmp/root/some.swift"])
|
||||
}
|
||||
|
||||
func testTwoRemappersReplacesLocalPaths() {
|
||||
func testTwoRemappersReplacesLocalPaths() throws {
|
||||
let remapper = DependenciesRemapperComposite([
|
||||
StringDependenciesRemapper(mappings: mappings1),
|
||||
StringDependenciesRemapper(mappings: mappings2),
|
||||
])
|
||||
|
||||
let genericPath = remapper.replace(localPaths: ["/tmp/root/some.swift", "/pwd/other.swift"])
|
||||
let genericPath = try remapper.replace(localPaths: ["/tmp/root/some.swift", "/pwd/other.swift"])
|
||||
|
||||
XCTAssertEqual(genericPath, ["$(SRC_ROOT)/some.swift", "$(PWD)/other.swift"])
|
||||
}
|
||||
|
||||
func testOneRemappersReplacesGenericPaths() {
|
||||
func testOneRemappersReplacesGenericPaths() throws {
|
||||
let remapper = DependenciesRemapperComposite([
|
||||
StringDependenciesRemapper(mappings: mappings1),
|
||||
StringDependenciesRemapper(mappings: mappings2),
|
||||
])
|
||||
|
||||
let localPath = remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift", "$(PWD)/other.swift"])
|
||||
let localPath = try remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift", "$(PWD)/other.swift"])
|
||||
|
||||
XCTAssertEqual(localPath, ["/tmp/root/some.swift", "/pwd/other.swift"])
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class DependenciesRemapperCompositeTests: XCTestCase {
|
||||
])
|
||||
let localPaths = ["/root/specific/file"]
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: localPaths)
|
||||
let genericPaths = try remapper.replace(localPaths: localPaths)
|
||||
|
||||
XCTAssertEqual(genericPaths, ["$(SPECIFIC)/file"])
|
||||
}
|
||||
@@ -98,7 +98,7 @@ class DependenciesRemapperCompositeTests: XCTestCase {
|
||||
])
|
||||
let genericPaths = ["$(SPECIFIC)/file"]
|
||||
|
||||
let localPaths = remapper.replace(genericPaths: genericPaths)
|
||||
let localPaths = try remapper.replace(genericPaths: genericPaths)
|
||||
|
||||
XCTAssertEqual(localPaths, ["/root/specific/file"])
|
||||
}
|
||||
@@ -110,8 +110,8 @@ class DependenciesRemapperCompositeTests: XCTestCase {
|
||||
])
|
||||
let localPaths = ["/root/specific/file"]
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: localPaths)
|
||||
let remappedLocalPaths = remapper.replace(genericPaths: genericPaths)
|
||||
let genericPaths = try remapper.replace(localPaths: localPaths)
|
||||
let remappedLocalPaths = try remapper.replace(genericPaths: genericPaths)
|
||||
|
||||
XCTAssertEqual(localPaths, remappedLocalPaths)
|
||||
}
|
||||
|
||||
@@ -26,40 +26,46 @@ class OverlayDependenciesRemapperTests: XCTestCase {
|
||||
)
|
||||
|
||||
func testMappingFromLocalToGeneric() throws {
|
||||
let reader = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
let remapper = OverlayDependenciesRemapper(overlayReader: overlayReader)
|
||||
|
||||
let dependencies = reader.replace(localPaths: ["/Intermediate/Some/file.h"])
|
||||
let dependencies = try remapper.replace(localPaths: ["/Intermediate/Some/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/file.h"])
|
||||
}
|
||||
|
||||
func testMappingFromGenericToLocal() throws {
|
||||
let reader = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
let remapper = OverlayDependenciesRemapper(overlayReader: overlayReader)
|
||||
|
||||
let dependencies = reader.replace(genericPaths: ["/file.h"])
|
||||
|
||||
let dependencies = try remapper.replace(genericPaths: ["/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/Intermediate/Some/file.h"])
|
||||
}
|
||||
|
||||
func testGenericDependenciesAreMerged() throws {
|
||||
func testGenericDependenciesAreNotMerged() throws {
|
||||
let remapper = OverlayDependenciesRemapper(overlayReader: overlayReader)
|
||||
|
||||
let reader = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
|
||||
let dependencies = reader.replace(localPaths: ["/Intermediate/Some/file.h", "/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/file.h"])
|
||||
let dependencies = try remapper.replace(localPaths: ["/Intermediate/Some/file.h", "/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/file.h", "/file.h"])
|
||||
}
|
||||
|
||||
func testLocalDependenciesAreMerged() throws {
|
||||
let reader = try OverlayDependenciesRemapper(
|
||||
overlayReader: overlayReader
|
||||
)
|
||||
func testLocalDependenciesAreNotMerged() throws {
|
||||
let remapper = OverlayDependenciesRemapper(overlayReader: overlayReader)
|
||||
|
||||
let dependencies = reader.replace(genericPaths: ["/Intermediate/Some/file.h", "/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/Intermediate/Some/file.h"])
|
||||
|
||||
let dependencies = try remapper.replace(genericPaths: ["/Intermediate/Some/file.h", "/file.h"])
|
||||
XCTAssertEqual(dependencies, ["/Intermediate/Some/file.h", "/Intermediate/Some/file.h"])
|
||||
}
|
||||
|
||||
func testMappingsAreReadOnce() throws {
|
||||
let remapper = OverlayDependenciesRemapper(overlayReader: overlayReader)
|
||||
|
||||
let firstDependencies = try remapper.replace(localPaths: ["/Intermediate/Some/file.h"])
|
||||
// Update mappings in-fly to verify the previous value is cached in a remapper
|
||||
overlayReader.mappings = []
|
||||
let secondDependencies = try remapper.replace(localPaths: ["/Intermediate/Some/file.h"])
|
||||
|
||||
XCTAssertEqual(firstDependencies, ["/file.h"])
|
||||
XCTAssertEqual(secondDependencies, ["/file.h"])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
@testable import XCRemoteCache
|
||||
import XCTest
|
||||
|
||||
class JsonOverlayReaderTests: XCTestCase {
|
||||
class JsonOverlayReaderTests: FileXCTestCase {
|
||||
private static let resourcesSubdirectory = "TestData/Dependencies/JsonOverlayReaderTests"
|
||||
|
||||
func testParsingWithSuccess() throws {
|
||||
@@ -59,6 +59,25 @@ class JsonOverlayReaderTests: XCTestCase {
|
||||
XCTAssertEqual(mappings, [])
|
||||
}
|
||||
|
||||
func testInvalidJsonDoesntThrowForBestEffortMode() throws {
|
||||
let workingDir = try prepareTempDir()
|
||||
let file = workingDir.appendingPathExtension("overlay.json")
|
||||
try fileManager.spt_createEmptyFile(file)
|
||||
let reader = JsonOverlayReader(file, mode: .bestEffort, fileReader: fileManager)
|
||||
let mappings = try reader.provideMappings()
|
||||
|
||||
XCTAssertEqual(mappings, [])
|
||||
}
|
||||
|
||||
func testInvalidJsonThrowsForStrictMode() throws {
|
||||
let workingDir = try prepareTempDir()
|
||||
let file = workingDir.appendingPathExtension("overlay.json")
|
||||
try fileManager.spt_createEmptyFile(file)
|
||||
let reader = JsonOverlayReader(file, mode: .strict, fileReader: fileManager)
|
||||
|
||||
XCTAssertThrowsError(try reader.provideMappings())
|
||||
}
|
||||
|
||||
private func pathForTestData(name: String) throws -> URL {
|
||||
return try XCTUnwrap(Bundle.module.url(forResource: name, withExtension: "json", subdirectory: JsonOverlayReaderTests.resourcesSubdirectory))
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class StringDependenciesRemapperFactoryTests: XCTestCase {
|
||||
customMappings: [:]
|
||||
)
|
||||
|
||||
let localPaths = remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
let localPaths = try remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
XCTAssertEqual(localPaths, ["/tmp/root/some.swift"])
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class StringDependenciesRemapperFactoryTests: XCTestCase {
|
||||
customMappings: ["TMP": "/tmp"]
|
||||
)
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: ["/some/repoFile.swift", "/tmp/externalFile.swift"])
|
||||
let genericPaths = try remapper.replace(localPaths: ["/some/repoFile.swift", "/tmp/externalFile.swift"])
|
||||
XCTAssertEqual(genericPaths, ["$(PWD)/repoFile.swift", "$(TMP)/externalFile.swift"])
|
||||
}
|
||||
|
||||
|
||||
@@ -30,34 +30,34 @@ class StringDependenciesRemapperTests: XCTestCase {
|
||||
remapper = StringDependenciesRemapper(mappings: mappings)
|
||||
}
|
||||
|
||||
func testMappingSingleGenericPathReplacesWithLocalPath() {
|
||||
let localPaths = remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
func testMappingSingleGenericPathReplacesWithLocalPath() throws {
|
||||
let localPaths = try remapper.replace(genericPaths: ["$(SRC_ROOT)/some.swift"])
|
||||
|
||||
XCTAssertEqual(localPaths, ["/tmp/root/some.swift"])
|
||||
}
|
||||
|
||||
func testRewritingSingleLocalPathReplacesWithGenericPath() {
|
||||
let genericPaths = remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
func testRewritingSingleLocalPathReplacesWithGenericPath() throws {
|
||||
let genericPaths = try remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
|
||||
XCTAssertEqual(genericPaths, ["$(SRC_ROOT)/some.swift"])
|
||||
}
|
||||
|
||||
func testRewritingLocalToGenericAndLocalIsIdentical() {
|
||||
func testRewritingLocalToGenericAndLocalIsIdentical() throws {
|
||||
let inputLocalPaths = ["/tmp/root/some.swift"]
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: inputLocalPaths)
|
||||
let localPaths = remapper.replace(genericPaths: genericPaths)
|
||||
let genericPaths = try remapper.replace(localPaths: inputLocalPaths)
|
||||
let localPaths = try remapper.replace(genericPaths: genericPaths)
|
||||
|
||||
XCTAssertEqual(localPaths, inputLocalPaths)
|
||||
}
|
||||
|
||||
func testRewritingUnrelatedDirReturnsInputPath() {
|
||||
let genericPaths = remapper.replace(localPaths: ["/other/some.swift"])
|
||||
func testRewritingUnrelatedDirReturnsInputPath() throws {
|
||||
let genericPaths = try remapper.replace(localPaths: ["/other/some.swift"])
|
||||
|
||||
XCTAssertEqual(genericPaths, ["/other/some.swift"])
|
||||
}
|
||||
|
||||
func testMultipleMatchesTakeTheFirstMapping() {
|
||||
func testMultipleMatchesTakeTheFirstMapping() throws {
|
||||
let mappings: [StringDependenciesRemapper.Mapping] = [
|
||||
.init(generic: "$(SRC_ROOT)", local: "/tmp/root"),
|
||||
.init(generic: "$(PWD)", local: "/tmp"),
|
||||
@@ -65,12 +65,12 @@ class StringDependenciesRemapperTests: XCTestCase {
|
||||
remapper = StringDependenciesRemapper(mappings: mappings)
|
||||
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: ["/tmp/root/some.swift", "/tmp/extra.swift"])
|
||||
let genericPaths = try remapper.replace(localPaths: ["/tmp/root/some.swift", "/tmp/extra.swift"])
|
||||
|
||||
XCTAssertEqual(genericPaths, ["$(SRC_ROOT)/some.swift", "$(PWD)/extra.swift"])
|
||||
}
|
||||
|
||||
func testMappingsLocalPathsIsDoneInOrder() {
|
||||
func testMappingsLocalPathsIsDoneInOrder() throws {
|
||||
let mappings: [StringDependenciesRemapper.Mapping] = [
|
||||
.init(generic: "$(TMP)", local: "/tmp"),
|
||||
.init(generic: "$(ROOT)", local: "$(TMP)/root"),
|
||||
@@ -78,12 +78,12 @@ class StringDependenciesRemapperTests: XCTestCase {
|
||||
remapper = StringDependenciesRemapper(mappings: mappings)
|
||||
|
||||
|
||||
let genericPaths = remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
let genericPaths = try remapper.replace(localPaths: ["/tmp/root/some.swift"])
|
||||
|
||||
XCTAssertEqual(genericPaths, ["$(ROOT)/some.swift"])
|
||||
}
|
||||
|
||||
func testMappingsGenericPathsIsDoneInReversedOrder() {
|
||||
func testMappingsGenericPathsIsDoneInReversedOrder() throws {
|
||||
let mappings: [StringDependenciesRemapper.Mapping] = [
|
||||
.init(generic: "$(TMP)", local: "/tmp"),
|
||||
.init(generic: "$(ROOT)", local: "$(TMP)/root"),
|
||||
@@ -91,7 +91,7 @@ class StringDependenciesRemapperTests: XCTestCase {
|
||||
remapper = StringDependenciesRemapper(mappings: mappings)
|
||||
|
||||
|
||||
let localPaths = remapper.replace(genericPaths: ["$(ROOT)/some.swift"])
|
||||
let localPaths = try remapper.replace(genericPaths: ["$(ROOT)/some.swift"])
|
||||
|
||||
XCTAssertEqual(localPaths, ["/tmp/root/some.swift"])
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import Foundation
|
||||
@testable import XCRemoteCache
|
||||
|
||||
class OverlayReaderFake: OverlayReader {
|
||||
private let mappings: [OverlayMapping]
|
||||
var mappings: [OverlayMapping]
|
||||
|
||||
init(mappings: [OverlayMapping]) {
|
||||
self.mappings = mappings
|
||||
}
|
||||
|
||||
@@ -135,7 +135,8 @@ module CocoapodsXCRemoteCacheModifier
|
||||
phase.name != nil && phase.name.start_with?("[XCRC] Prebuild")
|
||||
end
|
||||
end
|
||||
prebuild_script = existing_prebuild_script || target.new_shell_script_build_phase("[XCRC] Prebuild")
|
||||
|
||||
prebuild_script = existing_prebuild_script || target.new_shell_script_build_phase("[XCRC] Prebuild #{target.name}")
|
||||
prebuild_script.shell_script = "\"$SCRIPT_INPUT_FILE_0\""
|
||||
prebuild_script.input_paths = ["$SRCROOT/#{srcroot_relative_xc_location}/xcprebuild"]
|
||||
prebuild_script.output_paths = [
|
||||
@@ -144,8 +145,9 @@ module CocoapodsXCRemoteCacheModifier
|
||||
]
|
||||
prebuild_script.dependency_file = "$(TARGET_TEMP_DIR)/prebuild.d"
|
||||
|
||||
# Move prebuild (last element) to the first position (to make it real 'prebuild')
|
||||
target.build_phases.rotate!(-1) if existing_prebuild_script.nil?
|
||||
# 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))
|
||||
elsif mode == 'producer' || mode == 'producer-fast'
|
||||
# Delete existing prebuild build phase (to support switching between modes)
|
||||
target.build_phases.delete_if do |phase|
|
||||
@@ -161,7 +163,7 @@ module CocoapodsXCRemoteCacheModifier
|
||||
phase.name != nil && phase.name.start_with?("[XCRC] Postbuild")
|
||||
end
|
||||
end
|
||||
postbuild_script = existing_postbuild_script || target.new_shell_script_build_phase("[XCRC] Postbuild")
|
||||
postbuild_script = existing_postbuild_script || target.new_shell_script_build_phase("[XCRC] Postbuild #{target.name}")
|
||||
postbuild_script.shell_script = "\"$SCRIPT_INPUT_FILE_0\""
|
||||
postbuild_script.input_paths = ["$SRCROOT/#{srcroot_relative_xc_location}/xcpostbuild"]
|
||||
postbuild_script.output_paths = [
|
||||
|
||||
Reference in New Issue
Block a user