Skip to content

Commit

Permalink
Implement SE-0219 Package Manager Dependency Mirroring
Browse files Browse the repository at this point in the history
<rdar://problem/42511642> [SR-8328]: Implement SE-0219 Package Manager Dependency Mirroring
https://bugs.swift.org/browse/SR-8328
  • Loading branch information
aciidgh committed Oct 5, 2018
1 parent a20c530 commit 9d7278c
Show file tree
Hide file tree
Showing 14 changed files with 498 additions and 27 deletions.
141 changes: 141 additions & 0 deletions Sources/Commands/SwiftPackageTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ struct FetchDeprecatedDiagnostic: DiagnosticData {
)
}

struct RequiredArgumentDiagnostic: DiagnosticData {
static let id = DiagnosticID(
type: RequiredArgumentDiagnostic.self,
name: "org.swift.diags.required-argument",
defaultBehavior: .error,
description: {
$0 <<< "missing required argument" <<< { "\($0.argument)" }
}
)

let argument: String
}

struct RequiredSubcommandDiagnostic: DiagnosticData {
static let id = DiagnosticID(
type: RequiredSubcommandDiagnostic.self,
name: "org.swift.diags.required-subcommand",
defaultBehavior: .error,
description: {
$0 <<< "missing required subcommand; use --help to list available subcommands"
}
)
}

/// swift-package tool namespace
public class SwiftPackageTool: SwiftTool<PackageToolOptions> {

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

case .config:
guard let configMode = options.configMode else {
diagnostics.emit(data: RequiredSubcommandDiagnostic())
return
}

let config = try getSwiftPMConfig()
try config.load()

switch configMode {
case .getMirror:
guard let packageURL = options.configOptions.packageURL else {
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url"))
return
}

if let mirror = config.getMirror(forURL: packageURL) {
print(mirror)
} else {
stderrStream <<< "not found\n"
stderrStream.flush()
executionStatus = .failure
}

case .unsetMirror:
guard let packageOrMirror = options.configOptions.packageURL ?? options.configOptions.mirrorURL else {
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url or --mirror-url"))
return
}

try config.unset(packageOrMirrorURL: packageOrMirror)

case .setMirror:
guard let packageURL = options.configOptions.packageURL else {
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--package-url"))
return
}
guard let mirrorURL = options.configOptions.mirrorURL else {
diagnostics.emit(data: RequiredArgumentDiagnostic(argument: "--mirror-url"))
return
}

try config.set(mirrorURL: mirrorURL, forPackageURL: packageURL)
}

case .initPackage:
// FIXME: Error handling.
let cwd = localFileSystem.currentWorkingDirectory!
Expand Down Expand Up @@ -347,6 +416,58 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
usage: "Set tools version of package to the current tools version in use"),
to: { if $1 { $0.toolsVersionMode = .setCurrent } })

// SwiftPM config subcommand.
let configParser = parser.add(
subparser: PackageMode.config.rawValue,
overview: "Manipulate configuration of the package")
binder.bind(parser: configParser,
to: { $0.configMode = PackageToolOptions.ConfigMode(rawValue: $1)! })

let setMirrorParser = configParser.add(
subparser: PackageToolOptions.ConfigMode.setMirror.rawValue,
overview: "Set a mirror for a dependency")

binder.bind(
setMirrorParser.add(
option: "--package-url", kind: String.self,
usage: "The package dependency url"),
setMirrorParser.add(
option: "--mirror-url", kind: String.self,
usage: "The mirror url"),
to: {
$0.configOptions.packageURL = $1
$0.configOptions.mirrorURL = $2
}
)

let unsetMirrorParser = configParser.add(
subparser: PackageToolOptions.ConfigMode.unsetMirror.rawValue,
overview: "Remove an existing mirror")
binder.bind(
unsetMirrorParser.add(
option: "--package-url", kind: String.self,
usage: "The package dependency url"),
unsetMirrorParser.add(
option: "--mirror-url", kind: String.self,
usage: "The mirror url"),
to: {
$0.configOptions.packageURL = $1
$0.configOptions.mirrorURL = $2
}
)

let getMirrorParser = configParser.add(
subparser: PackageToolOptions.ConfigMode.getMirror.rawValue,
overview: "Print mirror configuration for the given package dependency")
binder.bind(
option: getMirrorParser.add(
option: "--package-url", kind: String.self, usage: "The package dependency url"),
to: {
$0.configOptions.packageURL = $1
}
)

// Xcode project generation.
let generateXcodeParser = parser.add(
subparser: PackageMode.generateXcodeproj.rawValue,
overview: "Generates an Xcode project")
Expand Down Expand Up @@ -482,10 +603,24 @@ public class PackageToolOptions: ToolOptions {
case setCurrent
}
var toolsVersionMode: ToolsVersionMode = .display

enum ConfigMode: String {
case setMirror = "set-mirror"
case unsetMirror = "unset-mirror"
case getMirror = "get-mirror"
}
var configMode: ConfigMode?

struct ConfigOptions {
var packageURL: String?
var mirrorURL: String?
}
var configOptions = ConfigOptions()
}

public enum PackageMode: String, StringEnumArgument {
case clean
case config
case describe
case dumpPackage = "dump-package"
case edit
Expand Down Expand Up @@ -548,6 +683,12 @@ extension PackageToolOptions.CompletionToolMode: StringEnumArgument {
}
}

extension PackageToolOptions.ConfigMode: StringEnumArgument {
static var completion: ShellCompletion {
return .none
}
}

extension SwiftPackageTool: ToolName {
static var toolName: String {
return "swift package"
Expand Down
10 changes: 5 additions & 5 deletions Sources/Commands/SwiftTestTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ struct NoMatchingTestsWarning: DiagnosticData {
)
}

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

Expand Down
12 changes: 12 additions & 0 deletions Sources/Commands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,17 @@ public class SwiftTool<Options: ToolOptions> {
return try getPackageRoot().appending(component: "Package.resolved")
}

func configFilePath() throws -> AbsolutePath {
return try getPackageRoot().appending(components: ".swiftpm", "config")
}

func getSwiftPMConfig() throws -> SwiftPMConfig {
return try _swiftpmConfig.dematerialize()
}
private lazy var _swiftpmConfig: Result<SwiftPMConfig, AnyError> = {
return Result(anyError: { SwiftPMConfig(path: try configFilePath()) })
}()

/// Holds the currently active workspace.
///
/// It is not initialized in init() because for some of the commands like package init , usage etc,
Expand All @@ -439,6 +450,7 @@ public class SwiftTool<Options: ToolOptions> {
manifestLoader: try getManifestLoader(),
toolsVersionLoader: ToolsVersionLoader(),
delegate: delegate,
config: try getSwiftPMConfig(),
repositoryProvider: provider,
isResolverPrefetchingEnabled: options.shouldEnableResolverPrefetching,
skipUpdate: options.skipDependencyUpdate
Expand Down
12 changes: 9 additions & 3 deletions Sources/PackageGraph/PackageGraphLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import Basic
import SourceControl
import PackageLoading
import PackageModel
import Utility
Expand Down Expand Up @@ -73,6 +74,7 @@ public struct PackageGraphLoader {
/// Load the package graph for the given package path.
public func load(
root: PackageGraphRoot,
config: SwiftPMConfig = SwiftPMConfig(),
externalManifests: [Manifest],
diagnostics: DiagnosticsEngine,
fileSystem: FileSystem = localFileSystem,
Expand All @@ -90,8 +92,9 @@ public struct PackageGraphLoader {
externalManifests.map({ (PackageReference.computeIdentity(packageURL: $0.url), $0) })
let manifestMap = Dictionary(uniqueKeysWithValues: manifestMapSequence)
let successors: (Manifest) -> [Manifest] = { manifest in
manifest.dependencies.compactMap({
manifestMap[PackageReference.computeIdentity(packageURL: $0.url)]
manifest.dependencies.compactMap({
let url = config.mirroredURL(forURL: $0.url)
return manifestMap[PackageReference.computeIdentity(packageURL: url)]
})
}

Expand Down Expand Up @@ -150,6 +153,7 @@ public struct PackageGraphLoader {
// Resolve dependencies and create resolved packages.
let resolvedPackages = createResolvedPackages(
allManifests: allManifests,
config: config,
manifestToPackage: manifestToPackage,
rootManifestSet: rootManifestSet,
diagnostics: diagnostics
Expand Down Expand Up @@ -205,6 +209,7 @@ private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], _ di
/// Create resolved packages from the loaded packages.
private func createResolvedPackages(
allManifests: [Manifest],
config: SwiftPMConfig,
manifestToPackage: [Manifest: Package],
// FIXME: This shouldn't be needed once <rdar://problem/33693433> is fixed.
rootManifestSet: Set<Manifest>,
Expand Down Expand Up @@ -232,7 +237,8 @@ private func createResolvedPackages(

// Establish the manifest-declared package dependencies.
packageBuilder.dependencies = package.manifest.dependencies.compactMap({
packageMap[PackageReference.computeIdentity(packageURL: $0.url)]
let url = config.mirroredURL(forURL: $0.url)
return packageMap[PackageReference.computeIdentity(packageURL: url)]
})

// Create target builders for each target in the package.
Expand Down
12 changes: 7 additions & 5 deletions Sources/PackageGraph/RawPackageConstraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
*/

import PackageModel
import SourceControl

extension PackageDependencyDescription {
/// Create the package reference object for the dependency.
public func createPackageRef() -> PackageReference {
public func createPackageRef(config: SwiftPMConfig) -> PackageReference {
let effectiveURL = config.mirroredURL(forURL: self.url)
return PackageReference(
identity: PackageReference.computeIdentity(packageURL: url),
path: url,
identity: PackageReference.computeIdentity(packageURL: effectiveURL),
path: effectiveURL,
isLocal: (requirement == .localPackage)
)
}
Expand All @@ -24,10 +26,10 @@ extension PackageDependencyDescription {
extension Manifest {

/// Constructs constraints of the dependencies in the raw package.
public func dependencyConstraints() -> [RepositoryPackageConstraint] {
public func dependencyConstraints(config: SwiftPMConfig) -> [RepositoryPackageConstraint] {
return dependencies.map({
return RepositoryPackageConstraint(
container: $0.createPackageRef(),
container: $0.createPackageRef(config: config),
requirement: $0.requirement.toConstraintRequirement())
})
}
Expand Down
Loading

0 comments on commit 9d7278c

Please sign in to comment.