Skip to content

Commit 201243f

Browse files
neonichutgymnich
authored andcommitted
WIP shared repository cache
1 parent 9beff45 commit 201243f

File tree

3 files changed

+7
-112
lines changed

3 files changed

+7
-112
lines changed

Sources/SourceControl/RepositoryManager.swift

Lines changed: 6 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,6 @@ public class RepositoryManager {
113113
precondition(status == .available, "cloneCheckout() called in invalid state")
114114
try self.manager.cloneCheckout(self, to: path, editable: editable)
115115
}
116-
117-
fileprivate func toJSON() -> JSON {
118-
return .init([
119-
"status": status.rawValue,
120-
"repositoryURL": repository,
121-
"subpath": subpath,
122-
])
123-
}
124116
}
125117

126118
/// The path under which repositories are stored.
@@ -132,18 +124,6 @@ public class RepositoryManager {
132124
/// The delegate interface.
133125
private let delegate: RepositoryManagerDelegate?
134126

135-
// FIXME: We should use a more sophisticated map here, which tracks the
136-
// full specifier but then is capable of efficiently determining if two
137-
// repositories map to the same location.
138-
//
139-
/// The map of registered repositories.
140-
fileprivate var repositories: [String: RepositoryHandle] = [:]
141-
142-
/// The map of serialized repositories.
143-
///
144-
/// NOTE: This is to be used only for persistence support.
145-
fileprivate var serializedRepositories: [String: JSON] = [:]
146-
147127
/// Queue to protect concurrent reads and mutations to repositories registery.
148128
private let serialQueue = DispatchQueue(label: "org.swift.swiftpm.repomanagerqueue-serial")
149129

@@ -159,9 +139,6 @@ public class RepositoryManager {
159139
/// The filesystem to operate on.
160140
public let fileSystem: FileSystem
161141

162-
/// Simple persistence helper.
163-
private let persistence: SimplePersistence
164-
165142
/// Create a new empty manager.
166143
///
167144
/// - Parameters:
@@ -185,24 +162,6 @@ public class RepositoryManager {
185162
self.operationQueue = OperationQueue()
186163
self.operationQueue.name = "org.swift.swiftpm.repomanagerqueue-concurrent"
187164
self.operationQueue.maxConcurrentOperationCount = 10
188-
189-
self.persistence = SimplePersistence(
190-
fileSystem: fileSystem,
191-
schemaVersion: 1,
192-
statePath: path.appending(component: "checkouts-state.json"))
193-
194-
// Load the state from disk, if possible.
195-
do {
196-
_ = try self.persistence.restoreState(self)
197-
} catch {
198-
// State restoration errors are ignored, for now.
199-
//
200-
// FIXME: We need to do something better here.
201-
print("warning: unable to restore checkouts state: \(error)")
202-
203-
// Try to save the empty state.
204-
try? self.persistence.saveState(self)
205-
}
206165
}
207166

208167
/// Get a handle to a repository.
@@ -282,21 +241,6 @@ public class RepositoryManager {
282241
self.callbacksQueue.async {
283242
self.delegate?.fetchingDidFinish(handle: handle, error: fetchError)
284243
}
285-
286-
// Save the manager state.
287-
self.serialQueue.sync {
288-
do {
289-
// Update the serialized repositories map.
290-
//
291-
// We do this so we don't have to read the other
292-
// handles when saving the sate of this handle.
293-
self.serializedRepositories[repository.url] = handle.toJSON()
294-
try self.persistence.saveState(self)
295-
} catch {
296-
// FIXME: Handle failure gracefully, somehow.
297-
fatalError("unable to save manager state \(error)")
298-
}
299-
}
300244
}
301245
// Call the completion handler.
302246
self.callbacksQueue.async {
@@ -311,20 +255,11 @@ public class RepositoryManager {
311255
/// Note: This method is thread safe.
312256
private func getHandle(repository: RepositorySpecifier) -> RepositoryHandle {
313257
return serialQueue.sync {
314-
315-
// Reset if the state file was deleted during the lifetime of RepositoryManager.
316-
if !self.serializedRepositories.isEmpty && !self.persistence.stateFileExists() {
317-
self.unsafeReset()
318-
}
319-
320-
let handle: RepositoryHandle
321-
if let oldHandle = self.repositories[repository.url] {
322-
handle = oldHandle
323-
} else {
324-
let subpath = RelativePath(repository.fileSystemIdentifier)
325-
let newHandle = RepositoryHandle(manager: self, repository: repository, subpath: subpath)
326-
self.repositories[repository.url] = newHandle
327-
handle = newHandle
258+
let subpath = RelativePath(repository.fileSystemIdentifier)
259+
let handle = RepositoryHandle(manager: self, repository: repository, subpath: subpath)
260+
let repositoryPath = path.appending(RelativePath(repository.fileSystemIdentifier))
261+
if fileSystem.exists(repositoryPath) {
262+
handle.status = .available
328263
}
329264
return handle
330265
}
@@ -352,15 +287,8 @@ public class RepositoryManager {
352287
/// Removes the repository.
353288
public func remove(repository: RepositorySpecifier) throws {
354289
try serialQueue.sync {
355-
// If repository isn't present, we're done.
356-
guard let handle = repositories[repository.url] else {
357-
return
358-
}
359-
repositories[repository.url] = nil
360-
serializedRepositories[repository.url] = nil
361-
let repositoryPath = path.appending(handle.subpath)
290+
let repositoryPath = path.appending(RelativePath(repository.fileSystemIdentifier))
362291
try fileSystem.removeFileTree(repositoryPath)
363-
try self.persistence.saveState(self)
364292
}
365293
}
366294

@@ -375,31 +303,10 @@ public class RepositoryManager {
375303

376304
/// Performs the reset operation without the serial queue.
377305
private func unsafeReset() {
378-
self.repositories = [:]
379-
self.serializedRepositories = [:]
380306
try? self.fileSystem.removeFileTree(path)
381307
}
382308
}
383309

384-
// MARK: Persistence
385-
extension RepositoryManager: SimplePersistanceProtocol {
386-
387-
public func restore(from json: JSON) throws {
388-
// Update the serialized repositories.
389-
//
390-
// We will use this to save the state so we don't have to read the other
391-
// handles when saving the sate of a handle.
392-
self.serializedRepositories = try json.get("repositories")
393-
self.repositories = try serializedRepositories.mapValues({
394-
try RepositoryHandle(manager: self, json: $0)
395-
})
396-
}
397-
398-
public func toJSON() -> JSON {
399-
return JSON(["repositories": JSON(self.serializedRepositories)])
400-
}
401-
}
402-
403310
extension RepositoryManager.RepositoryHandle: CustomStringConvertible {
404311
public var description: String {
405312
return "<\(type(of: self)) subpath:\(subpath)>"

Sources/Workspace/Workspace.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ public class Workspace {
453453
self.resolvedFile = pinsFile
454454
self.additionalFileRules = additionalFileRules
455455

456-
let repositoriesPath = self.dataPath.appending(component: "repositories")
456+
let repositoriesPath = fileSystem.homeDirectory.appending(RelativePath("Library/Caches/SwiftPM/Repositories"))
457457
let repositoryManager = repositoryManager ?? RepositoryManager(
458458
path: repositoriesPath,
459459
provider: repositoryProvider,

Tests/SourceControlTests/RepositoryManagerTests.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,6 @@ class RepositoryManagerTests: XCTestCase {
217217
// Remove the repo.
218218
try manager.remove(repository: dummyRepo)
219219

220-
// Check removing the repo updates the persistent file.
221-
do {
222-
let checkoutsStateFile = path.appending(component: "checkouts-state.json")
223-
let jsonData = try JSON(bytes: localFileSystem.readFileContents(checkoutsStateFile))
224-
XCTAssertEqual(jsonData.dictionary?["object"]?.dictionary?["repositories"]?.dictionary?[dummyRepo.url], nil)
225-
}
226-
227220
// We should get a new handle now because we deleted the exisiting repository.
228221
XCTNonNil(prevHandle) {
229222
try XCTAssert($0 !== manager.lookupSynchronously(repository: dummyRepo))
@@ -293,7 +286,6 @@ class RepositoryManagerTests: XCTestCase {
293286
do {
294287
let delegate = DummyRepositoryManagerDelegate()
295288
var manager = RepositoryManager(path: path, provider: provider, delegate: delegate)
296-
try! localFileSystem.removeFileTree(path.appending(component: "checkouts-state.json"))
297289
manager = RepositoryManager(path: path, provider: provider, delegate: delegate)
298290
let dummyRepo = RepositorySpecifier(url: "dummy")
299291

@@ -386,10 +378,6 @@ class RepositoryManagerTests: XCTestCase {
386378
_ = try manager.lookupSynchronously(repository: dummyRepo)
387379
XCTAssertEqual(delegate.didFetch.count, 1)
388380

389-
// Delete the checkout state file.
390-
let stateFile = repos.appending(component: "checkouts-state.json")
391-
try localFileSystem.removeFileTree(stateFile)
392-
393381
// We should refetch the repository since we lost the state file.
394382
_ = try manager.lookupSynchronously(repository: dummyRepo)
395383
XCTAssertEqual(delegate.didFetch.count, 2)

0 commit comments

Comments
 (0)