@@ -37,7 +37,6 @@ extension ModulesGraph {
37
37
fileSystem: FileSystem ,
38
38
observabilityScope: ObservabilityScope
39
39
) throws -> ModulesGraph {
40
-
41
40
let observabilityScope = observabilityScope. makeChildScope ( description: " Loading Package Graph " )
42
41
43
42
// Create a map of the manifests, keyed by their identity.
@@ -51,43 +50,64 @@ extension ModulesGraph {
51
50
let rootDependencies = Set ( root. dependencies. compactMap {
52
51
manifestMap [ $0. identity] ? . manifest
53
52
} )
54
- let rootManifestNodes = root. packages. map { identity, package in
55
- GraphLoadingNode ( identity: identity, manifest: package . manifest, productFilter: . everything)
53
+
54
+ let rootManifestNodes = try root. packages. map { identity, package in
55
+ // We are going to enable all default traits of the root manifests.
56
+ // In a future PR we make this overridable by CLI options.
57
+ let enabledTraits = package . manifest. traits. lazy. filter { $0. isDefault } . map { $0. name }
58
+ return try GraphLoadingNode (
59
+ identity: identity,
60
+ manifest: package . manifest,
61
+ productFilter: . everything,
62
+ enabledTraits: Set ( enabledTraits)
63
+ )
56
64
}
57
- let rootDependencyNodes = root. dependencies. lazy. compactMap { dependency in
58
- manifestMap [ dependency. identity] . map {
59
- GraphLoadingNode (
65
+ let rootDependencyNodes = try root. dependencies. lazy. compactMap { dependency in
66
+ try manifestMap [ dependency. identity] . map {
67
+ try GraphLoadingNode (
60
68
identity: dependency. identity,
61
69
manifest: $0. manifest,
62
- productFilter: dependency. productFilter
70
+ productFilter: dependency. productFilter,
71
+ enabledTraits: dependency. traits. flatMap { Set ( $0. map { $0. name } ) }
63
72
)
64
73
}
65
74
}
66
75
let inputManifests = ( rootManifestNodes + rootDependencyNodes) . map {
67
- KeyedPair ( $0, key: $0. id )
76
+ KeyedPair ( $0, key: $0. identity )
68
77
}
69
78
70
79
// Collect the manifests for which we are going to build packages.
71
- var allNodes = [ GraphLoadingNode] ( )
80
+ var allNodes = OrderedDictionary < PackageIdentity , GraphLoadingNode > ( )
72
81
73
82
let nodeSuccessorProvider = { ( node: KeyedPair < GraphLoadingNode , PackageIdentity > ) in
74
- node. item. requiredDependencies. compactMap { dependency in
75
- manifestMap [ dependency. identity] . map { manifest, _ in
76
- KeyedPair (
77
- GraphLoadingNode (
78
- identity: dependency. identity,
79
- manifest: manifest,
80
- productFilter: dependency. productFilter
81
- ) ,
82
- key: dependency. identity
83
- )
83
+ return try node. item. requiredDependencies. compactMap { dependency in
84
+ return try manifestMap [ dependency. identity] . map { manifest, _ in
85
+ // We are going to check the conditionally enabled traits here and enable them if
86
+ // required. This checks the current node and then enables the conditional
87
+ // dependencies of the dependency node.
88
+ let enabledTraits = dependency. traits? . filter {
89
+ guard let conditionTraits = $0. condition? . traits else {
90
+ return true
91
+ }
92
+ return !conditionTraits. intersection ( node. item. enabledTraits) . isEmpty
93
+ } . map { $0. name }
94
+
95
+ return try KeyedPair (
96
+ GraphLoadingNode (
97
+ identity: dependency. identity,
98
+ manifest: manifest,
99
+ productFilter: dependency. productFilter,
100
+ enabledTraits: enabledTraits. flatMap { Set ( $0) }
101
+ ) ,
102
+ key: dependency. identity
103
+ )
84
104
}
85
105
}
86
106
}
87
107
88
108
// Package dependency cycles feature is gated on tools version 6.0.
89
109
if !root. manifests. allSatisfy ( { $1. toolsVersion >= . v6_0 } ) {
90
- if let cycle = findCycle ( inputManifests, successors: nodeSuccessorProvider) {
110
+ if let cycle = try findCycle ( inputManifests, successors: nodeSuccessorProvider) {
91
111
let path = ( cycle. path + cycle. cycle) . map ( \. item. manifest)
92
112
observabilityScope. emit ( PackageGraphError . dependencyCycleDetected (
93
113
path: path, cycle: cycle. cycle [ 0 ] . item. manifest
@@ -104,18 +124,19 @@ extension ModulesGraph {
104
124
}
105
125
106
126
// Cycles in dependencies don't matter as long as there are no target cycles between packages.
107
- depthFirstSearch (
127
+ try depthFirstSearch (
108
128
inputManifests,
109
129
successors: nodeSuccessorProvider
110
130
) {
111
- allNodes. append ( $0. item)
112
- } onDuplicate: { _, _ in
113
- // no de-duplication is required.
131
+ allNodes [ $0. key] = $0. item
132
+ } onDuplicate: { first, second in
133
+ // We are unifying the enabled traits on duplicate
134
+ allNodes [ first. key] ? . enabledTraits. formUnion ( second. item. enabledTraits)
114
135
}
115
136
116
137
// Create the packages.
117
138
var manifestToPackage : [ Manifest : Package ] = [ : ]
118
- for node in allNodes {
139
+ for node in allNodes. values {
119
140
let nodeObservabilityScope = observabilityScope. makeChildScope (
120
141
description: " loading package \( node. identity) " ,
121
142
metadata: . packageMetadata( identity: node. identity, kind: node. manifest. packageKind)
@@ -139,7 +160,8 @@ extension ModulesGraph {
139
160
testEntryPointPath: testEntryPointPath,
140
161
createREPLProduct: manifest. packageKind. isRoot ? createREPLProduct : false ,
141
162
fileSystem: fileSystem,
142
- observabilityScope: nodeObservabilityScope
163
+ observabilityScope: nodeObservabilityScope,
164
+ enabledTraits: node. enabledTraits
143
165
)
144
166
let package = try builder. construct ( )
145
167
manifestToPackage [ manifest] = package
@@ -162,7 +184,7 @@ extension ModulesGraph {
162
184
163
185
// Resolve dependencies and create resolved packages.
164
186
let resolvedPackages = try createResolvedPackages (
165
- nodes: allNodes,
187
+ nodes: Array ( allNodes. values ) ,
166
188
identityResolver: identityResolver,
167
189
manifestToPackage: manifestToPackage,
168
190
rootManifests: root. manifests,
@@ -273,7 +295,7 @@ private func createResolvedPackages(
273
295
) throws -> IdentifiableSet < ResolvedPackage > {
274
296
275
297
// Create package builder objects from the input manifests.
276
- let packageBuilders : [ ResolvedPackageBuilder ] = nodes. compactMap { node in
298
+ let packageBuilders : [ ResolvedPackageBuilder ] = nodes. compactMap { node in
277
299
guard let package = manifestToPackage [ node. manifest] else {
278
300
return nil
279
301
}
@@ -283,6 +305,7 @@ private func createResolvedPackages(
283
305
return ResolvedPackageBuilder (
284
306
package ,
285
307
productFilter: node. productFilter,
308
+ enabledTraits: node. enabledTraits,
286
309
isAllowedToVendUnsafeProducts: isAllowedToVendUnsafeProducts,
287
310
allowedToOverride: allowedToOverride,
288
311
platformVersionProvider: platformVersionProvider
@@ -315,8 +338,9 @@ private func createResolvedPackages(
315
338
var dependenciesByNameForTargetDependencyResolution = [ String: ResolvedPackageBuilder] ( )
316
339
var dependencyNamesForTargetDependencyResolutionOnly = [ PackageIdentity: String] ( )
317
340
318
- // Establish the manifest-declared package dependencies.
319
- package . manifest. dependenciesRequired ( for: packageBuilder. productFilter) . forEach { dependency in
341
+ package . manifest. dependenciesRequired (
342
+ for: packageBuilder. productFilter
343
+ ) . forEach { dependency in
320
344
let dependencyPackageRef = dependency. packageRef
321
345
322
346
// Otherwise, look it up by its identity.
@@ -530,6 +554,13 @@ private func createResolvedPackages(
530
554
531
555
// Establish product dependencies.
532
556
for case . product( let productRef, let conditions) in targetBuilder. target. dependencies {
557
+ if let traitCondition = conditions. compactMap ( { $0. traitCondition } ) . first {
558
+ if packageBuilder. enabledTraits. intersection ( traitCondition. traits) . isEmpty {
559
+ /// If we land here non of the traits required to enable this depenendcy has been enabled.
560
+ continue
561
+ }
562
+ }
563
+
533
564
// Find the product in this package's dependency products.
534
565
// Look it up by ID if module aliasing is used, otherwise by name.
535
566
let product = lookupByProductIDs ? productDependencyMap [ productRef. identity] : productDependencyMap [ productRef. name]
@@ -1054,6 +1085,9 @@ private final class ResolvedPackageBuilder: ResolvedBuilder<ResolvedPackage> {
1054
1085
/// The products in this package.
1055
1086
var products : [ ResolvedProductBuilder ] = [ ]
1056
1087
1088
+ /// The enabled traits of this package.
1089
+ var enabledTraits : Set < String > = [ ]
1090
+
1057
1091
/// The dependencies of this package.
1058
1092
var dependencies : [ ResolvedPackageBuilder ] = [ ]
1059
1093
@@ -1074,12 +1108,14 @@ private final class ResolvedPackageBuilder: ResolvedBuilder<ResolvedPackage> {
1074
1108
init (
1075
1109
_ package : Package ,
1076
1110
productFilter: ProductFilter ,
1111
+ enabledTraits: Set < String > ,
1077
1112
isAllowedToVendUnsafeProducts: Bool ,
1078
1113
allowedToOverride: Bool ,
1079
1114
platformVersionProvider: PlatformVersionProvider
1080
1115
) {
1081
1116
self . package = package
1082
1117
self . productFilter = productFilter
1118
+ self . enabledTraits = enabledTraits
1083
1119
self . isAllowedToVendUnsafeProducts = isAllowedToVendUnsafeProducts
1084
1120
self . allowedToOverride = allowedToOverride
1085
1121
self . platformVersionProvider = platformVersionProvider
@@ -1095,6 +1131,7 @@ private final class ResolvedPackageBuilder: ResolvedBuilder<ResolvedPackage> {
1095
1131
defaultLocalization: self . defaultLocalization,
1096
1132
supportedPlatforms: self . supportedPlatforms,
1097
1133
dependencies: self . dependencies. map { $0. package . identity } ,
1134
+ enabledTraits: self . enabledTraits,
1098
1135
targets: targets,
1099
1136
products: products,
1100
1137
registryMetadata: self . registryMetadata,
0 commit comments