Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI tools necessary for the binary targets proposal #2509

Merged
merged 1 commit into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 69 additions & 18 deletions Sources/Commands/SwiftPackageTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {

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

if let mirror = config.getMirror(forURL: packageURL) {
if let mirror = config.getMirror(forURL: originalURL) {
print(mirror)
} else {
stderrStream <<< "not found\n"
Expand All @@ -62,24 +62,25 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
}

case .unsetMirror:
guard let packageOrMirror = options.configOptions.packageURL ?? options.configOptions.mirrorURL else {
diagnostics.emit(.missingRequiredArg("--package-url or --mirror-url"))
guard let originalOrMirrorURL = options.configOptions.originalURL ?? options.configOptions.mirrorURL
else {
diagnostics.emit(.missingRequiredArg("--original-url or --mirror-url"))
return
}

try config.unset(packageOrMirrorURL: packageOrMirror)
try config.unset(originalOrMirrorURL: originalOrMirrorURL)

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

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

case .initPackage:
Expand Down Expand Up @@ -379,6 +380,21 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
default:
preconditionFailure("somehow we ended up with an invalid positional argument")
}

case .computeChecksum:
let workspace = try getActiveWorkspace()
let checksum = workspace.checksum(
forBinaryArtifactAt: options.computeChecksumOptions.path,
diagnostics: diagnostics
)

guard !diagnostics.hasErrors else {
return
}

stdoutStream <<< checksum <<< "\n"
stdoutStream.flush()

case .help:
parser.printUsage(on: stdoutStream)
}
Expand Down Expand Up @@ -507,17 +523,19 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
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: "--original-url", kind: String.self,
usage: "The original url"),
setMirrorParser.add(
option: "--mirror-url", kind: String.self,
usage: "The mirror url"),
to: {
$0.configOptions.packageURL = $1
$0.configOptions.mirrorURL = $2
$0.configOptions.originalURL = $1 ?? $2
$0.configOptions.mirrorURL = $3
}
)

Expand All @@ -528,23 +546,30 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
unsetMirrorParser.add(
option: "--package-url", kind: String.self,
usage: "The package dependency url"),
unsetMirrorParser.add(
option: "--original-url", kind: String.self,
usage: "The original url"),
unsetMirrorParser.add(
option: "--mirror-url", kind: String.self,
usage: "The mirror url"),
to: {
$0.configOptions.packageURL = $1
$0.configOptions.mirrorURL = $2
$0.configOptions.originalURL = $1 ?? $2
$0.configOptions.mirrorURL = $3
}
)

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"),
getMirrorParser.add(
option: "--package-url", kind: String.self,
usage: "The package dependency url"),
getMirrorParser.add(
option: "--original-url", kind: String.self,
usage: "The original url"),
to: {
$0.configOptions.packageURL = $1
$0.configOptions.originalURL = $1 ?? $2
}
)

Expand Down Expand Up @@ -635,10 +660,30 @@ public class SwiftPackageTool: SwiftTool<PackageToolOptions> {
usage: "Invert the baseline which is helpful for determining API additions"),
to: { $0.apiDiffOptions.invertBaseline = $1 })

let computeChecksumParser = parser.add(
subparser: PackageMode.computeChecksum.rawValue,
overview: "Compute the checksum for a binary artifact.")
binder.bind(
positional: computeChecksumParser.add(
positional: "file", kind: PathArgument.self,
usage: "The absolute or relative path to the binary artifact"),
to: { $0.computeChecksumOptions.path = $1.path })

binder.bind(
parser: parser,
to: { $0.mode = PackageMode(rawValue: $1)! })
}

override class func postprocessArgParserResult(
result: ArgumentParser.Result,
diagnostics: DiagnosticsEngine
) throws {
try super.postprocessArgParserResult(result: result, diagnostics: diagnostics)

if result.exists(arg: "--package-url") {
diagnostics.emit(warning: "'--package-url' option is deprecated; use '--original-url' instead")
}
}
}

public class PackageToolOptions: ToolOptions {
Expand Down Expand Up @@ -700,6 +745,11 @@ public class PackageToolOptions: ToolOptions {
}
var apiDiffOptions = APIDiffOptions()

struct ComputeChecksumOptions {
var path: AbsolutePath!
}
var computeChecksumOptions = ComputeChecksumOptions()

enum ToolsVersionMode {
case display
case set(String)
Expand All @@ -721,7 +771,7 @@ public class PackageToolOptions: ToolOptions {
var configMode: ConfigMode?

struct ConfigOptions {
var packageURL: String?
var originalURL: String?
var mirrorURL: String?
}
var configOptions = ConfigOptions()
Expand Down Expand Up @@ -749,6 +799,7 @@ public enum PackageMode: String, StringEnumArgument {
case update
case version
case apidiff = "experimental-api-diff"
case computeChecksum = "compute-checksum"
case help

// PackageMode is not used as an argument; completions will be
Expand Down
2 changes: 1 addition & 1 deletion Sources/Commands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ public class SwiftTool<Options: ToolOptions> {
(packageRoot ?? cwd).appending(component: ".build")
}

static func postprocessArgParserResult(result: ArgumentParser.Result, diagnostics: DiagnosticsEngine) throws {
class func postprocessArgParserResult(result: ArgumentParser.Result, diagnostics: DiagnosticsEngine) throws {
if result.exists(arg: "--chdir") || result.exists(arg: "-C") {
diagnostics.emit(warning: "'--chdir/-C' option is deprecated; use '--package-path' instead")
}
Expand Down
16 changes: 8 additions & 8 deletions Sources/SourceControl/SwiftPMConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ public final class SwiftPMConfig {
self.persistence = nil
}

/// Set a mirror URL for the given package URL.
public func set(mirrorURL: String, forPackageURL packageURL: String) throws {
mirrors[packageURL] = Mirror(original: packageURL, mirror: mirrorURL)
/// Set a mirror URL for the given URL.
public func set(mirrorURL: String, forURL url: String) throws {
mirrors[url] = Mirror(original: url, mirror: mirrorURL)
try saveState()
}

/// Unset a mirror for the given package or mirror URL.
/// Unset a mirror for the given URL.
///
/// This method will throw if there is no mirror for the given input.
public func unset(packageOrMirrorURL: String) throws {
if mirrors.keys.contains(packageOrMirrorURL) {
mirrors[packageOrMirrorURL] = nil
} else if let mirror = mirrors.first(where: { $0.value.mirror == packageOrMirrorURL }) {
public func unset(originalOrMirrorURL: String) throws {
if mirrors.keys.contains(originalOrMirrorURL) {
mirrors[originalOrMirrorURL] = nil
} else if let mirror = mirrors.first(where: { $0.value.mirror == originalOrMirrorURL }) {
mirrors[mirror.key] = nil
} else {
throw Error.mirrorNotFound
Expand Down
21 changes: 21 additions & 0 deletions Sources/Workspace/Workspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ public class Workspace {
/// The package container provider.
fileprivate let containerProvider: RepositoryPackageContainerProvider

/// The algorithm used for generating file checksums.
fileprivate let checksumAlgorithm: HashAlgorithm

/// Enable prefetching containers in resolver.
fileprivate let isResolverPrefetchingEnabled: Bool

Expand Down Expand Up @@ -386,6 +389,7 @@ public class Workspace {
config: SwiftPMConfig = SwiftPMConfig(),
fileSystem: FileSystem = localFileSystem,
repositoryProvider: RepositoryProvider = GitRepositoryProvider(),
checksumAlgorithm: HashAlgorithm = SHA256(),
hartbit marked this conversation as resolved.
Show resolved Hide resolved
additionalFileRules: [FileRuleDescription] = [],
isResolverPrefetchingEnabled: Bool = false,
enablePubgrubResolver: Bool = false,
Expand All @@ -399,6 +403,7 @@ public class Workspace {
self.manifestLoader = manifestLoader
self.currentToolsVersion = currentToolsVersion
self.toolsVersionLoader = toolsVersionLoader
self.checksumAlgorithm = checksumAlgorithm
self.isResolverPrefetchingEnabled = isResolverPrefetchingEnabled
self.enablePubgrubResolver = enablePubgrubResolver
self.skipUpdate = skipUpdate
Expand Down Expand Up @@ -800,6 +805,22 @@ extension Workspace {

return rootManifests
}

/// Generates the checksum
public func checksum(
forBinaryArtifactAt path: AbsolutePath,
diagnostics: DiagnosticsEngine
) -> String {
guard fileSystem.isFile(path) else {
diagnostics.emit(error: "file not found at path: \(path.pathString)")
return ""
}

return diagnostics.wrap {
let contents = try fileSystem.readFileContents(path)
return checksumAlgorithm.hash(contents).hexadecimalRepresentation
} ?? ""
}
}

// MARK: - Editing Functions
Expand Down
43 changes: 32 additions & 11 deletions Tests/CommandsTests/PackageToolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -567,19 +567,21 @@ final class PackageToolTests: XCTestCase {
)

// Test writing.
try execute(["config", "set-mirror", "--package-url", "https://github.com/foo/bar", "--mirror-url", "https://mygithub.com/foo/bar"], packagePath: packageRoot)
try execute(["config", "set-mirror", "--package-url", "git@github.com:apple/swift-package-manager.git", "--mirror-url", "git@mygithub.com:foo/swift-package-manager.git"], packagePath: packageRoot)
var (stdout, stderr) = try execute(["config", "set-mirror", "--package-url", "https://github.com/foo/bar", "--mirror-url", "https://mygithub.com/foo/bar"], packagePath: packageRoot)
XCTAssertMatch(stderr, .contains("warning: '--package-url' option is deprecated; use '--original-url' instead"))
try execute(["config", "set-mirror", "--original-url", "git@github.com:apple/swift-package-manager.git", "--mirror-url", "git@mygithub.com:foo/swift-package-manager.git"], packagePath: packageRoot)
XCTAssertTrue(fs.isFile(configFile))

// Test env override.
try execute(["config", "set-mirror", "--package-url", "https://github.com/foo/bar", "--mirror-url", "https://mygithub.com/foo/bar"], packagePath: packageRoot, env: ["SWIFTPM_MIRROR_CONFIG": configOverride.pathString])
try execute(["config", "set-mirror", "--original-url", "https://github.com/foo/bar", "--mirror-url", "https://mygithub.com/foo/bar"], packagePath: packageRoot, env: ["SWIFTPM_MIRROR_CONFIG": configOverride.pathString])
XCTAssertTrue(fs.isFile(configOverride))
XCTAssertTrue(try fs.readFileContents(configOverride).description.contains("mygithub"))

// Test reading.
var (stdout, stderr) = try execute(["config", "get-mirror", "--package-url", "https://github.com/foo/bar"], packagePath: packageRoot)
(stdout, stderr) = try execute(["config", "get-mirror", "--package-url", "https://github.com/foo/bar"], packagePath: packageRoot)
XCTAssertEqual(stdout.spm_chomp(), "https://mygithub.com/foo/bar")
(stdout, _) = try execute(["config", "get-mirror", "--package-url", "git@github.com:apple/swift-package-manager.git"], packagePath: packageRoot)
XCTAssertMatch(stderr, .contains("warning: '--package-url' option is deprecated; use '--original-url' instead"))
(stdout, _) = try execute(["config", "get-mirror", "--original-url", "git@github.com:apple/swift-package-manager.git"], packagePath: packageRoot)
XCTAssertEqual(stdout.spm_chomp(), "git@mygithub.com:foo/swift-package-manager.git")

func check(stderr: String, _ block: () throws -> ()) {
Expand All @@ -594,23 +596,42 @@ final class PackageToolTests: XCTestCase {
}

check(stderr: "not found\n") {
try execute(["config", "get-mirror", "--package-url", "foo"], packagePath: packageRoot)
try execute(["config", "get-mirror", "--original-url", "foo"], packagePath: packageRoot)
}

// Test deletion.
try execute(["config", "unset-mirror", "--package-url", "https://github.com/foo/bar"], packagePath: packageRoot)
try execute(["config", "unset-mirror", "--mirror-url", "git@mygithub.com:foo/swift-package-manager.git"], packagePath: packageRoot)
(_, stderr) = try execute(["config", "unset-mirror", "--package-url", "https://github.com/foo/bar"], packagePath: packageRoot)
XCTAssertMatch(stderr, .contains("warning: '--package-url' option is deprecated; use '--original-url' instead"))
try execute(["config", "unset-mirror", "--original-url", "git@mygithub.com:foo/swift-package-manager.git"], packagePath: packageRoot)

check(stderr: "not found\n") {
try execute(["config", "get-mirror", "--package-url", "https://github.com/foo/bar"], packagePath: packageRoot)
try execute(["config", "get-mirror", "--original-url", "https://github.com/foo/bar"], packagePath: packageRoot)
}
check(stderr: "not found\n") {
try execute(["config", "get-mirror", "--package-url", "git@github.com:apple/swift-package-manager.git"], packagePath: packageRoot)
try execute(["config", "get-mirror", "--original-url", "git@github.com:apple/swift-package-manager.git"], packagePath: packageRoot)
}

check(stderr: "error: mirror not found\n") {
try execute(["config", "unset-mirror", "--package-url", "foo"], packagePath: packageRoot)
try execute(["config", "unset-mirror", "--original-url", "foo"], packagePath: packageRoot)
}
}
}

func testComputeChecksum() {
fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { prefix in
let invalid = prefix.appending(component: "invalid-file")
do {
try execute(["compute-checksum", invalid.pathString], packagePath: prefix)
XCTFail("expected to fail")
} catch SwiftPMProductError.executionFailure(_, _, let stderr) {
XCTAssertMatch(stderr, .contains("error: file not found at path: \(invalid.pathString)"))
} catch {
XCTFail("unexpected error: \(error)")
}

let readme = prefix.appending(component: "README.md")
let (stdout, _) = try execute(["compute-checksum", readme.pathString], packagePath: prefix)
XCTAssertEqual(stdout.spm_chomp(), "5a2cd751cc6e8005a56c836c7269b038bbd536ee998275a1497c37fc986c4352")
}
}
}
1 change: 1 addition & 0 deletions Tests/CommandsTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extension PackageToolTests {
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__PackageToolTests = [
("testComputeChecksum", testComputeChecksum),
("testDescribe", testDescribe),
("testDumpPackage", testDumpPackage),
("testInitCustomNameExecutable", testInitCustomNameExecutable),
Expand Down
4 changes: 2 additions & 2 deletions Tests/WorkspaceTests/WorkspaceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3243,8 +3243,8 @@ final class WorkspaceTests: XCTestCase {
result.check(notPresent: "Baz")
}

try workspace.config.set(mirrorURL: workspace.packagesDir.appending(component: "Baz").pathString, forPackageURL: workspace.packagesDir.appending(component: "Bar").pathString)
try workspace.config.set(mirrorURL: workspace.packagesDir.appending(component: "Baz").pathString, forPackageURL: workspace.packagesDir.appending(component: "Bam").pathString)
try workspace.config.set(mirrorURL: workspace.packagesDir.appending(component: "Baz").pathString, forURL: workspace.packagesDir.appending(component: "Bar").pathString)
try workspace.config.set(mirrorURL: workspace.packagesDir.appending(component: "Baz").pathString, forURL: workspace.packagesDir.appending(component: "Bam").pathString)

let deps: [TestWorkspace.PackageDependency] = [
.init(name: "Bam", requirement: .upToNextMajor(from: "1.0.0")),
Expand Down