@@ -1028,7 +1028,7 @@ private struct DiagnosticReportBuilder {
1028
1028
1029
1029
/// A container for an individual package. This enhances PackageContainer to add PubGrub specific
1030
1030
/// logic which is mostly related to computing incompatibilities at a particular version.
1031
- private final class PubGrubPackageContainer {
1031
+ internal final class PubGrubPackageContainer {
1032
1032
/// The underlying package container.
1033
1033
let underlying : PackageContainer
1034
1034
@@ -1037,10 +1037,10 @@ private final class PubGrubPackageContainer {
1037
1037
1038
1038
/// The map of dependencies to version set that indicates the versions that have had their
1039
1039
/// incompatibilities emitted.
1040
- private var emittedIncompatibilities = ThreadSafeKeyValueStore < PackageReference , VersionSetSpecifier > ( )
1040
+ private var emittedIncompatibilities = ThreadSafeKeyValueStore < DependencyResolutionNode , VersionSetSpecifier > ( )
1041
1041
1042
1042
/// Whether we've emitted the incompatibilities for the pinned versions.
1043
- private var emittedPinnedVersionIncompatibilities = ThreadSafeBox ( false )
1043
+ private var emittedPinnedVersionIncompatibilities = ThreadSafeKeyValueStore < DependencyResolutionNode , Bool > ( )
1044
1044
1045
1045
init ( underlying: PackageContainer , pinsMap: PinsStore . PinsMap ) {
1046
1046
self . underlying = underlying
@@ -1191,20 +1191,28 @@ private final class PubGrubPackageContainer {
1191
1191
1192
1192
// Skip if we already emitted incompatibilities for this dependency such that the selected
1193
1193
// falls within the previously computed bounds.
1194
- if emittedIncompatibilities [ dep. package ] ? . contains ( version) != true {
1195
- constraints. append ( dep)
1194
+ if emittedIncompatibilities [ node] ? . contains ( version) != true {
1195
+ for node in dep. nodes ( ) {
1196
+ constraints. append (
1197
+ PackageContainerConstraint (
1198
+ package : node. package ,
1199
+ requirement: dep. requirement,
1200
+ products: node. productFilter
1201
+ )
1202
+ )
1203
+ }
1196
1204
}
1197
1205
}
1198
1206
1199
1207
// Emit the dependencies at the pinned version if we haven't emitted anything else yet.
1200
1208
if version == pinnedVersion, emittedIncompatibilities. isEmpty {
1201
1209
// We don't need to emit anything if we already emitted the incompatibilities at the
1202
1210
// pinned version.
1203
- if self . emittedPinnedVersionIncompatibilities. get ( ) ?? false {
1211
+ if self . emittedPinnedVersionIncompatibilities [ node ] ?? false {
1204
1212
return [ ]
1205
1213
}
1206
1214
1207
- self . emittedPinnedVersionIncompatibilities. put ( true )
1215
+ self . emittedPinnedVersionIncompatibilities [ node ] = true
1208
1216
1209
1217
// Since the pinned version is most likely to succeed, we don't compute bounds for its
1210
1218
// incompatibilities.
@@ -1223,30 +1231,29 @@ private final class PubGrubPackageContainer {
1223
1231
1224
1232
let ( lowerBounds, upperBounds) = try self . computeBounds ( for: node,
1225
1233
constraints: constraints,
1226
- startingWith: version,
1227
- products : node . productFilter )
1228
-
1229
- return try constraints . map { constraint in
1230
- var terms : OrderedSet < Term > = [ ]
1231
- let lowerBound = lowerBounds [ constraint . package ] ?? " 0.0.0 "
1232
- let upperBound = upperBounds [ constraint . package ] ?? Version ( version. major + 1 , 0 , 0 )
1233
- assert ( lowerBound < upperBound)
1234
-
1235
- // We only have version-based requirements at this point.
1236
- guard case . versionSet( let vs) = constraint. requirement else {
1237
- throw InternalError ( " Unexpected unversioned requirement: \( constraint) " )
1238
- }
1234
+ startingWith: version)
1235
+
1236
+ return try constraints . flatMap { constraint in
1237
+ return try constraint . nodes ( ) . map { constraintNode in
1238
+ var terms : OrderedSet < Term > = [ ]
1239
+ let lowerBound = lowerBounds [ constraintNode ] ?? " 0.0.0 "
1240
+ let upperBound = upperBounds [ constraintNode ] ?? Version ( version. major + 1 , 0 , 0 )
1241
+ assert ( lowerBound < upperBound)
1242
+
1243
+ // We only have version-based requirements at this point.
1244
+ guard case . versionSet( let vs) = constraint. requirement else {
1245
+ throw InternalError ( " Unexpected unversioned requirement: \( constraint) " )
1246
+ }
1239
1247
1240
- for constraintNode in constraint. nodes ( ) {
1241
1248
let requirement : VersionSetSpecifier = . range( lowerBound ..< upperBound)
1242
1249
terms. append ( Term ( node, requirement) )
1243
1250
terms. append ( Term ( not: constraintNode, vs) )
1244
1251
1245
1252
// Make a record for this dependency so we don't have to recompute the bounds when the selected version falls within the bounds.
1246
- self . emittedIncompatibilities [ constraint. package ] = requirement. union ( emittedIncompatibilities [ constraint. package ] ?? . empty)
1247
- }
1253
+ self . emittedIncompatibilities [ constraintNode] = requirement. union ( emittedIncompatibilities [ constraintNode] ?? . empty)
1248
1254
1249
- return try Incompatibility ( terms, root: root, cause: . dependency( node: node) )
1255
+ return try Incompatibility ( terms, root: root, cause: . dependency( node: node) )
1256
+ }
1250
1257
}
1251
1258
}
1252
1259
@@ -1259,9 +1266,8 @@ private final class PubGrubPackageContainer {
1259
1266
private func computeBounds(
1260
1267
for node: DependencyResolutionNode ,
1261
1268
constraints: [ PackageContainerConstraint ] ,
1262
- startingWith firstVersion: Version ,
1263
- products: ProductFilter
1264
- ) throws -> ( lowerBounds: [ PackageReference : Version ] , upperBounds: [ PackageReference : Version ] ) {
1269
+ startingWith firstVersion: Version
1270
+ ) throws -> ( lowerBounds: [ DependencyResolutionNode : Version ] , upperBounds: [ DependencyResolutionNode : Version ] ) {
1265
1271
let preloadCount = 3
1266
1272
1267
1273
// nothing to do
@@ -1274,15 +1280,15 @@ private final class PubGrubPackageContainer {
1274
1280
for version in versions {
1275
1281
DispatchQueue . sharedConcurrent. async ( group: sync) {
1276
1282
if self . underlying. isToolsVersionCompatible ( at: version) {
1277
- _ = try ? self . underlying. getDependencies ( at: version, productFilter: products )
1283
+ _ = try ? self . underlying. getDependencies ( at: version, productFilter: node . productFilter )
1278
1284
}
1279
1285
}
1280
1286
}
1281
1287
sync. wait ( )
1282
1288
}
1283
1289
1284
- func compute( _ versions: [ Version ] , upperBound: Bool ) -> [ PackageReference : Version ] {
1285
- var result : [ PackageReference : Version ] = [ : ]
1290
+ func compute( _ versions: [ Version ] , upperBound: Bool ) -> [ DependencyResolutionNode : Version ] {
1291
+ var result : [ DependencyResolutionNode : Version ] = [ : ]
1286
1292
var previousVersion = firstVersion
1287
1293
1288
1294
for (index, version) in versions. enumerated ( ) {
@@ -1299,17 +1305,19 @@ private final class PubGrubPackageContainer {
1299
1305
let bound = upperBound ? version : previousVersion
1300
1306
1301
1307
let isToolsVersionCompatible = self . underlying. isToolsVersionCompatible ( at: version)
1302
- for constraint in constraints where !result. keys. contains ( constraint. package ) {
1303
- // If we hit a version which doesn't have a compatible tools version then that's the boundary.
1304
- // Record the bound if the tools version isn't compatible at the current version.
1305
- if !isToolsVersionCompatible {
1306
- result [ constraint. package ] = bound
1307
- } else {
1308
- // Get the dependencies at this version.
1309
- if let currentDependencies = try ? self . underlying. getDependencies ( at: version, productFilter: products) {
1310
- // Record this version as the bound for our list of dependencies, if appropriate.
1311
- if currentDependencies. first ( where: { $0. package == constraint. package } ) != constraint {
1312
- result [ constraint. package ] = bound
1308
+ for constraint in constraints {
1309
+ for constraintNode in constraint. nodes ( ) where !result. keys. contains ( constraintNode) {
1310
+ // If we hit a version which doesn't have a compatible tools version then that's the boundary.
1311
+ // Record the bound if the tools version isn't compatible at the current version.
1312
+ if !isToolsVersionCompatible {
1313
+ result [ constraintNode] = bound
1314
+ } else {
1315
+ // Get the dependencies at this version.
1316
+ if let currentDependencies = try ? self . underlying. getDependencies ( at: version, productFilter: constraintNode. productFilter) {
1317
+ // Record this version as the bound for our list of dependencies, if appropriate.
1318
+ if currentDependencies. first ( where: { $0. package == constraint. package } ) != constraint {
1319
+ result [ constraintNode] = bound
1320
+ }
1313
1321
}
1314
1322
}
1315
1323
}
@@ -1334,12 +1342,12 @@ private final class PubGrubPackageContainer {
1334
1342
1335
1343
let sync = DispatchGroup ( )
1336
1344
1337
- var upperBounds = [ PackageReference : Version] ( )
1345
+ var upperBounds = [ DependencyResolutionNode : Version] ( )
1338
1346
DispatchQueue . sharedConcurrent. async ( group: sync) {
1339
1347
upperBounds = compute ( Array ( versions. dropFirst ( idx + 1 ) ) , upperBound: true )
1340
1348
}
1341
1349
1342
- var lowerBounds = [ PackageReference : Version] ( )
1350
+ var lowerBounds = [ DependencyResolutionNode : Version] ( )
1343
1351
DispatchQueue . sharedConcurrent. async ( group: sync) {
1344
1352
lowerBounds = compute ( Array ( versions. dropLast ( versions. count - idx) . reversed ( ) ) , upperBound: false )
1345
1353
}
0 commit comments