using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using System.Text; using CliWrap; using Serilog; namespace Recyclarr.VersionControl; [SuppressMessage("Design", "CA1068:CancellationToken parameters must come last", Justification = "Doesn't mix well with `params` (which has to be at the end)")] public sealed class GitRepository : IGitRepository { private readonly ILogger _log; private readonly IGitPath _gitPath; private readonly IDirectoryInfo _workDir; public GitRepository(ILogger log, IGitPath gitPath, IDirectoryInfo workDir) { _log = log; _gitPath = gitPath; _workDir = workDir; } private Task RunGitCmd(CancellationToken token, params string[] args) { return RunGitCmd(token, (ICollection) args); } private async Task RunGitCmd(CancellationToken token, ICollection args) { _log.Debug("Executing git command with args: {Args}", args); var output = new StringBuilder(); var error = new StringBuilder(); _log.Debug("Using working directory: {Dir}", _workDir.FullName); _workDir.Create(); var cli = Cli.Wrap(_gitPath.Path) .WithArguments(args) .WithValidation(CommandResultValidation.None) .WithStandardOutputPipe(PipeTarget.ToStringBuilder(output)) .WithStandardErrorPipe(PipeTarget.ToStringBuilder(error)) .WithWorkingDirectory(_workDir.FullName); var result = await cli.ExecuteAsync(token); _log.Debug("Command Output: {Output}", output.ToString().Trim()); if (result.ExitCode != 0) { throw new GitCmdException(result.ExitCode, error.ToString()); } } public void Dispose() { // Nothing to do here } public async Task ForceCheckout(CancellationToken token, string branch) { await RunGitCmd(token, "checkout", "-f", branch); } public async Task Fetch(CancellationToken token, string remote = "origin") { await RunGitCmd(token, "fetch", remote); } public async Task Status(CancellationToken token) { await RunGitCmd(token, "status"); } public async Task ResetHard(CancellationToken token, string toBranchOrSha1) { await RunGitCmd(token, "reset", "--hard", toBranchOrSha1); } public async Task SetRemote(CancellationToken token, string name, Uri newUrl) { await RunGitCmd(token, "remote", "set-url", name, newUrl.ToString()); } public async Task Clone(CancellationToken token, Uri cloneUrl, string? branch = null, int depth = 0) { var args = new List {"clone"}; if (branch is not null) { args.AddRange(new[] {"-b", branch}); } if (depth != 0) { args.AddRange(new[] {"--depth", depth.ToString()}); } args.AddRange(new[] {cloneUrl.ToString(), "."}); await RunGitCmd(token, args); } }