Skip to content

Commit ba7a1d8

Browse files
committed
using file locks to protect the cache
1 parent a87bf21 commit ba7a1d8

File tree

1 file changed

+16
-7
lines changed

1 file changed

+16
-7
lines changed

Sources/SourceControl/GitRepository.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ public class GitRepositoryProvider: RepositoryProvider {
7373
/// Clones the git repository we want to cache into the cache directory if it does not already exist and returns it.
7474
/// If the repository is already cached we perfrom a fetch. In case the `RepositoryProvider`has no `cachePath` or an error occured while
7575
/// setting up the cache `nil` is returned.
76-
private func setupCacheIfNeeded(for repository: RepositorySpecifier) -> GitRepository? {
76+
private func setupCacheIfNeeded(for repository: RepositorySpecifier) throws -> GitRepository? {
7777
guard let cachePath = cachePath else { return nil }
7878
let repositoryPath = cachePath.appending(component: repository.fileSystemIdentifier)
7979

8080
do {
8181
let process: Process
8282

8383
if localFileSystem.exists(repositoryPath) {
84-
process = Process(args: Git.tool, "-C", cachePath.pathString, "fetch")
84+
process = Process(args: Git.tool, "-C", repositoryPath.pathString, "fetch")
8585
} else {
8686
try localFileSystem.createDirectory(repositoryPath, recursive: true)
8787
// We are cloning each repository into its own directory instead of using one large bare repository and
@@ -93,7 +93,10 @@ public class GitRepositoryProvider: RepositoryProvider {
9393
}
9494

9595
try processSet?.add(process)
96-
try process.checkNonZeroExit()
96+
let lock = FileLock(name: repository.fileSystemIdentifier, cachePath: cachePath)
97+
try lock.withLock {
98+
try process.checkNonZeroExit()
99+
}
97100
} catch {
98101
return nil
99102
}
@@ -118,11 +121,14 @@ public class GitRepositoryProvider: RepositoryProvider {
118121
for repository in repositories {
119122
let cacheSize = try localFileSystem.getDirectorySize(cachePath)
120123
guard cacheSize > desiredCacheSize else { break }
121-
try localFileSystem.removeFileTree(repository.path)
124+
let lock = FileLock(name: repository.path.basename, cachePath: cachePath)
125+
try lock.withLock {
126+
try localFileSystem.removeFileTree(repository.path)
127+
}
122128
}
123129
} catch {
124130
// The cache seems to be broken. Lets remove everything.
125-
try? localFileSystem.removeFileTree(cachePath)
131+
print("Error purging cache")
126132
}
127133
}
128134

@@ -139,14 +145,17 @@ public class GitRepositoryProvider: RepositoryProvider {
139145
// FIXME: We need infrastructure in this subsystem for reporting
140146
// status information.
141147

142-
if let cache = setupCacheIfNeeded(for: repository) {
148+
if let cachePath = cachePath, let cache = try setupCacheIfNeeded(for: repository) {
143149
// Clone the repository using the cache as a reference if possible.
144150
// Git objects are not shared (--dissociate) to avoid problems that might occur when the cache is
145151
// deleted or the package is copied somewhere it cannot reach the cache directory.
146152
let process = Process(args: Git.tool, "clone", "--mirror",
147153
cache.path.pathString, path.pathString, environment: Git.environment)
148154
try processSet?.add(process)
149-
try process.checkGitError(repository: repository)
155+
let lock = FileLock(name: cache.path.basename, cachePath: cachePath)
156+
try lock.withLock {
157+
try process.checkGitError(repository: repository)
158+
}
150159

151160
let clone = GitRepository(path: path, isWorkingRepo: false)
152161
// In destination repo remove the remote which will be pointing to the cached source repo.

0 commit comments

Comments
 (0)