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 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 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 GetOthersModifiedAndDeletedExcludingStandardFilesAsList(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) { List results = []; Task 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 GetOthersModifiedAndDeletedExcludingStandardFiles(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) { List results = []; List 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 RemoteRemove(string repositoryDirectory, string name, CancellationToken cancellationToken) { List results = []; Task 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 RemoteAdd(string repositoryDirectory, string name, string url, CancellationToken cancellationToken) { List results = []; Task 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 PushBranch(string repositoryDirectory, string remote, string name, CancellationToken cancellationToken) { List results = []; Task 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); } }