diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f709af37f..e8f6c840248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ Swift Next Swift 6.0 ----------- +* [#7741] + + Fixed an issue where repositories would be re-cloned each build rather than using the cache due to git validation errors. + * [#7507] `swift experimental-sdk` command is deprecated with `swift sdk` command replacing it. `--experimental-swift-sdk` and diff --git a/Sources/Commands/PackageCommands/ArchiveSource.swift b/Sources/Commands/PackageCommands/ArchiveSource.swift index 01d2b7695ef..3c55008cf28 100644 --- a/Sources/Commands/PackageCommands/ArchiveSource.swift +++ b/Sources/Commands/PackageCommands/ArchiveSource.swift @@ -66,8 +66,7 @@ extension SwiftPackageCommand { cancellator: Cancellator? ) throws { let gitRepositoryProvider = GitRepositoryProvider() - if gitRepositoryProvider.repositoryExists(at: packageDirectory) && - (try? gitRepositoryProvider.isValidDirectory(packageDirectory)) == true { + if (try? gitRepositoryProvider.isValidDirectory(packageDirectory)) == true { let repository = GitRepository(path: packageDirectory, cancellator: cancellator) try repository.archive(to: archivePath) } else { diff --git a/Sources/PackageModel/PackageIdentity.swift b/Sources/PackageModel/PackageIdentity.swift index d34aca1a797..54f53a35da7 100644 --- a/Sources/PackageModel/PackageIdentity.swift +++ b/Sources/PackageModel/PackageIdentity.swift @@ -480,6 +480,7 @@ private func computeCanonicalLocation(_ string: String) -> (description: String, // Prepend a leading slash for file URLs and paths if detectedScheme == "file" || string.first.flatMap(isSeparator) ?? false { + scheme = "file" description.insert("/", at: description.startIndex) } diff --git a/Sources/SourceControl/GitRepository.swift b/Sources/SourceControl/GitRepository.swift index 1d8a8f7e09b..feccd0dccb2 100644 --- a/Sources/SourceControl/GitRepository.swift +++ b/Sources/SourceControl/GitRepository.swift @@ -15,6 +15,8 @@ import Basics import Dispatch import class Foundation.NSLock +import struct PackageModel.CanonicalPackageURL + import struct TSCBasic.ByteString import protocol TSCBasic.DiagnosticLocation import struct TSCBasic.FileInfo @@ -201,10 +203,6 @@ public struct GitRepositoryProvider: RepositoryProvider, Cancellable { ) } - public func repositoryExists(at directory: Basics.AbsolutePath) -> Bool { - return localFileSystem.isDirectory(directory) - } - public func isValidDirectory(_ directory: Basics.AbsolutePath) throws -> Bool { let result = try self.git.run(["-C", directory.pathString, "rev-parse", "--git-dir"]) return result == ".git" || result == "." || result == directory.pathString @@ -212,7 +210,7 @@ public struct GitRepositoryProvider: RepositoryProvider, Cancellable { public func isValidDirectory(_ directory: Basics.AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { let remoteURL = try self.git.run(["-C", directory.pathString, "config", "--get", "remote.origin.url"]) - return remoteURL == repository.url + return CanonicalPackageURL(remoteURL) == CanonicalPackageURL(repository.url) } public func copy(from sourcePath: Basics.AbsolutePath, to destinationPath: Basics.AbsolutePath) throws { diff --git a/Sources/SourceControl/Repository.swift b/Sources/SourceControl/Repository.swift index 0f4bd4eaf75..a86227b7271 100644 --- a/Sources/SourceControl/Repository.swift +++ b/Sources/SourceControl/Repository.swift @@ -89,9 +89,6 @@ public protocol RepositoryProvider: Cancellable { /// - Throws: If there is any error fetching the repository. func fetch(repository: RepositorySpecifier, to path: AbsolutePath, progressHandler: FetchProgress.Handler?) throws - /// Returns true if a repository exists at `path` - func repositoryExists(at path: AbsolutePath) throws -> Bool - /// Open the given repository. /// /// - Parameters: diff --git a/Sources/SourceControl/RepositoryManager.swift b/Sources/SourceControl/RepositoryManager.swift index eee9a3e077b..2acc271b2b9 100644 --- a/Sources/SourceControl/RepositoryManager.swift +++ b/Sources/SourceControl/RepositoryManager.swift @@ -220,7 +220,7 @@ public class RepositoryManager: Cancellable { // check if a repository already exists // errors when trying to check if a repository already exists are legitimate // and recoverable, and as such can be ignored - quick: if (try? self.provider.repositoryExists(at: repositoryPath)) ?? false { + quick: if (try? self.provider.isValidDirectory(repositoryPath)) ?? false { let repository = try handle.open() guard ((try? self.provider.isValidDirectory(repositoryPath, for: repositorySpecifier)) ?? false) else { diff --git a/Sources/_InternalTestSupport/InMemoryGitRepository.swift b/Sources/_InternalTestSupport/InMemoryGitRepository.swift index c7fc4c4abba..6de8a0eec0a 100644 --- a/Sources/_InternalTestSupport/InMemoryGitRepository.swift +++ b/Sources/_InternalTestSupport/InMemoryGitRepository.swift @@ -14,6 +14,7 @@ import Basics import Dispatch import Foundation import SourceControl +import struct PackageModel.CanonicalPackageURL import struct TSCBasic.ByteString import enum TSCBasic.FileMode @@ -68,7 +69,7 @@ public final class InMemoryGitRepository { fileprivate let path: AbsolutePath /// The file system in which this repository should be installed. - private let fs: InMemoryFileSystem + fileprivate let fs: InMemoryFileSystem private let lock = NSLock() @@ -438,10 +439,6 @@ public final class InMemoryGitRepositoryProvider: RepositoryProvider { add(specifier: RepositorySpecifier(path: path), repository: repo) } - public func repositoryExists(at path: AbsolutePath) throws -> Bool { - return fetchedMap[path] != nil - } - public func copy(from sourcePath: AbsolutePath, to destinationPath: AbsolutePath) throws { guard let repo = fetchedMap[sourcePath] else { throw InternalError("unknown repo at \(sourcePath)") @@ -482,11 +479,11 @@ public final class InMemoryGitRepositoryProvider: RepositoryProvider { } public func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - return true + return fetchedMap[directory] != nil || specifierMap.get().values.map(\.path).contains(directory) } public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { - return true + return fetchedMap[directory] != nil || specifierMap[repository] != nil } public func cancel(deadline: DispatchTime) throws { diff --git a/Tests/SourceControlTests/GitRepositoryProviderTests.swift b/Tests/SourceControlTests/GitRepositoryProviderTests.swift index 4c2699a809d..7c032eef297 100644 --- a/Tests/SourceControlTests/GitRepositoryProviderTests.swift +++ b/Tests/SourceControlTests/GitRepositoryProviderTests.swift @@ -16,7 +16,7 @@ import _InternalTestSupport import XCTest class GitRepositoryProviderTests: XCTestCase { - func testRepositoryExists() throws { + func testIsValidDirectory() throws { try testWithTemporaryDirectory { sandbox in let provider = GitRepositoryProvider() @@ -24,20 +24,20 @@ class GitRepositoryProviderTests: XCTestCase { let repositoryPath = sandbox.appending("test") try localFileSystem.createDirectory(repositoryPath) initGitRepo(repositoryPath) - XCTAssertTrue(provider.repositoryExists(at: repositoryPath)) + XCTAssertTrue(try provider.isValidDirectory(repositoryPath)) // no-checkout bare repository let noCheckoutRepositoryPath = sandbox.appending("test-no-checkout") try localFileSystem.copy(from: repositoryPath.appending(".git"), to: noCheckoutRepositoryPath) - XCTAssertTrue(provider.repositoryExists(at: noCheckoutRepositoryPath)) + XCTAssertTrue(try provider.isValidDirectory(noCheckoutRepositoryPath)) // non-git directory let notGitPath = sandbox.appending("test-not-git") - XCTAssertFalse(provider.repositoryExists(at: notGitPath)) + XCTAssertThrowsError(try provider.isValidDirectory(notGitPath)) // non-git child directory of a git directory let notGitChildPath = repositoryPath.appending("test-not-git") - XCTAssertFalse(provider.repositoryExists(at: notGitChildPath)) + XCTAssertThrowsError(try provider.isValidDirectory(notGitChildPath)) } } } diff --git a/Tests/SourceControlTests/GitRepositoryTests.swift b/Tests/SourceControlTests/GitRepositoryTests.swift index 3ab25a71f65..5dc0a57ab5c 100644 --- a/Tests/SourceControlTests/GitRepositoryTests.swift +++ b/Tests/SourceControlTests/GitRepositoryTests.swift @@ -768,4 +768,142 @@ class GitRepositoryTests: XCTestCase { XCTAssertNoThrow(try checkoutRepo.getCurrentRevision()) } } + + func testValidDirectoryLocalRelativeOrigin() async throws { + try testWithTemporaryDirectory { tmpDir in + // Create a repository. + let packageDir = tmpDir.appending("SomePackage") + try localFileSystem.createDirectory(packageDir) + + // Create a repository manager for it. + let repoProvider = GitRepositoryProvider() + let repositoryManager = RepositoryManager( + fileSystem: localFileSystem, + path: packageDir, + provider: repoProvider, + delegate: .none + ) + + let customRemote = "../OriginOfSomePackage.git" + + // Before initializing the directory with a git repo, it is never valid. + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir)) + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString)))) + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemote)))) + + initGitRepo(packageDir) + // Set the remote. + try systemQuietly([Git.tool, "-C", packageDir.pathString, "remote", "add", "origin", customRemote]) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir)) + + let customRemoteWithoutPathExtension = (customRemote as NSString).deletingPathExtension + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemote)))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemoteWithoutPathExtension)))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL((customRemote as NSString).deletingPathExtension + "/")))) + + // The following ensure that are actually checking the remote's origin. + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: AbsolutePath(validating: "/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString)))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir.appending(extension: "git")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString.appending(".git"))))) + + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("https://mycustomdomain/some-package.git")))) + } + } + + func testValidDirectoryLocalAbsoluteOrigin() async throws { + try testWithTemporaryDirectory { tmpDir in + // Create a repository. + let packageDir = tmpDir.appending("SomePackage") + try localFileSystem.createDirectory(packageDir) + + // Create a repository manager for it. + let repoProvider = GitRepositoryProvider() + let repositoryManager = RepositoryManager( + fileSystem: localFileSystem, + path: packageDir, + provider: repoProvider, + delegate: .none + ) + + let customRemote = tmpDir.appending("OriginOfSomePackage.git") + + // Before initializing the directory with a git repo, it is never valid. + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir)) + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString)))) + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemote.pathString)))) + + initGitRepo(packageDir) + // Set the remote. + try systemQuietly([Git.tool, "-C", packageDir.pathString, "remote", "add", "origin", customRemote.pathString]) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir)) + + let customRemotePath = customRemote.pathString + let customRemotePathWithoutPathExtension = (customRemotePath as NSString).deletingPathExtension + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: customRemote))) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemotePath)))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: try AbsolutePath(validating: customRemotePathWithoutPathExtension)))) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemotePathWithoutPathExtension)))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: try AbsolutePath(validating: customRemotePathWithoutPathExtension + "/")))) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL((customRemotePath as NSString).deletingPathExtension + "/")))) + + // The following ensure that are actually checking the remote's origin. + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: AbsolutePath(validating: "/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString)))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir.appending(extension: "git")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString.appending(".git"))))) + + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("https://mycustomdomain/some-package.git")))) + } + } + + func testValidDirectoryRemoteOrigin() async throws { + try testWithTemporaryDirectory { tmpDir in + // Create a repository. + let packageDir = tmpDir.appending("SomePackage") + try localFileSystem.createDirectory(packageDir) + + // Create a repository manager for it. + let repoProvider = GitRepositoryProvider() + let repositoryManager = RepositoryManager( + fileSystem: localFileSystem, + path: packageDir, + provider: repoProvider, + delegate: .none + ) + + let customRemote = try XCTUnwrap(URL(string: "https://mycustomdomain/some-package.git")) + + // Before initializing the directory with a git repo, it is never valid. + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir)) + XCTAssertThrowsError(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemote)))) + + initGitRepo(packageDir) + // Set the remote. + try systemQuietly([Git.tool, "-C", packageDir.pathString, "remote", "add", "origin", customRemote.absoluteString]) + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir)) + + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(customRemote)))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("https://mycustomdomain/some-package")))) + // We consider the directory valid even if the remote does not have the same path extension - in this case we expected '.git'. + XCTAssertTrue(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("https://mycustomdomain/some-package/")))) + + // The following ensure that are actually checking the remote's origin. + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: AbsolutePath(validating: "/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL("/")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString)))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(path: packageDir.appending(extension: "git")))) + XCTAssertFalse(try repositoryManager.isValidDirectory(packageDir, for: RepositorySpecifier(url: SourceControlURL(packageDir.pathString.appending(".git"))))) + } + } } diff --git a/Tests/SourceControlTests/RepositoryManagerTests.swift b/Tests/SourceControlTests/RepositoryManagerTests.swift index 00381fd9367..31ae7369764 100644 --- a/Tests/SourceControlTests/RepositoryManagerTests.swift +++ b/Tests/SourceControlTests/RepositoryManagerTests.swift @@ -347,7 +347,8 @@ class RepositoryManagerTests: XCTestCase { provider: provider, delegate: delegate ) - let dummyRepo = RepositorySpecifier(path: "/dummy") + let dummyRepoPath = try AbsolutePath(validating: "/dummy") + let dummyRepo = RepositorySpecifier(path: dummyRepoPath) let results = ThreadSafeKeyValueStore() let concurrency = 10000 @@ -356,7 +357,7 @@ class RepositoryManagerTests: XCTestCase { group.addTask { delegate.prepare(fetchExpected: index == 0, updateExpected: index > 0) results[index] = try await manager.lookup( - package: .init(url: SourceControlURL(dummyRepo.url)), + package: PackageIdentity(path: dummyRepoPath), repository: dummyRepo, updateStrategy: .always, observabilityScope: observability.topScope, @@ -453,11 +454,12 @@ class RepositoryManagerTests: XCTestCase { let finishGroup = DispatchGroup() let results = ThreadSafeKeyValueStore>() for index in 0 ..< total { - let repository = RepositorySpecifier(path: try .init(validating: "/repo/\(index)")) + let path = try AbsolutePath(validating: "/repo/\(index)") + let repository = RepositorySpecifier(path: path) provider.startGroup.enter() finishGroup.enter() manager.lookup( - package: .init(urlString: repository.url), + package: PackageIdentity(path: path), repository: repository, updateStrategy: .never, observabilityScope: observability.topScope, @@ -528,10 +530,6 @@ class RepositoryManagerTests: XCTestCase { print("\(repository) okay") } - func repositoryExists(at path: AbsolutePath) throws -> Bool { - return false - } - func open(repository: RepositorySpecifier, at path: AbsolutePath) throws -> Repository { fatalError("should not be called") } @@ -553,7 +551,7 @@ class RepositoryManagerTests: XCTestCase { } func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - fatalError("should not be called") + return false } public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { @@ -606,11 +604,6 @@ class RepositoryManagerTests: XCTestCase { self.fetch += 1 } - func repositoryExists(at path: AbsolutePath) throws -> Bool { - // the directory exists - return true - } - func open(repository: RepositorySpecifier, at path: AbsolutePath) throws -> Repository { return MockRepository() } @@ -632,7 +625,8 @@ class RepositoryManagerTests: XCTestCase { } func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - fatalError("should not be called") + // the directory exists + return true } public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { @@ -663,14 +657,6 @@ class RepositoryManagerTests: XCTestCase { fatalError("unexpected API call") } - func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - fatalError("unexpected API call") - } - - public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { - fatalError("unexpected API call") - } - func fetch() throws { // noop } @@ -752,16 +738,12 @@ private class DummyRepositoryProvider: RepositoryProvider { } // We only support one dummy URL. - let basename = (repository.url as NSString).lastPathComponent + let basename = repository.basename if basename != "dummy" { throw DummyError.invalidRepository } } - public func repositoryExists(at path: AbsolutePath) throws -> Bool { - return self.fileSystem.isDirectory(path) - } - func copy(from sourcePath: AbsolutePath, to destinationPath: AbsolutePath) throws { try self.fileSystem.copy(from: sourcePath, to: destinationPath) @@ -795,7 +777,7 @@ private class DummyRepositoryProvider: RepositoryProvider { } func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - return true + return self.fileSystem.isDirectory(directory) } func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { @@ -976,14 +958,6 @@ fileprivate class DummyRepository: Repository { fatalError("unexpected API call") } - func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - fatalError("unexpected API call") - } - - public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { - fatalError("unexpected API call") - } - func fetch() throws { self.provider.increaseFetchCount() } diff --git a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift index f21afdb77ec..abc5395e39a 100644 --- a/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift +++ b/Tests/WorkspaceTests/SourceControlPackageContainerTests.swift @@ -89,74 +89,6 @@ private class MockRepository: Repository { } } -private class MockRepositories: RepositoryProvider { - /// The known repositories, as a map of URL to repository. - let repositories: [RepositorySpecifier.Location: MockRepository] - var fetchRepositories = ThreadSafeKeyValueStore() - - /// A mock manifest loader for all repositories. - let manifestLoader: MockManifestLoader - - init(repositories repositoryList: [MockRepository]) { - var allManifests: [MockManifestLoader.Key: Manifest] = [:] - var repositories: [RepositorySpecifier.Location: MockRepository] = [:] - for repository in repositoryList { - assert(repositories.index(forKey: repository.location) == nil) - repositories[repository.location] = repository - for (version, manifest) in repository.versions { - allManifests[MockManifestLoader.Key(url: repository.location.description, version: version)] = manifest - } - } - - self.repositories = repositories - self.manifestLoader = MockManifestLoader(manifests: allManifests) - } - - func fetch(repository: RepositorySpecifier, to path: AbsolutePath, progressHandler: FetchProgress.Handler? = nil) throws { - assert(self.repositories.index(forKey: repository.location) != nil) - self.fetchRepositories[repository] = path - } - - func repositoryExists(at path: AbsolutePath) throws -> Bool { - self.fetchRepositories.get().contains(where: { key, value in value == path }) - } - - func copy(from sourcePath: AbsolutePath, to destinationPath: AbsolutePath) throws { - // No-op. - } - - func workingCopyExists(at path: AbsolutePath) throws -> Bool { - return false - } - - func open(repository: RepositorySpecifier, at path: AbsolutePath) throws -> Repository { - guard let repository = self.repositories[repository.location] else { - throw InternalError("unknown repository at \(repository.location)") - } - return repository - } - - func createWorkingCopy(repository: RepositorySpecifier, sourcePath: AbsolutePath, at destinationPath: AbsolutePath, editable: Bool) throws -> WorkingCheckout { - fatalError("unexpected API call") - } - - func openWorkingCopy(at path: AbsolutePath) throws -> WorkingCheckout { - fatalError("unexpected API call") - } - - func isValidDirectory(_ directory: AbsolutePath) throws -> Bool { - return true - } - - public func isValidDirectory(_ directory: AbsolutePath, for repository: RepositorySpecifier) throws -> Bool { - return true - } - - func cancel(deadline: DispatchTime) throws { - // noop - } -} - private class MockRepositoryManagerDelegate: RepositoryManager.Delegate { var fetched = ThreadSafeArrayStore() var updated = ThreadSafeArrayStore()