Skip to content

Commit 9075543

Browse files
authored
Cleanup PackageGraph Module (#2992)
* Extract PackageRequirement into separate file * Extract PackageContainer into separate file * Move BasePackageContainer to PackageContainer file Change BasePackageContainer initializer to internal access * Extract LocalPackageContainer into separate file * Rename RepositoryPackageContainerProvider.swift to RepositoryPackageContainer.swift Reorder RepositoryPackageContainer declarations * Move CheckoutState.requirement to original type declaration * Extract BoundVersion to separate file * Extract DependencyResolutionNode to separate file * Extract GraphLoadingNode to separate file * Move PackageGraphError to PackageGraph declaration * Extract diagnostics concerns to separate file * Rename RawPackageConstraints.swift to PackageModel+Extensions.swift * Refactor PackageGraphLoader functionality into extension on PackageGraph * Extract Pubgrub resolver into separate files * Conform to protocols in extensions * Use built-in Result type * Convert requirement to computed property * Convert nameForDiagnostics into computed property Move nameForDiagnostics helper method into fileprivate extension * Convert productFilter into computed property Make productFilter public Fix documentation comment for productFilter * Remove leading underscore for public property isRemoteContainer * Move PackageReference extension into PackageModel+Extensions * Extract extension on Version into separate file * Make constrained extension on Range fileprivate * Reorganize PinsStore protocol conformance and headings * Move findCycles helper function to PackageGraph+Loading Make findCycles fileprivate * Remove unused delegate APIs for DependencyResolver * Fix CMakeLists source list
1 parent df3a3e8 commit 9075543

30 files changed

+1490
-1375
lines changed

Sources/Commands/SwiftTool.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ private class ToolWorkspaceDelegate: WorkspaceDelegate {
123123

124124
switch state {
125125
case .checkout(let checkoutState)?:
126-
let requirement = checkoutState.requirement()
127-
switch requirement {
126+
switch checkoutState.requirement {
128127
case .versionSet(.exact(let version)):
129128
stdoutStream <<< "resolved to '\(version)'"
130129
case .versionSet(_):
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import struct TSCUtility.Version
12+
13+
/// A bound version for a package within an assignment.
14+
public enum BoundVersion: Equatable, Hashable {
15+
/// The assignment should not include the package.
16+
///
17+
/// This is different from the absence of an assignment for a particular
18+
/// package, which only indicates the assignment is agnostic to its
19+
/// version. This value signifies the package *may not* be present.
20+
case excluded
21+
22+
/// The version of the package to include.
23+
case version(Version)
24+
25+
/// The package assignment is unversioned.
26+
case unversioned
27+
28+
/// The package assignment is this revision.
29+
case revision(String)
30+
}
31+
32+
extension BoundVersion: CustomStringConvertible {
33+
public var description: String {
34+
switch self {
35+
case .excluded:
36+
return "excluded"
37+
case .version(let version):
38+
return version.description
39+
case .unversioned:
40+
return "unversioned"
41+
case .revision(let identifier):
42+
return identifier
43+
}
44+
}
45+
}

Sources/PackageGraph/CMakeLists.txt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,30 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
add_library(PackageGraph
10+
BoundVersion.swift
1011
CheckoutState.swift
12+
DependencyResolutionNode.swift
1113
DependencyResolver.swift
14+
Diagnostics.swift
15+
GraphLoadingNode.swift
16+
LocalPackageContainer.swift
17+
PackageContainer.swift
1218
PackageGraph.swift
13-
PackageGraphLoader.swift
19+
PackageGraph+Loading.swift
1420
PackageGraphRoot.swift
21+
PackageModel+Extensions.swift
22+
PackageRequirement.swift
1523
PinsStore.swift
16-
Pubgrub.swift
17-
RawPackageConstraints.swift
24+
Pubgrub/Assignment.swift
25+
Pubgrub/Incompatibility.swift
26+
Pubgrub/PartialSolution.swift
27+
Pubgrub/PubgrubDependencyResolver.swift
28+
Pubgrub/Term.swift
29+
RepositoryPackageContainer.swift
1830
ResolvedPackage.swift
1931
ResolvedProduct.swift
2032
ResolvedTarget.swift
21-
RepositoryPackageContainerProvider.swift
33+
Version+Extensions.swift
2234
VersionSetSpecifier.swift)
2335
target_link_libraries(PackageGraph PUBLIC
2436
TSCBasic

Sources/PackageGraph/CheckoutState.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import TSCUtility
1515
/// A checkout state represents the current state of a repository.
1616
///
1717
/// A state will always has a revision. It can also have a branch or a version but not both.
18-
public struct CheckoutState: Equatable, CustomStringConvertible {
18+
public struct CheckoutState: Equatable, Hashable {
1919

2020
/// The revision of the checkout.
2121
public let revision: Revision
@@ -47,25 +47,27 @@ public struct CheckoutState: Equatable, CustomStringConvertible {
4747
self.init(revision: revision, version: version, branch: nil)
4848
}
4949

50-
public var description: String {
51-
return version?.description ?? branch ?? revision.identifier
52-
}
53-
5450
public var isBranchOrRevisionBased: Bool {
5551
return version == nil
5652
}
57-
}
58-
59-
extension CheckoutState {
6053

6154
/// Returns requirement induced by this state.
62-
public func requirement() -> PackageRequirement {
55+
public var requirement: PackageRequirement {
6356
if let version = version {
6457
return .versionSet(.exact(version))
6558
} else if let branch = branch {
6659
return .revision(branch)
60+
} else {
61+
return .revision(revision.identifier)
6762
}
68-
return .revision(revision.identifier)
63+
}
64+
}
65+
66+
// MARK: - CustomStringConvertible
67+
68+
extension CheckoutState: CustomStringConvertible {
69+
public var description: String {
70+
return version?.description ?? branch ?? revision.identifier
6971
}
7072
}
7173

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import TSCBasic
12+
import PackageModel
13+
import struct TSCUtility.Version
14+
15+
/// A node in the dependency resolution graph.
16+
///
17+
/// See the documentation of each case for more detailed descriptions of each kind and how they interact.
18+
///
19+
/// - SeeAlso: `GraphLoadingNode`
20+
public enum DependencyResolutionNode {
21+
22+
/// An empty package node.
23+
///
24+
/// This node indicates that a package needs to be present, but does not indicate that any of its contents are needed.
25+
///
26+
/// Empty package nodes are always leaf nodes; they have no dependencies.
27+
case empty(package: PackageReference)
28+
29+
/// A product node.
30+
///
31+
/// This node indicates that a particular product in a particular package is required.
32+
///
33+
/// Product nodes always have dependencies. A product node has...
34+
///
35+
/// - one implicit dependency on its own package at an exact version (as an empty package node).
36+
/// This dependency is what ensures the resolver does not select two products from the same package at different versions.
37+
/// - zero or more dependencies on the product nodes of other packages.
38+
/// These are all the external products required to build all of the targets vended by this product.
39+
/// They derive from the manifest.
40+
///
41+
/// Tools versions before 5.2 do not know which products belong to which packages, so each product is required from every dependency.
42+
/// Since a non‐existant product ends up with only its implicit dependency on its own package,
43+
/// only whichever package contains the product will end up adding additional constraints.
44+
/// See `ProductFilter` and `Manifest.register(...)`.
45+
case product(String, package: PackageReference)
46+
47+
/// A root node.
48+
///
49+
/// This node indicates a root node in the graph, which is required no matter what.
50+
///
51+
/// Root nodes may have dependencies. A root node has...
52+
///
53+
/// - zero or more dependencies on each external product node required to build any of its targets (vended or not).
54+
/// - zero or more dependencies directly on external empty package nodes.
55+
/// This special case occurs when a dependecy is declared but not used.
56+
/// It is a warning condition, and builds do not actually need these dependencies.
57+
/// However, forcing the graph to resolve and fetch them anyway allows the diagnostics passes access
58+
/// to the information needed in order to provide actionable suggestions to help the user stitch up the dependency declarations properly.
59+
case root(package: PackageReference)
60+
61+
/// The package.
62+
public var package: PackageReference {
63+
switch self {
64+
case .empty(let package), .product(_, let package), .root(let package):
65+
return package
66+
}
67+
}
68+
69+
/// The name of the specific product if the node is a product node, otherwise `nil`.
70+
public var specificProduct: String? {
71+
switch self {
72+
case .empty, .root:
73+
return nil
74+
case .product(let product, _):
75+
return product
76+
}
77+
}
78+
79+
/// Assembles the product filter to use on the manifest for this node to determine its dependencies.
80+
public var productFilter: ProductFilter {
81+
switch self {
82+
case .empty:
83+
return .specific([])
84+
case .product(let product, _):
85+
return .specific([product])
86+
case .root:
87+
return .everything
88+
}
89+
}
90+
91+
/// Returns the dependency that a product has on its own package, if relevant.
92+
///
93+
/// This is the constraint that requires all products from a package resolve to the same version.
94+
internal func versionLock(version: Version) -> RepositoryPackageConstraint? {
95+
// Don’t create a version lock for anything but a product.
96+
guard specificProduct != nil else { return nil }
97+
return RepositoryPackageConstraint(
98+
container: package,
99+
versionRequirement: .exact(version),
100+
products: .specific([])
101+
)
102+
}
103+
104+
/// Returns the dependency that a product has on its own package, if relevant.
105+
///
106+
/// This is the constraint that requires all products from a package resolve to the same revision.
107+
internal func revisionLock(revision: String) -> RepositoryPackageConstraint? {
108+
// Don’t create a revision lock for anything but a product.
109+
guard specificProduct != nil else { return nil }
110+
return RepositoryPackageConstraint(
111+
container: package,
112+
requirement: .revision(revision),
113+
products: .specific([])
114+
)
115+
}
116+
}
117+
118+
extension DependencyResolutionNode: Equatable {
119+
public static func ==(lhs: DependencyResolutionNode, rhs: DependencyResolutionNode) -> Bool {
120+
return (lhs.package, lhs.specificProduct) == (rhs.package, rhs.specificProduct)
121+
}
122+
}
123+
124+
extension DependencyResolutionNode: Hashable {
125+
public func hash(into hasher: inout Hasher) {
126+
hasher.combine(package)
127+
hasher.combine(specificProduct)
128+
}
129+
}
130+
131+
extension DependencyResolutionNode: CustomStringConvertible {
132+
public var description: String {
133+
return "\(package.name)\(productFilter)"
134+
}
135+
}

0 commit comments

Comments
 (0)