Skip to content

Commit a477ba3

Browse files
authored
Merge pull request #670 from aciidb0mb3r/package-builder-fixes
Package builder fixes
2 parents d0d5d27 + 7f4f7d5 commit a477ba3

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public enum ModuleError: Swift.Error {
3434

3535
/// The manifest has invalid configuration wrt type of the module.
3636
case invalidManifestConfig(String, String)
37+
38+
/// The target dependency declaration has cycle in it.
39+
case cycleDetected((path: [Module], cycle: [Module]))
3740
}
3841

3942
extension ModuleError: FixableError {
@@ -47,6 +50,10 @@ extension ModuleError: FixableError {
4750
return "the target \(module) cannot have the executable \(dependency) as a dependency"
4851
case .invalidManifestConfig(let package, let message):
4952
return "invalid configuration in '\(package)': \(message)"
53+
case .cycleDetected(let cycle):
54+
return "found cyclic dependency declaration: " +
55+
(cycle.path + cycle.cycle).map{$0.name}.joined(separator: " -> ") +
56+
" -> " + cycle.cycle[0].name
5057
}
5158
}
5259

@@ -60,6 +67,8 @@ extension ModuleError: FixableError {
6067
return "move the shared logic inside a library, which can be referenced from both the target and the executable"
6168
case .invalidManifestConfig(_):
6269
return nil
70+
case .cycleDetected(_):
71+
return nil
6372
}
6473
}
6574
}
@@ -452,6 +461,11 @@ public struct PackageBuilder {
452461
module.dependencies = [baseModule]
453462
}
454463
}
464+
465+
// Look for any cycle in the dependencies.
466+
if let cycle = findCycle(modules.sorted { $0.name < $1.name }, successors: { $0.dependencies}) {
467+
throw ModuleError.cycleDetected(cycle)
468+
}
455469
}
456470

457471
/// Private function that checks whether a module name is valid. This method doesn't return anything, but rather, if there's a problem, it throws an error describing what the problem is.

Tests/PackageLoadingTests/ConventionTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,36 @@ class ConventionTests: XCTestCase {
579579
result.checkDiagnostic("these referenced modules could not be found: Foo fix: reference only valid modules")
580580
}
581581

582+
// Reference self in dependencies.
583+
package = PackageDescription.Package(name: "pkg", targets: [Target(name: "pkg", dependencies: ["pkg"])])
584+
PackageBuilderTester(package, in: fs) { result in
585+
result.checkDiagnostic("found cyclic dependency declaration: pkg -> pkg")
586+
}
587+
588+
fs = InMemoryFileSystem(emptyFiles:
589+
"/Sources/pkg1/Foo.swift",
590+
"/Sources/pkg2/Foo.swift",
591+
"/Sources/pkg3/Foo.swift"
592+
)
593+
// Cyclic dependency.
594+
package = PackageDescription.Package(name: "pkg", targets: [
595+
Target(name: "pkg1", dependencies: ["pkg2"]),
596+
Target(name: "pkg2", dependencies: ["pkg3"]),
597+
Target(name: "pkg3", dependencies: ["pkg1"]),
598+
])
599+
PackageBuilderTester(package, in: fs) { result in
600+
result.checkDiagnostic("found cyclic dependency declaration: pkg1 -> pkg2 -> pkg3 -> pkg1")
601+
}
602+
603+
package = PackageDescription.Package(name: "pkg", targets: [
604+
Target(name: "pkg1", dependencies: ["pkg2"]),
605+
Target(name: "pkg2", dependencies: ["pkg3"]),
606+
Target(name: "pkg3", dependencies: ["pkg2"]),
607+
])
608+
PackageBuilderTester(package, in: fs) { result in
609+
result.checkDiagnostic("found cyclic dependency declaration: pkg1 -> pkg2 -> pkg3 -> pkg2")
610+
}
611+
582612
// Executable as dependency.
583613
// FIXME: maybe should support this and condiser it as build order dependency.
584614
fs = InMemoryFileSystem(emptyFiles:

0 commit comments

Comments
 (0)