@@ -815,7 +815,7 @@ extension Workspace {
815
815
let resolver = try self . createResolver ( pinsMap: pinsMap, observabilityScope: observabilityScope)
816
816
self . activeResolver = resolver
817
817
818
- let updateResults = resolveDependencies (
818
+ let updateResults = self . resolveDependencies (
819
819
resolver: resolver,
820
820
constraints: updateConstraints,
821
821
observabilityScope: observabilityScope
@@ -836,8 +836,8 @@ extension Workspace {
836
836
// Load the updated manifests.
837
837
let updatedDependencyManifests = try self . loadDependencyManifests ( root: graphRoot, observabilityScope: observabilityScope)
838
838
839
- // Update the pins store .
840
- self . pinAll (
839
+ // Update the resolved file .
840
+ self . saveResolvedFile (
841
841
pinsStore: pinsStore,
842
842
dependencyManifests: updatedDependencyManifests,
843
843
rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion,
@@ -1326,25 +1326,86 @@ extension Workspace {
1326
1326
// MARK: - Pinning Functions
1327
1327
1328
1328
extension Workspace {
1329
-
1330
1329
/// Pins all of the current managed dependencies at their checkout state.
1331
- fileprivate func pinAll (
1330
+ fileprivate func saveResolvedFile (
1332
1331
pinsStore: PinsStore ,
1333
1332
dependencyManifests: DependencyManifests ,
1334
1333
rootManifestsMinimumToolsVersion: ToolsVersion ,
1335
1334
observabilityScope: ObservabilityScope
1336
- ) {
1335
+ ) {
1336
+ var dependenciesToPin = [ ManagedDependency] ( )
1337
+ let requiredDependencies = dependencyManifests. computePackages ( ) . required. filter ( { $0. kind. isPinnable } )
1338
+ for dependency in requiredDependencies {
1339
+ if let managedDependency = self . state. dependencies [ comparingLocation: dependency] {
1340
+ dependenciesToPin. append ( managedDependency)
1341
+ } else {
1342
+ observabilityScope. emit ( warning: " required dependency \( dependency. identity) ( \( dependency. locationString) ) was not found in managed dependencies and will not be recorded in resolved file " )
1343
+ }
1344
+ }
1345
+
1346
+ // FIXME
1347
+ // load the pin store from disk so we can compare for any changes
1348
+ // this is needed as we want to avoid re-writing the resolved files
1349
+ // unless absolutely required
1350
+ guard let storedPinStore = observabilityScope. trap ( { try self . pinsStore. load ( ) } ) else {
1351
+ return
1352
+ }
1353
+
1354
+ // compare for any differences between the existing state and the stored one
1355
+ // subtle changes between versions of SwiftPM could treat URLs differently
1356
+ // in which case we dont want to cause unnecessary churn
1357
+ var needsUpdate = false
1358
+ if dependenciesToPin. count != storedPinStore. pinsMap. count {
1359
+ needsUpdate = true
1360
+ } else {
1361
+ for dependency in dependenciesToPin {
1362
+ if let pin = storedPinStore. pinsMap. first ( where: { $0. value. packageRef. equalsIncludingLocation ( dependency. packageRef) } ) {
1363
+ if pin. value. state != PinsStore . Pin ( dependency) ? . state {
1364
+ needsUpdate = true
1365
+ break
1366
+ }
1367
+ } else {
1368
+ needsUpdate = true
1369
+ break
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ // exist early is there is nothing to do
1375
+ guard needsUpdate else {
1376
+ return
1377
+ }
1378
+
1379
+ // reset the pinsStore and start pinning the required dependencies.
1380
+ pinsStore. unpinAll ( )
1381
+ for dependency in dependenciesToPin {
1382
+ pinsStore. pin ( dependency)
1383
+ }
1384
+
1385
+ /*
1337
1386
// Reset the pinsStore and start pinning the required dependencies.
1338
1387
pinsStore.unpinAll()
1339
1388
1389
+ let requiredDependencies = dependencyManifests.computePackages().required.filter({ $0.kind.isPinnable })
1390
+ for dependency in requiredDependencies {
1391
+ if let managedDependency = self.state.dependencies[comparingLocation: dependency] {
1392
+ pinsStore.pin(managedDependency)
1393
+ } else {
1394
+ observabilityScope.emit(warning: "required dependency \(dependency.identity) (\(dependency.locationString)) was not found in managed dependencies and will not be recorded in resolved file")
1395
+ }
1396
+ }
1397
+ */
1398
+
1399
+
1400
+ /*
1340
1401
let requiredDependencies = dependencyManifests.computePackages().required
1341
1402
for dependency in self.state.dependencies {
1342
1403
if requiredDependencies.contains(where: { $0.equalsIncludingLocation(dependency.packageRef) }) {
1343
1404
pinsStore.pin(dependency)
1344
1405
}
1345
- }
1406
+ }*/
1346
1407
1347
- observabilityScope. trap {
1408
+ observabilityScope. trap {
1348
1409
try pinsStore. saveState ( toolsVersion: rootManifestsMinimumToolsVersion)
1349
1410
}
1350
1411
@@ -1359,30 +1420,38 @@ fileprivate extension PinsStore {
1359
1420
///
1360
1421
/// This method does nothing if the dependency is in edited state.
1361
1422
func pin( _ dependency: Workspace . ManagedDependency ) {
1423
+ if let pin = PinsStore . Pin ( dependency) {
1424
+ self . add ( pin)
1425
+ }
1426
+ }
1427
+ }
1428
+
1429
+ fileprivate extension PinsStore . Pin {
1430
+ init ? ( _ dependency: Workspace . ManagedDependency ) {
1362
1431
switch dependency. state {
1363
1432
case . sourceControlCheckout( . version( let version, let revision) ) :
1364
- self . pin (
1433
+ self . init (
1365
1434
packageRef: dependency. packageRef,
1366
1435
state: . version( version, revision: revision. identifier)
1367
1436
)
1368
1437
case . sourceControlCheckout( . branch( let branch, let revision) ) :
1369
- self . pin (
1438
+ self . init (
1370
1439
packageRef: dependency. packageRef,
1371
1440
state: . branch( name: branch, revision: revision. identifier)
1372
1441
)
1373
1442
case . sourceControlCheckout( . revision( let revision) ) :
1374
- self . pin (
1443
+ self . init (
1375
1444
packageRef: dependency. packageRef,
1376
1445
state: . revision( revision. identifier)
1377
1446
)
1378
1447
case . registryDownload( let version) :
1379
- self . pin (
1448
+ self . init (
1380
1449
packageRef: dependency. packageRef,
1381
1450
state: . version( version, revision: . none)
1382
1451
)
1383
1452
case . edited, . fileSystem, . custom:
1384
1453
// NOOP
1385
- break
1454
+ return nil
1386
1455
}
1387
1456
}
1388
1457
}
@@ -1398,7 +1467,7 @@ extension Workspace {
1398
1467
/// The dependency manifests in the transitive closure of root manifest.
1399
1468
let dependencies : [ ( manifest: Manifest , dependency: ManagedDependency , productFilter: ProductFilter , fileSystem: FileSystem ) ]
1400
1469
1401
- let workspace : Workspace
1470
+ private let workspace : Workspace
1402
1471
1403
1472
fileprivate init (
1404
1473
root: PackageGraphRoot ,
@@ -1649,7 +1718,7 @@ extension Workspace {
1649
1718
} )
1650
1719
1651
1720
// optimization: preload first level dependencies manifest (in parallel)
1652
- let firstLevelDependencies = topLevelManifests. values. map { $0. dependencies. map { $0. createPackageRef ( ) } } . flatMap { $0 }
1721
+ let firstLevelDependencies = topLevelManifests. values. map { $0. dependencies. map { $0. createPackageRef ( ) } } . flatMap ( { $0 } )
1653
1722
let firstLevelManifests = try temp_await { self . loadManagedManifests ( for: firstLevelDependencies, observabilityScope: observabilityScope, completion: $0) } // FIXME: this should not block
1654
1723
1655
1724
// Continue to load the rest of the manifest for this graph
@@ -1677,7 +1746,7 @@ extension Workspace {
1677
1746
// dependencies that have the same identity but from a different location
1678
1747
// which is an error case we diagnose an report about in the GraphLoading part which
1679
1748
// is prepared to handle the case where not all manifest are available
1680
- $0. packageLocation == dependency . locationString ?
1749
+ $0. packageLocation. caseInsensitiveCompare ( dependency . locationString ) == . orderedSame ?
1681
1750
KeyedPair ( $0, key: Key ( identity: dependency. identity, productFilter: dependency. productFilter) ) : nil
1682
1751
}
1683
1752
}
@@ -2524,10 +2593,18 @@ extension Workspace {
2524
2593
return currentManifests
2525
2594
}
2526
2595
2527
- self . validatePinsStore ( dependencyManifests: currentManifests, rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion, observabilityScope: observabilityScope)
2596
+ // load and update the pins store with any changes from loading the top level dependencies
2597
+ guard let pinsStore = self . loadAndUpdatePinsStore (
2598
+ dependencyManifests: currentManifests,
2599
+ rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion,
2600
+ observabilityScope: observabilityScope
2601
+ ) else {
2602
+ // abort if PinsStore reported any errors.
2603
+ return currentManifests
2604
+ }
2528
2605
2529
- // Abort if pinsStore is unloadable or if diagnostics has errors.
2530
- guard !observabilityScope. errorsReported, let pinsStore = observabilityScope . trap ( { try pinsStore . load ( ) } ) else {
2606
+ // abort if PinsStore reported any errors.
2607
+ guard !observabilityScope. errorsReported else {
2531
2608
return currentManifests
2532
2609
}
2533
2610
@@ -2551,6 +2628,15 @@ extension Workspace {
2551
2628
2552
2629
switch result {
2553
2630
case . notRequired:
2631
+ // since nothing changed we can exit early,
2632
+ // but need update resolved file and download an missing binary artifact
2633
+ self . saveResolvedFile (
2634
+ pinsStore: pinsStore,
2635
+ dependencyManifests: currentManifests,
2636
+ rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion,
2637
+ observabilityScope: observabilityScope
2638
+ )
2639
+
2554
2640
try self . updateBinaryArtifacts (
2555
2641
manifests: currentManifests,
2556
2642
addedOrUpdatedPackages: [ ] ,
@@ -2601,7 +2687,8 @@ extension Workspace {
2601
2687
return updatedDependencyManifests
2602
2688
}
2603
2689
2604
- self . pinAll (
2690
+ // Update the resolved file.
2691
+ self . saveResolvedFile (
2605
2692
pinsStore: pinsStore,
2606
2693
dependencyManifests: updatedDependencyManifests,
2607
2694
rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion,
@@ -2784,43 +2871,32 @@ extension Workspace {
2784
2871
}
2785
2872
2786
2873
/// Validates that each checked out managed dependency has an entry in pinsStore.
2787
- private func validatePinsStore (
2874
+ private func loadAndUpdatePinsStore (
2788
2875
dependencyManifests: DependencyManifests ,
2789
2876
rootManifestsMinimumToolsVersion: ToolsVersion ,
2790
2877
observabilityScope: ObservabilityScope
2791
- ) {
2792
- guard let pinsStore = observabilityScope. trap ( { try pinsStore. load ( ) } ) else {
2793
- return
2878
+ ) -> PinsStore ? {
2879
+ guard let pinsStore = observabilityScope. trap ( { try self . pinsStore. load ( ) } ) else {
2880
+ return nil
2794
2881
}
2795
2882
2796
- let pins = pinsStore. pinsMap. keys
2797
- let requiredDependencies = dependencyManifests. computePackages ( ) . required
2798
-
2799
- for dependency in self . state. dependencies {
2800
- switch dependency. state {
2801
- case . sourceControlCheckout, . registryDownload: break
2802
- case . edited, . fileSystem, . custom: continue
2803
- }
2804
-
2883
+ let requiredDependencies = dependencyManifests. computePackages ( ) . required. filter ( { $0. kind. isPinnable } )
2884
+ for dependency in self . state. dependencies. filter ( { $0. packageRef. kind. isPinnable } ) {
2885
+ // a required dependency that is already loaded (managed) should be represented in the pins store.
2805
2886
// also comparing location as it may have changed at this point
2806
2887
if requiredDependencies. contains ( where: { $0. equalsIncludingLocation ( dependency. packageRef) } ) {
2807
- // If required identity contains this dependency, it should be in the pins store.
2808
- // also comparing location as it may have changed at this point
2809
- if let pin = pinsStore . pinsMap [ dependency . packageRef. identity ] , pin . packageRef . equalsIncludingLocation ( dependency. packageRef) {
2810
- continue
2888
+ let pin = pinsStore . pinsMap [ dependency. packageRef . identity ]
2889
+ // if pin not found, or location is different ( it may have changed at this point) pin it
2890
+ if ! ( pin? . packageRef. equalsIncludingLocation ( dependency. packageRef) ?? false ) {
2891
+ pinsStore . pin ( dependency )
2811
2892
}
2812
- } else if !pins . contains ( dependency. packageRef. identity) {
2813
- // Otherwise , it should *not* be in the pins store.
2814
- continue
2893
+ } else if let pin = pinsStore . pinsMap [ dependency. packageRef. identity] {
2894
+ // otherwise , it should *not* be in the pins store.
2895
+ pinsStore . remove ( pin )
2815
2896
}
2816
-
2817
- return self . pinAll (
2818
- pinsStore: pinsStore,
2819
- dependencyManifests: dependencyManifests,
2820
- rootManifestsMinimumToolsVersion: rootManifestsMinimumToolsVersion,
2821
- observabilityScope: observabilityScope
2822
- )
2823
2897
}
2898
+
2899
+ return pinsStore
2824
2900
}
2825
2901
2826
2902
/// This enum represents state of an external package.
@@ -3296,6 +3372,8 @@ extension Workspace {
3296
3372
try workingCopy. checkout ( revision: checkoutState. revision)
3297
3373
try ? fileSystem. chmod ( . userUnWritable, path: checkoutPath, options: [ . recursive, . onlyFiles] )
3298
3374
3375
+ print ( " ********************* adding \( package . locationString) to managed deps " )
3376
+
3299
3377
// Write the state record.
3300
3378
self . state. dependencies. add (
3301
3379
try . sourceControlCheckout(
@@ -3557,6 +3635,17 @@ internal extension PackageReference {
3557
3635
}
3558
3636
}
3559
3637
3638
+ fileprivate extension PackageReference . Kind {
3639
+ var isPinnable : Bool {
3640
+ switch self {
3641
+ case . remoteSourceControl, . localSourceControl, . registry:
3642
+ return true
3643
+ default :
3644
+ return false
3645
+ }
3646
+ }
3647
+ }
3648
+
3560
3649
// FIXME: remove this when remove the single call site that uses it
3561
3650
fileprivate extension PackageDependency {
3562
3651
var isLocal : Bool {
0 commit comments