Skip to content

Commit 9d7278c

Browse files
committed
Implement SE-0219 Package Manager Dependency Mirroring
<rdar://problem/42511642> [SR-8328]: Implement SE-0219 Package Manager Dependency Mirroring https://bugs.swift.org/browse/SR-8328
1 parent a20c530 commit 9d7278c

File tree

14 files changed

+498
-27
lines changed

14 files changed

+498
-27
lines changed

Sources/Commands/SwiftPackageTool.swift

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,30 @@ struct FetchDeprecatedDiagnostic: DiagnosticData {
3030
)
3131
}
3232

33+
struct RequiredArgumentDiagnostic: DiagnosticData {
34+
static let id = DiagnosticID(
35+
type: RequiredArgumentDiagnostic.self,
36+
name: "org.swift.diags.required-argument",
37+
defaultBehavior: .error,
38+
description: {
39+
$0 <<< "missing required argument" <<< { "\($0.argument)" }
40+
}
41+
)
42+
43+
let argument: String
44+
}
45+
46+
struct RequiredSubcommandDiagnostic: DiagnosticData {
47+
static let id = DiagnosticID(
48+
type: RequiredSubcommandDiagnostic.self,
49+
name: "org.swift.diags.required-subcommand",
50+
defaultBehavior: .error,
51+
description: {
52+
$0 <<< "missing required subcommand; use --help to list available subcommands"
53+
}
54+
)
55+
}
56+
3357
/// swift-package tool namespace
3458
public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
3559

@@ -48,6 +72,51 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
4872
case .version:
4973
print(Versioning.currentVersion.completeDisplayString)
5074

75+
case .config:
76+
guard let configMode = options.configMode else {
77+
diagnostics.emit(data: RequiredSubcommandDiagnostic())
78+
return
79+
}
80+
81+
let config = try getSwiftPMConfig()
82+
try config.load()
83+
84+
switch configMode {
85+
case .getMirror:
86+
guard let packageURL = options.configOptions.packageURL else {
87+
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url"))
88+
return
89+
}
90+
91+
if let mirror = config.getMirror(forURL: packageURL) {
92+
print(mirror)
93+
} else {
94+
stderrStream <<< "not found\n"
95+
stderrStream.flush()
96+
executionStatus = .failure
97+
}
98+
99+
case .unsetMirror:
100+
guard let packageOrMirror = options.configOptions.packageURL ?? options.configOptions.mirrorURL else {
101+
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url or --mirror-url"))
102+
return
103+
}
104+
105+
try config.unset(packageOrMirrorURL: packageOrMirror)
106+
107+
case .setMirror:
108+
guard let packageURL = options.configOptions.packageURL else {
109+
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url"))
110+
return
111+
}
112+
guard let mirrorURL = options.configOptions.mirrorURL else {
113+
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--mirror-url"))
114+
return
115+
}
116+
117+
try config.set(mirrorURL: mirrorURL, forPackageURL: packageURL)
118+
}
119+
51120
case .initPackage:
52121
// FIXME: Error handling.
53122
let cwd = localFileSystem.currentWorkingDirectory!
@@ -347,6 +416,58 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
347416
usage: "Set tools version of package to the current tools version in use"),
348417
to: { if $1 { $0.toolsVersionMode = .setCurrent } })
349418

419+
// SwiftPM config subcommand.
420+
let configParser = parser.add(
421+
subparser: PackageMode.config.rawValue,
422+
overview: "Manipulate configuration of the package")
423+
binder.bind(parser: configParser,
424+
to: { $0.configMode = PackageToolOptions.ConfigMode(rawValue: $1)! })
425+
426+
let setMirrorParser = configParser.add(
427+
subparser: PackageToolOptions.ConfigMode.setMirror.rawValue,
428+
overview: "Set a mirror for a dependency")
429+
430+
binder.bind(
431+
setMirrorParser.add(
432+
option: "--package-url", kind: String.self,
433+
usage: "The package dependency url"),
434+
setMirrorParser.add(
435+
option: "--mirror-url", kind: String.self,
436+
usage: "The mirror url"),
437+
to: {
438+
$0.configOptions.packageURL = $1
439+
$0.configOptions.mirrorURL = $2
440+
}
441+
)
442+
443+
let unsetMirrorParser = configParser.add(
444+
subparser: PackageToolOptions.ConfigMode.unsetMirror.rawValue,
445+
overview: "Remove an existing mirror")
446+
binder.bind(
447+
unsetMirrorParser.add(
448+
option: "--package-url", kind: String.self,
449+
usage: "The package dependency url"),
450+
unsetMirrorParser.add(
451+
option: "--mirror-url", kind: String.self,
452+
usage: "The mirror url"),
453+
to: {
454+
$0.configOptions.packageURL = $1
455+
$0.configOptions.mirrorURL = $2
456+
}
457+
)
458+
459+
let getMirrorParser = configParser.add(
460+
subparser: PackageToolOptions.ConfigMode.getMirror.rawValue,
461+
overview: "Print mirror configuration for the given package dependency")
462+
binder.bind(
463+
option: getMirrorParser.add(
464+
option: "--package-url", kind: String.self, usage: "The package dependency url"),
465+
to: {
466+
$0.configOptions.packageURL = $1
467+
}
468+
)
469+
470+
// Xcode project generation.
350471
let generateXcodeParser = parser.add(
351472
subparser: PackageMode.generateXcodeproj.rawValue,
352473
overview: "Generates an Xcode project")
@@ -482,10 +603,24 @@ public class PackageToolOptions: ToolOptions {
482603
case setCurrent
483604
}
484605
var toolsVersionMode: ToolsVersionMode = .display
606+
607+
enum ConfigMode: String {
608+
case setMirror = "set-mirror"
609+
case unsetMirror = "unset-mirror"
610+
case getMirror = "get-mirror"
611+
}
612+
var configMode: ConfigMode?
613+
614+
struct ConfigOptions {
615+
var packageURL: String?
616+
var mirrorURL: String?
617+
}
618+
var configOptions = ConfigOptions()
485619
}
486620

487621
public enum PackageMode: String, StringEnumArgument {
488622
case clean
623+
case config
489624
case describe
490625
case dumpPackage = "dump-package"
491626
case edit
@@ -548,6 +683,12 @@ extension PackageToolOptions.CompletionToolMode: StringEnumArgument {
548683
}
549684
}
550685

686+
extension PackageToolOptions.ConfigMode: StringEnumArgument {
687+
static var completion: ShellCompletion {
688+
return .none
689+
}
690+
}
691+
551692
extension SwiftPackageTool: ToolName {
552693
static var toolName: String {
553694
return "swift package"

Sources/Commands/SwiftTestTool.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ struct NoMatchingTestsWarning: DiagnosticData {
5454
)
5555
}
5656

57-
/// Diagnostic error when a command is run without its requeried command.
58-
struct RequiredArgumentDiagnostic: DiagnosticData {
57+
/// Diagnostic error when a command is run without its dependent command.
58+
struct DependentArgumentDiagnostic: DiagnosticData {
5959
static let id = DiagnosticID(
60-
type: RequiredArgumentDiagnostic.self,
61-
name: "org.swift.diags.required-argument",
60+
type: DependentArgumentDiagnostic.self,
61+
name: "org.swift.diags.dependent-argument",
6262
defaultBehavior: .error,
6363
description: {
6464
$0 <<< { "\($0.dependentArgument)" } <<< "must be used with" <<< { "\($0.requiredArgument)" }
@@ -423,7 +423,7 @@ public class SwiftTestTool: SwiftTool<TestToolOptions> {
423423
// The --num-worker option should be called with --parallel.
424424
guard options.mode == .runParallel else {
425425
diagnostics.emit(
426-
data: RequiredArgumentDiagnostic(requiredArgument: "--parallel", dependentArgument: "--num-workers"))
426+
data: DependentArgumentDiagnostic(requiredArgument: "--parallel", dependentArgument: "--num-workers"))
427427
throw Diagnostics.fatalError
428428
}
429429

Sources/Commands/SwiftTool.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,17 @@ public class SwiftTool<Options: ToolOptions> {
417417
return try getPackageRoot().appending(component: "Package.resolved")
418418
}
419419

420+
func configFilePath() throws -> AbsolutePath {
421+
return try getPackageRoot().appending(components: ".swiftpm", "config")
422+
}
423+
424+
func getSwiftPMConfig() throws -> SwiftPMConfig {
425+
return try _swiftpmConfig.dematerialize()
426+
}
427+
private lazy var _swiftpmConfig: Result<SwiftPMConfig, AnyError> = {
428+
return Result(anyError: { SwiftPMConfig(path: try configFilePath()) })
429+
}()
430+
420431
/// Holds the currently active workspace.
421432
///
422433
/// It is not initialized in init() because for some of the commands like package init , usage etc,
@@ -439,6 +450,7 @@ public class SwiftTool<Options: ToolOptions> {
439450
manifestLoader: try getManifestLoader(),
440451
toolsVersionLoader: ToolsVersionLoader(),
441452
delegate: delegate,
453+
config: try getSwiftPMConfig(),
442454
repositoryProvider: provider,
443455
isResolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
444456
skipUpdate: options.skipDependencyUpdate

Sources/PackageGraph/PackageGraphLoader.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
import Basic
12+
import SourceControl
1213
import PackageLoading
1314
import PackageModel
1415
import Utility
@@ -73,6 +74,7 @@ public struct PackageGraphLoader {
7374
/// Load the package graph for the given package path.
7475
public func load(
7576
root: PackageGraphRoot,
77+
config: SwiftPMConfig = SwiftPMConfig(),
7678
externalManifests: [Manifest],
7779
diagnostics: DiagnosticsEngine,
7880
fileSystem: FileSystem = localFileSystem,
@@ -90,8 +92,9 @@ public struct PackageGraphLoader {
9092
externalManifests.map({ (PackageReference.computeIdentity(packageURL: $0.url), $0) })
9193
let manifestMap = Dictionary(uniqueKeysWithValues: manifestMapSequence)
9294
let successors: (Manifest) -> [Manifest] = { manifest in
93-
manifest.dependencies.compactMap({
94-
manifestMap[PackageReference.computeIdentity(packageURL: $0.url)]
95+
manifest.dependencies.compactMap({
96+
let url = config.mirroredURL(forURL: $0.url)
97+
return manifestMap[PackageReference.computeIdentity(packageURL: url)]
9598
})
9699
}
97100

@@ -150,6 +153,7 @@ public struct PackageGraphLoader {
150153
// Resolve dependencies and create resolved packages.
151154
let resolvedPackages = createResolvedPackages(
152155
allManifests: allManifests,
156+
config: config,
153157
manifestToPackage: manifestToPackage,
154158
rootManifestSet: rootManifestSet,
155159
diagnostics: diagnostics
@@ -205,6 +209,7 @@ private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], _ di
205209
/// Create resolved packages from the loaded packages.
206210
private func createResolvedPackages(
207211
allManifests: [Manifest],
212+
config: SwiftPMConfig,
208213
manifestToPackage: [Manifest: Package],
209214
// FIXME: This shouldn't be needed once <rdar://problem/33693433> is fixed.
210215
rootManifestSet: Set<Manifest>,
@@ -232,7 +237,8 @@ private func createResolvedPackages(
232237

233238
// Establish the manifest-declared package dependencies.
234239
packageBuilder.dependencies = package.manifest.dependencies.compactMap({
235-
packageMap[PackageReference.computeIdentity(packageURL: $0.url)]
240+
let url = config.mirroredURL(forURL: $0.url)
241+
return packageMap[PackageReference.computeIdentity(packageURL: url)]
236242
})
237243

238244
// Create target builders for each target in the package.

Sources/PackageGraph/RawPackageConstraints.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
*/
1010

1111
import PackageModel
12+
import SourceControl
1213

1314
extension PackageDependencyDescription {
1415
/// Create the package reference object for the dependency.
15-
public func createPackageRef() -> PackageReference {
16+
public func createPackageRef(config: SwiftPMConfig) -> PackageReference {
17+
let effectiveURL = config.mirroredURL(forURL: self.url)
1618
return PackageReference(
17-
identity: PackageReference.computeIdentity(packageURL: url),
18-
path: url,
19+
identity: PackageReference.computeIdentity(packageURL: effectiveURL),
20+
path: effectiveURL,
1921
isLocal: (requirement == .localPackage)
2022
)
2123
}
@@ -24,10 +26,10 @@ extension PackageDependencyDescription {
2426
extension Manifest {
2527

2628
/// Constructs constraints of the dependencies in the raw package.
27-
public func dependencyConstraints() -> [RepositoryPackageConstraint] {
29+
public func dependencyConstraints(config: SwiftPMConfig) -> [RepositoryPackageConstraint] {
2830
return dependencies.map({
2931
return RepositoryPackageConstraint(
30-
container: $0.createPackageRef(),
32+
container: $0.createPackageRef(config: config),
3133
requirement: $0.requirement.toConstraintRequirement())
3234
})
3335
}

0 commit comments

Comments
 (0)