Skip to content

Commit 50fc7f2

Browse files
authored
enhance configuraiton for dependencies mirrors (#3670)
motivation: support both local and global configuraiton, as per SE-0292 changes: * reafactor and separate out the mirrors data model from the loading/saving mutation utility * use Codable for serialization * add new utility to manage local and shared mirrors configuraiton files * add new CLI flag to set custom shared configuration path * adjust call sites * add tests
1 parent 66153c2 commit 50fc7f2

15 files changed

+637
-214
lines changed
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public func foo() {
2+
{}()
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// swift-tools-version:5.2
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "Foo",
6+
products: [
7+
.library(name: "Foo", targets: ["Foo"]),
8+
],
9+
targets: [
10+
.target(name: "Foo", path: "./"),
11+
]
12+
)

Sources/Basics/FileSystem+Extensions.swift

+14-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11-
import TSCBasic
1211
import class Foundation.FileManager
12+
import struct Foundation.Data
13+
import TSCBasic
1314

1415
// MARK: - user level
1516

@@ -110,3 +111,15 @@ extension FileSystem {
110111
return idiomaticConfigDirectory
111112
}
112113
}
114+
115+
// MARK: - Utilities
116+
117+
extension FileSystem {
118+
public func readFileContents(_ path: AbsolutePath) throws -> Data {
119+
return try Data(self.readFileContents(path).contents)
120+
}
121+
122+
public func writeFileContents(_ path: AbsolutePath, data: Data) throws {
123+
return try self.writeFileContents(path, bytes: ByteString(data))
124+
}
125+
}

Sources/Commands/Options.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,7 @@ public struct SwiftToolOptions: ParsableArguments {
139139
@Option(help: "Specify the shared cache directory")
140140
var cachePath: AbsolutePath?
141141

142-
// TODO: add actual help when ready to be used
143-
@Option(help: .hidden)
142+
@Option(help: "Specify the shared configuration directory")
144143
var configPath: AbsolutePath?
145144

146145
/// Disables repository caching.

Sources/Commands/SwiftPackageTool.swift

+7-5
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ extension SwiftPackageTool {
685685

686686
case .set(let value):
687687
guard let toolsVersion = ToolsVersion(string: value) else {
688-
// FIXME: Probably lift this error defination to ToolsVersion.
688+
// FIXME: Probably lift this error definition to ToolsVersion.
689689
throw ToolsVersionLoader.Error.malformedToolsVersionSpecification(.versionSpecifier(.isMisspelt(value)))
690690
}
691691
try rewriteToolsVersionSpecification(toDefaultManifestIn: pkg, specifying: toolsVersion, fileSystem: localFileSystem)
@@ -895,8 +895,9 @@ extension SwiftPackageTool.Config {
895895
throw ExitCode.failure
896896
}
897897

898-
config.mirrors.set(mirrorURL: mirrorURL, forURL: originalURL)
899-
try config.saveState()
898+
try config.applyLocal { mirrors in
899+
mirrors.set(mirrorURL: mirrorURL, forURL: originalURL)
900+
}
900901
}
901902
}
902903

@@ -929,8 +930,9 @@ extension SwiftPackageTool.Config {
929930
throw ExitCode.failure
930931
}
931932

932-
try config.mirrors.unset(originalOrMirrorURL: originalOrMirrorURL)
933-
try config.saveState()
933+
try config.applyLocal { mirrors in
934+
try mirrors.unset(originalOrMirrorURL: originalOrMirrorURL)
935+
}
934936
}
935937
}
936938

Sources/Commands/SwiftTool.swift

+63-40
Original file line numberDiff line numberDiff line change
@@ -452,42 +452,63 @@ public class SwiftTool {
452452
}
453453
}
454454

455-
func editablesPath() throws -> AbsolutePath {
455+
private func editsDirectory() throws -> AbsolutePath {
456+
// TODO: replace multiroot-data-file with explicit overrides
456457
if let multiRootPackageDataFile = options.multirootPackageDataFile {
457458
return multiRootPackageDataFile.appending(component: "Packages")
458459
}
459-
return try getPackageRoot().appending(component: "Packages")
460+
return try Workspace.DefaultLocations.editsDirectory(forRootPackage: self.getPackageRoot())
460461
}
461462

462-
func resolvedVersionsFilePath() throws -> AbsolutePath {
463+
private func resolvedVersionsFile() throws -> AbsolutePath {
464+
// TODO: replace multiroot-data-file with explicit overrides
463465
if let multiRootPackageDataFile = options.multirootPackageDataFile {
464466
return multiRootPackageDataFile.appending(components: "xcshareddata", "swiftpm", "Package.resolved")
465467
}
466-
return try getPackageRoot().appending(component: "Package.resolved")
468+
return try Workspace.DefaultLocations.resolvedVersionsFile(forRootPackage: self.getPackageRoot())
467469
}
468470

469-
func mirrorsConfigFilePath() throws -> AbsolutePath {
471+
func getMirrorsConfig(sharedConfigurationDirectory: AbsolutePath? = nil) throws -> Workspace.Configuration.Mirrors {
472+
let sharedConfigurationDirectory = try sharedConfigurationDirectory ?? self.getSharedConfigurationDirectory()
473+
let sharedMirrorFile = sharedConfigurationDirectory.map { Workspace.DefaultLocations.mirrorsConfigurationFile(at: $0) }
474+
return try .init(
475+
localMirrorFile: self.mirrorsConfigFile(),
476+
sharedMirrorFile: sharedMirrorFile,
477+
fileSystem: localFileSystem
478+
)
479+
}
480+
481+
private func mirrorsConfigFile() throws -> AbsolutePath {
482+
// TODO: does this make sense now that we a global configuration as well? or should we at least rename it?
470483
// Look for the override in the environment.
471484
if let envPath = ProcessEnv.vars["SWIFTPM_MIRROR_CONFIG"] {
472485
return try AbsolutePath(validating: envPath)
473486
}
474487

475488
// Otherwise, use the default path.
489+
// TODO: replace multiroot-data-file with explicit overrides
476490
if let multiRootPackageDataFile = options.multirootPackageDataFile {
477-
return multiRootPackageDataFile.appending(components: "xcshareddata", "swiftpm", "config")
491+
// migrate from legacy location
492+
let legacyPath = multiRootPackageDataFile.appending(components: "xcshareddata", "swiftpm", "config")
493+
let newPath = multiRootPackageDataFile.appending(components: "xcshareddata", "swiftpm", "configuration", "mirrors.json")
494+
if localFileSystem.exists(legacyPath) {
495+
try localFileSystem.createDirectory(newPath.parentDirectory, recursive: true)
496+
try localFileSystem.move(from: legacyPath, to: newPath)
497+
}
498+
return newPath
478499
}
479-
return try getPackageRoot().appending(components: ".swiftpm", "config")
480-
}
481500

482-
func getMirrorsConfig() throws -> Workspace.Configuration {
483-
return try _mirrorsConfig.get()
501+
// migrate from legacy location
502+
let legacyPath = try self.getPackageRoot().appending(components: ".swiftpm", "config")
503+
let newPath = try Workspace.DefaultLocations.mirrorsConfigurationFile(forRootPackage: self.getPackageRoot())
504+
if localFileSystem.exists(legacyPath) {
505+
try localFileSystem.createDirectory(newPath.parentDirectory, recursive: true)
506+
try localFileSystem.move(from: legacyPath, to: newPath)
507+
}
508+
return newPath
484509
}
485510

486-
private lazy var _mirrorsConfig: Result<Workspace.Configuration, Swift.Error> = {
487-
return Result(catching: { try Workspace.Configuration(path: try mirrorsConfigFilePath(), fileSystem: localFileSystem) })
488-
}()
489-
490-
func netrcFilePath() throws -> AbsolutePath? {
511+
private func netrcFilePath() throws -> AbsolutePath? {
491512
guard options.netrc ||
492513
options.netrcFilePath != nil ||
493514
options.netrcOptional else { return nil }
@@ -499,43 +520,43 @@ public class SwiftTool {
499520
throw ExitCode.failure
500521
} else {
501522
diagnostics.emit(warning: "Did not find optional .netrc file at \(resolvedPath.pathString).")
502-
return nil
523+
return .none
503524
}
504525
}
505526
return resolvedPath
506527
}
507528

508-
private func getCachePath(fileSystem: FileSystem = localFileSystem) throws -> AbsolutePath? {
529+
private func getSharedCacheDirectory() throws -> AbsolutePath? {
509530
if let explicitCachePath = options.cachePath {
510531
// Create the explicit cache path if necessary
511-
if !fileSystem.exists(explicitCachePath) {
512-
try fileSystem.createDirectory(explicitCachePath, recursive: true)
532+
if !localFileSystem.exists(explicitCachePath) {
533+
try localFileSystem.createDirectory(explicitCachePath, recursive: true)
513534
}
514535
return explicitCachePath
515536
}
516537

517538
do {
518-
return try fileSystem.getOrCreateSwiftPMCacheDirectory()
539+
return try localFileSystem.getOrCreateSwiftPMCacheDirectory()
519540
} catch {
520-
self.diagnostics.emit(warning: "Failed creating default cache locations, \(error)")
521-
return nil
541+
self.diagnostics.emit(warning: "Failed creating default cache location, \(error)")
542+
return .none
522543
}
523544
}
524545

525-
private func getConfigPath(fileSystem: FileSystem = localFileSystem) throws -> AbsolutePath? {
546+
private func getSharedConfigurationDirectory() throws -> AbsolutePath? {
526547
if let explicitConfigPath = options.configPath {
527548
// Create the explicit config path if necessary
528-
if !fileSystem.exists(explicitConfigPath) {
529-
try fileSystem.createDirectory(explicitConfigPath, recursive: true)
549+
if !localFileSystem.exists(explicitConfigPath) {
550+
try localFileSystem.createDirectory(explicitConfigPath, recursive: true)
530551
}
531552
return explicitConfigPath
532553
}
533554

534555
do {
535-
return try fileSystem.getOrCreateSwiftPMConfigDirectory()
556+
return try localFileSystem.getOrCreateSwiftPMConfigDirectory()
536557
} catch {
537-
self.diagnostics.emit(warning: "Failed creating default config locations, \(error)")
538-
return nil
558+
self.diagnostics.emit(warning: "Failed creating default configuration location, \(error)")
559+
return .none
539560
}
540561
}
541562

@@ -548,25 +569,27 @@ public class SwiftTool {
548569
let isVerbose = options.verbosity != 0
549570
let delegate = ToolWorkspaceDelegate(self.stdoutStream, isVerbose: isVerbose, diagnostics: diagnostics)
550571
let provider = GitRepositoryProvider(processSet: processSet)
551-
let cachePath = self.options.useRepositoriesCache ? try self.getCachePath() : .none
552-
_ = try self.getConfigPath() // TODO: actually use this in the workspace
572+
let sharedCacheDirectory = try self.getSharedCacheDirectory()
573+
let sharedConfigurationDirectory = try self.getSharedConfigurationDirectory()
553574
let isXcodeBuildSystemEnabled = self.options.buildSystem == .xcode
554575
let workspace = try Workspace(
555576
fileSystem: localFileSystem,
556577
location: .init(
557578
workingDirectory: buildPath,
558-
editsDirectory: try editablesPath(),
559-
resolvedVersionsFilePath: try resolvedVersionsFilePath(),
560-
sharedCacheDirectory: cachePath
579+
editsDirectory: self.editsDirectory(),
580+
resolvedVersionsFile: self.resolvedVersionsFile(),
581+
sharedCacheDirectory: sharedCacheDirectory,
582+
sharedConfigurationDirectory: sharedConfigurationDirectory
561583
),
562-
netrcFilePath: try netrcFilePath(),
563-
mirrors: self.getMirrorsConfig().mirrors,
564-
customManifestLoader: try getManifestLoader(), // FIXME: doe we really need to customize it?
584+
mirrors: self.getMirrorsConfig(sharedConfigurationDirectory: sharedConfigurationDirectory).mirrors,
585+
netrcFilePath: self.netrcFilePath(),
586+
customManifestLoader: self.getManifestLoader(), // FIXME: doe we really need to customize it?
565587
customRepositoryProvider: provider, // FIXME: doe we really need to customize it?
566588
additionalFileRules: isXcodeBuildSystemEnabled ? FileRuleDescription.xcbuildFileTypes : FileRuleDescription.swiftpmFileTypes,
567589
resolverUpdateEnabled: !options.skipDependencyUpdate,
568590
resolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
569591
resolverTracingEnabled: options.enableResolverTrace,
592+
sharedRepositoriesCacheEnabled: self.options.useRepositoriesCache,
570593
delegate: delegate
571594
)
572595
_workspace = workspace
@@ -858,16 +881,16 @@ public class SwiftTool {
858881
switch (self.options.shouldDisableManifestCaching, self.options.manifestCachingMode) {
859882
case (true, _):
860883
// backwards compatibility
861-
cachePath = nil
884+
cachePath = .none
862885
case (false, .none):
863-
cachePath = nil
886+
cachePath = .none
864887
case (false, .local):
865888
cachePath = self.buildPath
866889
case (false, .shared):
867-
cachePath = try self.getCachePath().map{ $0.appending(component: "manifests") }
890+
cachePath = try self.getSharedCacheDirectory().map{ Workspace.DefaultLocations.manifestsDirectory(at: $0) }
868891
}
869892

870-
var extraManifestFlags = self.options.manifestFlags
893+
var extraManifestFlags = self.options.manifestFlags
871894
// Disable the implicit concurrency import if the compiler in use supports it to avoid warnings if we are building against an older SDK that does not contain a Concurrency module.
872895
if SwiftTargetBuildDescription.checkSupportedFrontendFlags(flags: ["disable-implicit-concurrency-module-import"], fs: localFileSystem) {
873896
extraManifestFlags += ["-Xfrontend", "-disable-implicit-concurrency-module-import"]

0 commit comments

Comments
 (0)