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