Skip to content

Commit

Permalink
[PackageGraph] Diagnose invalid usage of local package reference
Browse files Browse the repository at this point in the history
<rdar://problem/50188484>
  • Loading branch information
aciidgh committed Jul 11, 2019
1 parent 013c394 commit eabd0f3
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
24 changes: 24 additions & 0 deletions Sources/PackageGraph/DependencyResolver.swift
Expand Up @@ -28,6 +28,9 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible {
/// The resolver found missing versions for the given constraints.
case missingVersions([PackageContainerConstraint])

/// A revision-based dependency contains a local package dependency.
case revisionDependencyContainsLocalPackage(dependency: String, localPackage: String)

/// The resolution was cancelled.
case cancelled

Expand All @@ -50,6 +53,10 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible {
return lhs == rhs
case (.missingVersions, _):
return false
case (.revisionDependencyContainsLocalPackage(let a1, let b1), .revisionDependencyContainsLocalPackage(let a2, let b2)):
return a1 == a2 && b1 == b2
case (.revisionDependencyContainsLocalPackage, _):
return false
case (.cancelled, .cancelled):
return true
case (.cancelled, _):
Expand All @@ -61,6 +68,8 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible {
switch self {
case .cancelled:
return "the package resolution operation was cancelled"
case .revisionDependencyContainsLocalPackage(let dependency, let localPackage):
return "package '\(dependency)' is required using a revision-based requirement and it depends on local package '\(localPackage)', which is not supported"
case .unsatisfiable:
return "the package dependency graph could not be resolved due to an unknown conflict"
case .cycle(let package):
Expand Down Expand Up @@ -1114,6 +1123,21 @@ public class DependencyResolver {
guard let constraints = self.safely({ try container.getDependencies(at: identifier) }) else {
return AnySequence([])
}

// If we have any local packages, set the error and abort.
//
// We might want to support this in the future if the local package is contained
// inside the dependency. That's going to be tricky though since we don't have
// concrete checkouts yet.
let incompatibleConstraints = constraints.filter{ $0.requirement == .unversioned }
guard incompatibleConstraints.isEmpty else {
self.error = DependencyResolverError.revisionDependencyContainsLocalPackage(
dependency: container.identifier.identity,
localPackage: incompatibleConstraints[0].identifier.identity
)
return AnySequence([])
}

result = merge(constraints: constraints, binding: .revision(identifier))

case .versionSet(let versionSet):
Expand Down
53 changes: 53 additions & 0 deletions Tests/WorkspaceTests/WorkspaceTests.swift
Expand Up @@ -2995,6 +2995,59 @@ final class WorkspaceTests: XCTestCase {
XCTAssertEqual(loadedPackage.name, "SwiftPM")
XCTAssert(graph.reachableProducts.contains(where: { $0.name == "SwiftPM" }))
}

func testRevisionDepOnLocal() throws {
let sandbox = AbsolutePath("/tmp/ws/")
let fs = InMemoryFileSystem()

let workspace = try TestWorkspace(
sandbox: sandbox,
fs: fs,
roots: [
TestPackage(
name: "Root",
targets: [
TestTarget(name: "Root", dependencies: ["Foo"]),
],
products: [],
dependencies: [
TestDependency(name: "Foo", requirement: .branch("develop")),
]
),
],
packages: [
TestPackage(
name: "Foo",
targets: [
TestTarget(name: "Foo"),
],
products: [
TestProduct(name: "Foo", targets: ["Foo"]),
],
dependencies: [
TestDependency(name: "Local", requirement: .localPackage),
],
versions: ["develop"]
),
TestPackage(
name: "Local",
targets: [
TestTarget(name: "Local"),
],
products: [
TestProduct(name: "Local", targets: ["Local"]),
],
versions: [nil]
),
]
)

workspace.checkPackageGraph(roots: ["Root"]) { (_, diagnostics) in
DiagnosticsEngineTester(diagnostics) { result in
result.check(diagnostic: .equal("package 'foo' is required using a revision-based requirement and it depends on local package 'local', which is not supported"), behavior: .error)
}
}
}
}

extension PackageGraph {
Expand Down
1 change: 1 addition & 0 deletions Tests/WorkspaceTests/XCTestManifests.swift
Expand Up @@ -75,6 +75,7 @@ extension WorkspaceTests {
("testResolve", testResolve),
("testResolvedFileUpdate", testResolvedFileUpdate),
("testResolverCanHaveError", testResolverCanHaveError),
("testRevisionDepOnLocal", testRevisionDepOnLocal),
("testRevisionVersionSwitch", testRevisionVersionSwitch),
("testRootAsDependency1", testRootAsDependency1),
("testRootAsDependency2", testRootAsDependency2),
Expand Down

0 comments on commit eabd0f3

Please sign in to comment.