using System.Collections.ObjectModel; using System.Diagnostics; using System.Text; namespace File_Folder_Helper.Helpers; internal static class HelperGit { private record ProcessResult(string Errors, int ExitCode, string Output); private static async Task<ProcessResult> RunProcessAsync(string application, string arguments, string workingDirectory, CancellationToken cancellationToken) { using Process process = new(); StringBuilder outputBuilder = new(); StringBuilder errorsBuilder = new(); process.StartInfo = new ProcessStartInfo { CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, FileName = application, Arguments = arguments, WorkingDirectory = workingDirectory, }; process.OutputDataReceived += (_, args) => outputBuilder.AppendLine(args.Data); process.ErrorDataReceived += (_, args) => errorsBuilder.AppendLine(args.Data); _ = process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); await process.WaitForExitAsync(cancellationToken); return new(errorsBuilder.ToString().Trim(), process.ExitCode, outputBuilder.ToString().Trim()); } private static async Task<string> RunAsync(string arguments, string workingDirectory, CancellationToken cancellationToken) { ProcessResult result = await RunProcessAsync("git", arguments, workingDirectory, cancellationToken); if (result.ExitCode != 0) throw new Exception($"{result.ExitCode} {result.Errors}"); return result.Output; } private static List<string> GetOthersModifiedAndDeletedExcludingStandardFilesAsList(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) { List<string> results = []; Task<string> task = RunAsync("ls-files --others --modified --deleted --exclude-standard", repositoryDirectory, cancellationToken); task.Wait(cancellationToken); string[] files = task.Result.Split("\r\n"); foreach (string file in files) { if (!usePathCombine) results.Add(file); else results.Add(Path.GetFullPath(Path.Combine(repositoryDirectory, file))); } return results; } internal static ReadOnlyCollection<string> GetOthersModifiedAndDeletedExcludingStandardFiles(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) { List<string> results = []; List<string> relativePathFiles; DirectoryInfo directoryInfo; bool usePathCombineInner = false; string checkDirectory = Path.Combine(repositoryDirectory, ".git"); if (Directory.Exists(checkDirectory)) results.AddRange(GetOthersModifiedAndDeletedExcludingStandardFilesAsList(repositoryDirectory, usePathCombine, cancellationToken)); string[] subdirectories = Directory.GetDirectories(repositoryDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string subdirectory in subdirectories) { directoryInfo = new(subdirectory); if (directoryInfo.LinkTarget is null) continue; checkDirectory = Path.Combine(directoryInfo.LinkTarget, ".git"); if (!Directory.Exists(checkDirectory)) continue; relativePathFiles = GetOthersModifiedAndDeletedExcludingStandardFilesAsList(directoryInfo.LinkTarget, usePathCombineInner, cancellationToken); foreach (string relativePathFile in relativePathFiles) results.Add(Path.GetFullPath(Path.Combine(subdirectory, relativePathFile))); } return new(results); } internal static ReadOnlyCollection<string> RemoteRemove(string repositoryDirectory, string name, CancellationToken cancellationToken) { List<string> results = []; Task<string> task = RunAsync($"remote rm {name}", repositoryDirectory, cancellationToken); task.Wait(cancellationToken); string[] lines = task.Result.Split("\r\n"); foreach (string line in lines) results.Add(line); return new(results); } internal static ReadOnlyCollection<string> RemoteAdd(string repositoryDirectory, string name, string url, CancellationToken cancellationToken) { List<string> results = []; Task<string> task = RunAsync($"remote add {name} {url}", repositoryDirectory, cancellationToken); task.Wait(cancellationToken); string[] lines = task.Result.Split("\r\n"); foreach (string line in lines) results.Add(line); return new(results); } internal static ReadOnlyCollection<string> PushBranch(string repositoryDirectory, string remote, string name, CancellationToken cancellationToken) { List<string> results = []; Task<string> task = RunAsync($"push {remote} {name}", repositoryDirectory, cancellationToken); task.Wait(cancellationToken); string[] lines = task.Result.Split("\r\n"); foreach (string line in lines) results.Add(line); return new(results); } }