@@ -229,16 +229,11 @@ public class Workspace {
229
229
private let containerProvider : RepositoryPackageContainerProvider
230
230
231
231
/// The current state of managed dependencies.
232
- private ( set ) var dependencyMap : [ RepositorySpecifier : ManagedDependency ]
232
+ let managedDependencies : ManagedDependencies
233
233
234
234
/// Enable prefetching containers in resolver.
235
235
let enableResolverPrefetching : Bool
236
236
237
- /// The known set of dependencies.
238
- public var dependencies : AnySequence < ManagedDependency > {
239
- return AnySequence < ManagedDependency > ( dependencyMap. values)
240
- }
241
-
242
237
/// Create a new package workspace.
243
238
///
244
239
/// This will automatically load the persisted state for the package, if
@@ -282,19 +277,11 @@ public class Workspace {
282
277
repositoryManager: repositoryManager, manifestLoader: manifestLoader, toolsVersionLoader: toolsVersionLoader)
283
278
self . fileSystem = fileSystem
284
279
285
- // Initialize the default state.
286
- self . dependencyMap = [ : ]
287
-
288
280
self . pinsStore = try PinsStore ( pinsFile: pinsFile, fileSystem: self . fileSystem)
281
+ self . managedDependencies = try ManagedDependencies ( dataPath: dataPath, fileSystem: fileSystem)
289
282
290
283
// Ensure the cache path exists.
291
284
try createCacheDirectories ( )
292
-
293
- // Load the state from disk, if possible.
294
- if try ! restoreState( ) {
295
- // There was no state, write the default state immediately.
296
- try saveState ( )
297
- }
298
285
}
299
286
300
287
/// Create the cache directories.
@@ -327,7 +314,7 @@ public class Workspace {
327
314
let protectedAssets = Set < String > ( [
328
315
repositoryManager. path,
329
316
checkoutsPath,
330
- statePath,
317
+ managedDependencies . statePath,
331
318
] . map { path in
332
319
// Assert that these are present inside data directory.
333
320
assert ( path. parentDirectory == dataPath)
@@ -345,7 +332,7 @@ public class Workspace {
345
332
346
333
/// Resets the entire workspace by removing the data directory.
347
334
public func reset( ) throws {
348
- dependencyMap = [ : ]
335
+ managedDependencies . reset ( )
349
336
repositoryManager. reset ( )
350
337
fileSystem. removeFileTree ( dataPath)
351
338
try createCacheDirectories ( )
@@ -447,10 +434,10 @@ public class Workspace {
447
434
}
448
435
449
436
// Change its stated to edited.
450
- dependencyMap [ dependency. repository] = dependency. makingEditable (
437
+ managedDependencies [ dependency. repository] = dependency. makingEditable (
451
438
subpath: RelativePath ( packageName) , state: state)
452
439
// Save the state.
453
- try saveState ( )
440
+ try managedDependencies . saveState ( )
454
441
}
455
442
456
443
/// Ends the edit mode of a dependency which is in edit mode.
@@ -498,9 +485,9 @@ public class Workspace {
498
485
fileSystem. removeFileTree ( editablesPath)
499
486
}
500
487
// Restore the dependency state.
501
- dependencyMap [ dependency. repository] = dependency. basedOn
488
+ managedDependencies [ dependency. repository] = dependency. basedOn
502
489
// Save the state.
503
- try saveState ( )
490
+ try managedDependencies . saveState ( )
504
491
}
505
492
506
493
/// Pins a package at a given state.
@@ -558,7 +545,7 @@ public class Workspace {
558
545
try updateCheckouts ( with: results)
559
546
560
547
// Get the updated dependency.
561
- let newDependency = dependencyMap [ dependency. repository] !
548
+ let newDependency = managedDependencies [ dependency. repository] !
562
549
563
550
// Assert that the dependency is at the pinned checkout state now.
564
551
if case . checkout( let checkoutState) = newDependency. state {
@@ -629,7 +616,7 @@ public class Workspace {
629
616
/// - Throws: If the operation could not be satisfied.
630
617
private func fetch( repository: RepositorySpecifier ) throws -> AbsolutePath {
631
618
// If we already have it, fetch to update the repo from its remote.
632
- if let dependency = dependencyMap [ repository] {
619
+ if let dependency = managedDependencies [ repository] {
633
620
let path = checkoutsPath. appending ( dependency. subpath)
634
621
// Fetch the checkout in case there are updates available.
635
622
let workingRepo = try repositoryManager. provider. openCheckout ( at: path)
@@ -679,10 +666,10 @@ public class Workspace {
679
666
try workingRepo. checkout ( revision: checkoutState. revision)
680
667
681
668
// Write the state record.
682
- dependencyMap [ repository] = ManagedDependency (
669
+ managedDependencies [ repository] = ManagedDependency (
683
670
repository: repository, subpath: path. relative ( to: checkoutsPath) ,
684
671
checkoutState: checkoutState)
685
- try saveState ( )
672
+ try managedDependencies . saveState ( )
686
673
687
674
return path
688
675
}
@@ -773,7 +760,7 @@ public class Workspace {
773
760
// Otherwise, we need to repin only the previous pins.
774
761
for pin in pinsStore. pins {
775
762
// Check if this is a stray pin.
776
- guard let dependency = dependencyMap [ pin. repository] else {
763
+ guard let dependency = managedDependencies [ pin. repository] else {
777
764
// FIXME: Use diagnosics engine when we have that.
778
765
delegate. warning ( message: " Consider unpinning \( pin. package ) , it is pinned at \( pin. state. description) but the dependency is not present. " )
779
766
continue
@@ -832,7 +819,7 @@ public class Workspace {
832
819
case . unversioned:
833
820
// Right not it is only possible to get unversioned binding if
834
821
// a dependency is in editable state.
835
- assert ( dependencyMap [ specifier] ? . state. isCheckout == false )
822
+ assert ( managedDependencies [ specifier] ? . state. isCheckout == false )
836
823
packageStateChanges [ specifier] = . unchanged
837
824
838
825
case . revision( let identifier) :
@@ -850,7 +837,7 @@ public class Workspace {
850
837
}
851
838
852
839
// First check if we have this dependency.
853
- if let currentDependency = dependencyMap [ specifier] {
840
+ if let currentDependency = managedDependencies [ specifier] {
854
841
// If current state and new state are equal, we don't need
855
842
// to do anything.
856
843
let newState = CheckoutState ( revision: revision, branch: branch)
@@ -865,7 +852,7 @@ public class Workspace {
865
852
}
866
853
867
854
case . version( let version) :
868
- if let currentDependency = dependencyMap [ specifier] {
855
+ if let currentDependency = managedDependencies [ specifier] {
869
856
if case . checkout( let checkoutState) = currentDependency. state, checkoutState. version == version {
870
857
packageStateChanges [ specifier] = . unchanged
871
858
} else {
@@ -877,6 +864,7 @@ public class Workspace {
877
864
}
878
865
}
879
866
// Set the state of any old package that might have been removed.
867
+ let dependencies = managedDependencies. values
880
868
for specifier in dependencies. lazy. map ( { $0. repository} ) where packageStateChanges [ specifier] == nil {
881
869
packageStateChanges [ specifier] = . removed
882
870
}
@@ -912,7 +900,7 @@ public class Workspace {
912
900
let dependencies = transitiveClosure ( rootManifests. map { KeyedPair ( $0, key: $0. url) } ) { node in
913
901
return node. item. package . dependencies. flatMap { dependency in
914
902
// Check if this dependency is available.
915
- guard let managedDependency = dependencyMap [ RepositorySpecifier ( url: dependency. url) ] else {
903
+ guard let managedDependency = managedDependencies [ RepositorySpecifier ( url: dependency. url) ] else {
916
904
return nil
917
905
}
918
906
@@ -954,15 +942,15 @@ public class Workspace {
954
942
return KeyedPair ( manifest, key: manifest. url)
955
943
}
956
944
}
957
-
958
- return DependencyManifests ( roots: rootManifests, dependencies: dependencies . map { ( $0 . item , dependencyMap [ RepositorySpecifier ( url : $0 . item . url ) ] ! ) } )
945
+ let deps = dependencies . map { ( $0 . item , managedDependencies [ $0 . item . url ] ! ) }
946
+ return DependencyManifests ( roots: rootManifests, dependencies: deps )
959
947
}
960
948
961
949
/// Validates that all the edited dependencies are still present in the file system.
962
950
/// If some edited dependency is removed from the file system, mark it as unedited and
963
951
/// fallback on the original checkout.
964
952
private func validateEditedPackages( ) throws {
965
- for dependency in dependencies {
953
+ for dependency in managedDependencies . values {
966
954
967
955
let dependencyPath : AbsolutePath
968
956
@@ -1067,7 +1055,7 @@ public class Workspace {
1067
1055
1068
1056
/// Removes the clone and checkout of the provided specifier.
1069
1057
func remove( specifier: RepositorySpecifier ) throws {
1070
- guard var dependency = dependencyMap [ specifier] else {
1058
+ guard var dependency = managedDependencies [ specifier] else {
1071
1059
fatalError ( " This should never happen, trying to remove \( specifier) which isn't in workspace " )
1072
1060
}
1073
1061
@@ -1085,7 +1073,7 @@ public class Workspace {
1085
1073
delegate. removing ( repository: dependency. repository. url)
1086
1074
1087
1075
// Remove the repository from dependencies.
1088
- dependencyMap [ dependency. repository] = nil
1076
+ managedDependencies [ dependency. repository] = nil
1089
1077
1090
1078
// Remove the checkout.
1091
1079
let dependencyPath = checkoutsPath. appending ( dependency. subpath)
@@ -1099,7 +1087,7 @@ public class Workspace {
1099
1087
try repositoryManager. remove ( repository: dependency. repository)
1100
1088
1101
1089
// Save the state.
1102
- try saveState ( )
1090
+ try managedDependencies . saveState ( )
1103
1091
}
1104
1092
1105
1093
/// Loads and returns the root manifests, if all manifests are loaded successfully.
@@ -1126,63 +1114,6 @@ public class Workspace {
1126
1114
package : $0, baseURL: $0. asString, manifestVersion: toolsVersion. manifestVersion)
1127
1115
}
1128
1116
}
1129
-
1130
- // MARK: Persistence
1131
-
1132
- // FIXME: A lot of the persistence mechanism here is copied from
1133
- // `RepositoryManager`. It would be nice to get actual infrastructure around
1134
- // persistence to handle the boilerplate parts.
1135
-
1136
- private enum PersistenceError : Swift . Error {
1137
- /// The schema does not match the current version.
1138
- case invalidVersion
1139
-
1140
- /// There was a missing or malformed key.
1141
- case unexpectedData
1142
- }
1143
-
1144
- /// The current schema version for the persisted information.
1145
- ///
1146
- /// We currently discard any restored state if we detect a schema change.
1147
- private static let currentSchemaVersion = 1
1148
-
1149
- /// The path at which we persist the manager state.
1150
- var statePath : AbsolutePath {
1151
- return dataPath. appending ( component: " workspace-state.json " )
1152
- }
1153
-
1154
- /// Restore the manager state from disk.
1155
- ///
1156
- /// - Throws: A PersistenceError if the state was available, but could not
1157
- /// be restored.
1158
- ///
1159
- /// - Returns: True if the state was restored, or false if the state wasn't
1160
- /// available.
1161
- private func restoreState( ) throws -> Bool {
1162
- // If the state doesn't exist, don't try to load and fail.
1163
- if !fileSystem. exists ( statePath) {
1164
- return false
1165
- }
1166
- // Load the state.
1167
- let json = try JSON ( bytes: try fileSystem. readFileContents ( statePath) )
1168
- guard try json. get ( " version " ) == Workspace . currentSchemaVersion else {
1169
- throw PersistenceError . invalidVersion
1170
- }
1171
- self . dependencyMap = try Dictionary ( items:
1172
- json. get ( " dependencies " ) . map { ( $0. repository, $0) }
1173
- )
1174
- return true
1175
- }
1176
-
1177
- /// Write the manager state to disk.
1178
- private func saveState( ) throws {
1179
- let data = JSON ( [
1180
- " version " : Workspace . currentSchemaVersion,
1181
- " dependencies " : dependencies. toJSON ( ) ,
1182
- ] )
1183
- // FIXME: This should write atomically.
1184
- try fileSystem. writeFileContents ( statePath, bytes: data. toBytes ( ) )
1185
- }
1186
1117
}
1187
1118
1188
1119
// FIXME: Lift these to Basic once proven useful.
0 commit comments