public void TestInstallWithCache() { var packageMock = new Mock <IPackage>(); packageMock.Setup((o) => o.GetSourceReference()) .Returns("1234567890123456789012345678901234567890"); packageMock.Setup((o) => o.GetSourceUris()) .Returns(new[] { "https://example.com/bucket/bucket" }); packageMock.Setup((o) => o.GetSourceUri()) .Returns("https://example.com/bucket/bucket"); packageMock.Setup((o) => o.GetVersionPretty()) .Returns("dev-master"); var processMock = new Mock <IProcessExecutor>(); var expectedGitCommand = WinCompat("git --version"); processMock.Setup(expectedGitCommand, "git version 2.3.1"); var config = new Config(); SetupConfig(config); var cachePath = config.Get(Settings.CacheVcsDir) + $"/{CacheFileSystem.FormatCacheFolder("https://example.com/bucket/bucket")}/"; expectedGitCommand = WinCompat($"git clone --mirror 'https://example.com/bucket/bucket' '{cachePath}'"); processMock.Setup(expectedGitCommand, returnValue: () => { if (Directory.Exists(cachePath)) { Directory.Delete(cachePath, true); } Directory.CreateDirectory(cachePath); return(0); }); expectedGitCommand = WinCompat($"git clone --no-checkout '{cachePath}' 'bucketPath' --dissociate --reference '{cachePath}' && cd 'bucketPath' && git remote set-url origin 'https://example.com/bucket/bucket' && git remote add bucket 'https://example.com/bucket/bucket'"); processMock.Setup(expectedGitCommand); expectedGitCommand = WinCompat("git branch -r"); processMock.Setup(expectedGitCommand, expectedCwd: bucketPath); expectedGitCommand = WinCompat("git checkout master --"); processMock.Setup(expectedGitCommand, expectedCwd: bucketPath); expectedGitCommand = WinCompat("git reset --hard 1234567890123456789012345678901234567890 --"); processMock.Setup(expectedGitCommand, expectedCwd: bucketPath); var downloader = CreateDownloaderMock(config: config, process: processMock.Object); downloader.Install(packageMock.Object, "bucketPath"); processMock.VerifyAll(); }
/// <summary> /// Initializes a new instance of the <see cref="RepositoryBucket"/> class. /// </summary> public RepositoryBucket( ConfigRepositoryBucket configRepository, IIO io, Config config, ITransport transport = null, IEventDispatcher eventDispatcher = null, IVersionParser versionParser = null) { if (!Regex.IsMatch(configRepository.Uri, @"^[\w.]+\??://")) { // assume http as the default protocol configRepository.Uri = $"http://{configRepository.Uri}"; } configRepository.Uri = configRepository.Uri.TrimEnd('/'); if (configRepository.Uri.StartsWith("https?", StringComparison.OrdinalIgnoreCase)) { configRepository.Uri = $"https{configRepository.Uri.Substring(6)}"; uriIsIntelligent = true; } if (!Uri.TryCreate(configRepository.Uri, UriKind.RelativeOrAbsolute, out _)) { throw new ConfigException($"Invalid url given for Bucket repository: {configRepository.Uri}"); } // changes will not be applied to configRepository. uri = configRepository.Uri; // force url for gxpack.org to repo.gxpack.org // without converting other addresses. var match = Regex.Match(configRepository.Uri, @"^(?<proto>https?)://gxpack\.org/?$", RegexOptions.IgnoreCase); if (match.Success) { uri = $"{match.Groups["proto"].Value}://repo.gxpack.org"; } baseUri = Regex.Replace(uri, @"(?:/[^/\\\\]+\.json)?(?:[?#].*)?$", string.Empty).TrimEnd('/'); this.configRepository = configRepository; this.io = io; this.transport = transport ?? new TransportHttp(io, config); this.eventDispatcher = eventDispatcher; this.versionParser = versionParser ?? new BVersionParser(); var cacheDir = Path.Combine(config.Get(Settings.CacheDir), CacheFileSystem.FormatCacheFolder(uri)); cache = new CacheFileSystem(cacheDir, io, "a-z0-9.$~"); loader = new LoaderPackage(versionParser); providersByUid = new Dictionary <int, IPackage>(); }
/// <inheritdoc /> public override void Initialize() { string cacheUri; if (FileSystemLocal.IsLocalPath(Uri)) { Uri = Regex.Replace(Uri, @"[\\/]\.git/?$", string.Empty); repositoryDirectory = Uri; cacheUri = Path.GetFullPath(Uri); } else { var cacheVcsDir = Config.Get(Settings.CacheVcsDir); if (!CacheFileSystem.IsUsable(cacheVcsDir)) { throw new RuntimeException("DriverGit requires a usable cache directory, and it looks like you set it to be disabled."); } if (Regex.IsMatch("^ssh://[^@]+@[^:]+:[^0-9]+", Uri)) { throw new InvalidArgumentException($"The source URL {Uri} is invalid, ssh URLs should have a port number after \":\".{Environment.NewLine}Use ssh://[email protected]:22/path or just [email protected]:path if you do not want to provide a password or custom port."); } Git.CleanEnvironment(); var fileSystem = new FileSystemLocal($"{cacheVcsDir}/{CacheFileSystem.FormatCacheFolder(Uri)}/"); var git = new Git(IO, Config, Process, fileSystem); repositoryDirectory = fileSystem.Root; if (!git.SyncMirror(Uri, repositoryDirectory)) { IO.WriteError($"<error>Failed to update {Uri}, package information from this repository may be outdated</error>"); } cacheUri = Uri; } GetTags(); GetBranches(); cache = new CacheFileSystem($"{Config.Get(Settings.CacheRepoDir)}/{CacheFileSystem.FormatCacheFolder(cacheUri)}", IO); }
/// <inheritdoc /> protected override void DoInstall(IPackage package, string cwd, string uri) { Git.CleanEnvironment(); cwd = NormalizePath(cwd); var cachePath = Config.Get(Settings.CacheVcsDir) + $"/{CacheFileSystem.FormatCacheFolder(uri)}/"; var reference = package.GetSourceReference(); var flag = Platform.IsWindows ? "/D " : string.Empty; // --dissociate option is only available since git 2.3.0-rc0 var gitVersion = git.GetVersion(); var message = $"Cloning {GetShortHash(reference)}"; var command = $"git clone --no-checkout %uri% %path% && cd {flag}%path% && git remote add bucket %uri% && git fetch bucket"; if (!string.IsNullOrEmpty(gitVersion) && Comparator.GreaterThanOrEqual(gitVersion, "2.3.0-rc0") && CacheFileSystem.IsUsable(cachePath)) { IO.WriteError(string.Empty, true, Verbosities.Debug); IO.WriteError($" Cloning to cache at {ProcessExecutor.Escape(cachePath)}", true, Verbosities.Debug); try { git.FetchReferenceOrSyncMirror(uri, reference, cachePath); if (FileSystem.Exists(cachePath, FileSystemOptions.Directory)) { command = "git clone --no-checkout %cachePath% %path% --dissociate --reference %cachePath%" + $" && cd {flag}%path%" + " && git remote set-url origin %uri% && git remote add bucket %uri%"; message = $"Cloning {GetShortHash(reference)} from cache."; } } catch (RuntimeException) { // ignore runtime exception because this is an optimization solution. } } IO.WriteError(message); string CommandCallable(string authUri) { var template = command; template = template.Replace("%uri%", ProcessExecutor.Escape(authUri)); template = template.Replace("%path%", ProcessExecutor.Escape(cwd)); template = template.Replace("%cachePath%", ProcessExecutor.Escape(cachePath)); return(template); } git.ExecuteCommand(CommandCallable, uri, cwd, true); if (uri != package.GetSourceUri()) { UpdateOriginUri(package.GetSourceUri(), cwd); } else { SetPushUri(uri, cwd); } ExecuteUpdate(cwd, reference, package); }