diff --git a/src/ModuleCore/Git/GitManager.cs b/src/ModuleCore/Git/GitManager.cs index 8b2b6f4..cfdf2d8 100644 --- a/src/ModuleCore/Git/GitManager.cs +++ b/src/ModuleCore/Git/GitManager.cs @@ -145,6 +145,73 @@ public class GitManager throw new Exception($"No git repo has been registered with the name {registeredName}"); } + /// + /// Returns the git root directory for any nested directory if git rev-parse --show-toplevel returns a value. + /// + /// Path to check if it or any of its parents contain a git repository + /// + /// + /// Git fails to start, returns an error (ie: the directory is not in a git repo), or the git process does not return + /// any output or error. + /// + public static ParsedGitFolderDetails IsGitRepo(string path) + { + _debugWriterDelegate?.Invoke("Checking if current directory is a git repository..."); + + var ps = new ProcessStartInfo("git", + ["-C", path, "rev-parse", "--show-toplevel"]) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + // If the user doesn't have git on their path, this will throw an exception that I don't have to do anything + // special with, it'll be unhandled and powershell will handle it + var gitProcess = Process.Start(ps); + + // This probably shouldn't be possible? Not really sure of the conditions where the process could be started + // but return null, but I'm going to consider that unrecoverable error territory + if (gitProcess is null) + { + throw new Exception("git failed to start") + { + Source = "git-process", + }; + } + + gitProcess.WaitForExit(); + + if (!gitProcess.StandardOutput.EndOfStream) + { + var directory = gitProcess.StandardOutput.ReadToEnd(); + // Gotta trim what we get as it might already have a newline character at the end + var dirInfo = new DirectoryInfo(directory.Trim()); + + _debugWriterDelegate?.Invoke("...location is a git repo (duh)."); + + var repoFolderInfo = new ParsedGitFolderDetails + { + Directory = dirInfo.FullName, + Folder = dirInfo.Name, + }; + + return repoFolderInfo; + } + + if (!gitProcess.StandardError.EndOfStream) + { + throw new Exception(gitProcess.StandardError.ReadToEnd()) + { + Source = "git-not-found", + }; + } + + throw new Exception("Unable to determine if directory is repository: git command returned no output or errors.") + { + Source = "git-parse-failed", + }; + } + /// /// Registers an output for debug output. should be called as soon as the need for output /// is no longer needed. @@ -234,4 +301,20 @@ public class GitManager return _currentBranch.Trim(); } } +} + +/// +/// The directory details of the directory returned from git rev-parse --show-toplevel +/// +public class ParsedGitFolderDetails +{ + /// + /// The full path to the top level folder containing a git repository + /// + public string Directory { get; init; } = null!; + + /// + /// The last folder name of the directory + /// + public string Folder { get; init; } = null!; } \ No newline at end of file diff --git a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs index 29f629a..7204731 100644 --- a/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs +++ b/src/PowershellModule/Git/Commands/NewGitRepoCommand.cs @@ -17,95 +17,21 @@ public sealed class NewGitRepoCommand : PSCmdlet protected override void BeginProcessing() { - GitManager.SetDebugWriter(WriteDebug); - - var repoFolder = IsGitRepo(SessionState.Path.CurrentLocation.Path); - - if (repoFolder is not null) + try { + GitManager.SetDebugWriter(WriteDebug); + + var repoFolder = GitManager.IsGitRepo(SessionState.Path.CurrentLocation.Path); + GitManager.Instance.RegisterRepo(repoFolder.Directory, Name ?? repoFolder.Folder); + + GitManager.ClearDebugWriter(); + + base.BeginProcessing(); } - else + catch (Exception ex) { - // Not sure how we'd hit this path, but in case we do, show some sort of error. - // TODO: I should probably have IsGitRepo throw instead so I can get the location it tried in the stack track - WriteError(new ErrorRecord( - new Exception("Unable to register repo - failed to parse git repo location"), - "git-parse-failed", - ErrorCategory.InvalidData, - null - ) - ); + WriteError(new ErrorRecord(ex, ex.Source, ErrorCategory.FromStdErr, null)); } - - GitManager.ClearDebugWriter(); - - base.BeginProcessing(); - } - - private ParsedGitFolderDetails? IsGitRepo(string path) - { - WriteDebug("Checking if current directory is a git repository..."); - - var ps = new ProcessStartInfo("git", - ["-C", path, "rev-parse", "--show-toplevel"]) - { - RedirectStandardOutput = true, - RedirectStandardError = true, - }; - - // If the user doesn't have git on their path, this will throw an exception that I don't have to do anything - // special with, it'll be unhandled and powershell will handle it - var gitProcess = Process.Start(ps); - - // This probably shouldn't be possible? Not really sure of the conditions where the process could be started - // but return null, but I'm going to consider that unrecoverable error territory - if (gitProcess is null) - { - throw new Exception("git failed to start"); - } - - gitProcess.WaitForExit(); - - if (!gitProcess.StandardOutput.EndOfStream) - { - var directory = gitProcess.StandardOutput.ReadToEnd(); - // Gotta trim what we get as it might already have a newline character at the end - var dirInfo = new DirectoryInfo(directory.Trim()); - - WriteDebug("...location is a git repo (duh)."); - - var repoFolderInfo = new ParsedGitFolderDetails - { - Directory = dirInfo.FullName, - Folder = dirInfo.Name, - }; - - return repoFolderInfo; - } - - if (!gitProcess.StandardError.EndOfStream) - { - var errorAsException = new Exception(gitProcess.StandardError.ReadToEnd()); - WriteError(new ErrorRecord(errorAsException, "git-not-found", ErrorCategory.FromStdErr, null)); - } - - return null; - } - - /// - /// The directory details of the directory returned from git rev-parse --show-toplevel - /// - private class ParsedGitFolderDetails - { - /// - /// The full path to the top level folder containing a git repository - /// - public string Directory { get; init; } = null!; - - /// - /// The last folder name of the directory - /// - public string Folder { get; init; } = null!; } } \ No newline at end of file