/// <summary> /// Updates local copies of the files. /// </summary> /// <param name="filesToCommit">Files to update locally</param> /// <param name="repoUri">Base path of the repo</param> /// <param name="branch">Unused</param> /// <param name="commitMessage">Unused</param> /// <returns></returns> public async Task CommitFilesAsync(List <GitFile> filesToCommit, string repoUri, string branch, string commitMessage) { string repoDir = LocalHelpers.GetRootDir(_gitExecutable, _logger); try { using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir)) { foreach (GitFile file in filesToCommit) { switch (file.Operation) { case GitFileOperation.Add: string parentDirectory = Directory.GetParent(file.FilePath).FullName; if (!Directory.Exists(parentDirectory)) { Directory.CreateDirectory(parentDirectory); } string fullPath = Path.Combine(repoUri, file.FilePath); using (var streamWriter = new StreamWriter(fullPath)) { string finalContent; switch (file.ContentEncoding) { case ContentEncoding.Utf8: finalContent = file.Content; break; case ContentEncoding.Base64: byte[] bytes = Convert.FromBase64String(file.Content); finalContent = Encoding.UTF8.GetString(bytes); break; default: throw new DarcException($"Unknown file content encoding {file.ContentEncoding}"); } finalContent = NormalizeLineEndings(fullPath, finalContent); await streamWriter.WriteAsync(finalContent); LibGit2SharpHelpers.AddFileToIndex(localRepo, file, fullPath, _logger); } break; case GitFileOperation.Delete: if (File.Exists(file.FilePath)) { File.Delete(file.FilePath); } break; } } } } catch (Exception exc) { throw new DarcException($"Something went wrong when checking out {repoUri} in {repoDir}", exc); } }
/// <summary> /// Clone a remote git repo. /// </summary> /// <param name="repoUri">Repository uri to clone</param> /// <param name="commit">Branch, commit, or tag to checkout</param> /// <param name="targetDirectory">Target directory to clone to</param> /// <param name="gitDirectory">Location for the .git directory, or null for default</param> /// <returns></returns> protected void Clone(string repoUri, string commit, string targetDirectory, ILogger _logger, string pat, string gitDirectory) { string dotnetMaestro = "dotnet-maestro"; LibGit2Sharp.CloneOptions cloneOptions = new LibGit2Sharp.CloneOptions { Checkout = false, CredentialsProvider = (url, user, cred) => new LibGit2Sharp.UsernamePasswordCredentials { // The PAT is actually the only thing that matters here, the username // will be ignored. Username = dotnetMaestro, Password = pat }, }; using (_logger.BeginScope("Cloning {repoUri} to {targetDirectory}", repoUri, targetDirectory)) { try { _logger.LogDebug($"Cloning {repoUri} to {targetDirectory}"); string repoPath = LibGit2Sharp.Repository.Clone( repoUri, targetDirectory, cloneOptions); LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions { CheckoutModifiers = LibGit2Sharp.CheckoutModifiers.Force, }; _logger.LogDebug($"Reading local repo from {repoPath}"); using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoPath)) { if (commit == null) { commit = localRepo.Head.Reference.TargetIdentifier; _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} has no commit to clone at, assuming it's {commit}"); } _logger.LogDebug($"Attempting to checkout {commit} as commit in {localRepo.Info.WorkingDirectory}"); LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger); } // LibGit2Sharp doesn't support a --git-dir equivalent yet (https://github.com/libgit2/libgit2sharp/issues/1467), so we do this manually if (gitDirectory != null) { Directory.Move(repoPath, gitDirectory); File.WriteAllText(repoPath.TrimEnd('\\', '/'), $"gitdir: {gitDirectory}"); } using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(targetDirectory)) { CheckoutSubmodules(localRepo, cloneOptions, gitDirectory, _logger); } } catch (Exception exc) { throw new Exception($"Something went wrong when cloning repo {repoUri} at {commit ?? "<default branch>"} into {targetDirectory}", exc); } } }
/// <summary> /// Checkout the repo to the specified state. /// </summary> /// <param name="commit">Tag, branch, or commit to checkout.</param> public void Checkout(string repoDir, string commit, bool force = false) { using (_logger.BeginScope("Checking out {commit}", commit ?? "default commit")) { _logger.LogDebug($"Checking out {commit}", commit ?? "default commit"); LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions { CheckoutModifiers = force ? LibGit2Sharp.CheckoutModifiers.Force : LibGit2Sharp.CheckoutModifiers.None, }; try { _logger.LogDebug($"Checking out {commit ?? "default commit"}"); _logger.LogDebug($"Reading local repo from {repoDir}"); using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir)) { if (commit == null) { commit = localRepo.Head.Reference.TargetIdentifier; _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} default commit to checkout is {commit}"); } try { _logger.LogDebug($"Attempting to check out {commit} in {repoDir}"); LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger); if (force) { CleanRepoAndSubmodules(localRepo, _logger); } } catch (LibGit2Sharp.NotFoundException) { _logger.LogWarning($"Couldn't find commit {commit} in {repoDir} locally. Attempting fetch."); try { foreach (LibGit2Sharp.Remote r in localRepo.Network.Remotes) { IEnumerable <string> refSpecs = r.FetchRefSpecs.Select(x => x.Specification); _logger.LogDebug($"Fetching {string.Join(";", refSpecs)} from {r.Url} in {repoDir}"); try { LibGit2Sharp.Commands.Fetch(localRepo, r.Name, refSpecs, new LibGit2Sharp.FetchOptions(), $"Fetching from {r.Url}"); } catch { _logger.LogWarning($"Fetching failed, are you offline or missing a remote?"); } } _logger.LogDebug($"After fetch, attempting to checkout {commit} in {repoDir}"); LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger); if (force) { CleanRepoAndSubmodules(localRepo, _logger); } } catch // Most likely network exception, could also be no remotes. We can't do anything about any error here. { _logger.LogError($"After fetch, still couldn't find commit or treeish {commit} in {repoDir}. Are you offline or missing a remote?"); throw; } } } } catch (Exception exc) { throw new Exception($"Something went wrong when checking out {commit} in {repoDir}", exc); } } }