Compare commits

..

9 Commits

Author SHA1 Message Date
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
15 changed files with 127 additions and 27 deletions
+1 -1
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 | `[]` | ⬜️ |
@@ -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")
@@ -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
@@ -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 {
@@ -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 {
@@ -316,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()
@@ -348,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)
}
@@ -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")
}
}
@@ -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|
@@ -13,5 +13,5 @@
# limitations under the License.
module CocoapodsXcremotecache
VERSION = "0.0.8"
VERSION = "0.0.9"
end