-
Notifications
You must be signed in to change notification settings - Fork 323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Git command line changes for WSL #3893
Conversation
extensions/GitExtension/FileExplorerGitIntegration/Models/StatusCache.cs
Outdated
Show resolved
Hide resolved
extensions/GitExtension/FileExplorerGitIntegration/Models/StatusCache.cs
Outdated
Show resolved
Hide resolved
extensions/GitExtension/FileExplorerGitIntegration/Models/GitLocalRepositoryProviderFactory.cs
Outdated
Show resolved
Hide resolved
} | ||
|
||
var output = validateGitRootRepo.Output; | ||
if (output is null || output.Contains("fatal: not a git repository")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the string fatal: not a git repository
be in different languages? Should this be localized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got curious. This seems like a complicated question.
https://github.com/git/git/blob/master/po/README.md#marking-strings-for-translation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, it does not seem like the git output needs to be translated. The output is parsed to throw the right exception and eventually the error displayed to the user in Dev Home is localized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use the exit code of the process? I don't know if git.exe sets the exit code though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got curious. This seems like a complicated question. https://github.com/git/git/blob/master/po/README.md#marking-strings-for-translation
That's how the linux flavors of git do translation - I don't know all the details, but it seems to be more runtime-oriented and uses gettext
in contrast to how we provide translations in Windows land. There might be some other stuff they use on Windows, but at current, it doesn't appear to be active in most cases: git-for-windows/git#724
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use the exit code of the process? I don't know if git.exe sets the exit code though.
I agree that parsing the output for this specific message feels somewhat brittle. We can most likely rely on git returning a non-zero exit code for failure, but it doesn't return any specific error codes to tell us what the problem was. Can we check the exit code of the process and also return a failure if it is non-zero?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we check the exit code of the process and also return a failure if it is non-zero?
Incorporated in latest changes. Thanks!
} | ||
|
||
var output = validateGitRootRepo.Output; | ||
if (output is null || output.Contains("fatal: not a git repository")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got curious. This seems like a complicated question.
https://github.com/git/git/blob/master/po/README.md#marking-strings-for-translation
extensions/GitExtension/FileExplorerGitIntegration/Models/RepositoryWrapper.cs
Outdated
Show resolved
Hide resolved
extensions/GitExtension/FileExplorerGitIntegration/Models/RepositoryWrapper.cs
Outdated
Show resolved
Hide resolved
extensions/GitExtension/FileExplorerGitIntegration/Models/RepositoryWrapper.cs
Outdated
Show resolved
Hide resolved
_log.Error("GitLocalRepositoryProviderFactory", "Failed to create GitLocalRepository", libGitEx); | ||
return new GetLocalRepositoryResult(libGitEx, _stringResource.GetLocalized("RepositoryNotFound"), $"Message: {libGitEx.Message} and HRESULT: {libGitEx.HResult}"); | ||
_log.Error(ex, "GitLocalRepositoryProviderFactory: Failed to create GitLocalRepository"); | ||
return new GetLocalRepositoryResult(ex, _stringResource.GetLocalized("RepositoryNotFound"), $"Message: {ex.Message} and HRESULT: {ex.HResult}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe this needs to be changed? Do we still tell the user "Repo not found"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository
not found.
|
||
if (process.ExitCode != 0) | ||
{ | ||
Log.Error("Execute Git process exited unsuccessfully with exit code {ExitCode}", process.ExitCode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
Log.Error("Execute Git process exited unsuccessfully with exit code {ExitCode}", process.ExitCode); | |
Log.Error($"Execute Git process exited unsuccessfully with exit code {process.ExitCode}"); |
if (WslIntegrator.IsWSLRepo(rootFolder)) | ||
{ | ||
var normalizedLinuxPath = WslIntegrator.GetNormalizedLinuxPath(rootFolder); | ||
if (output.TrimEnd('\n') != normalizedLinuxPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Should we get Env.NewLine or do we want to hard code \n here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Env.NewLine
is correct because this is for WSL. WIndows and Linux have different line endings. I'm afraid that Env.NewLine
is the windows definition of a line ending.
EDIT: Unless this only applies to file endings and not line endings.
public GitCommandRunnerResultInfo(ProviderOperationStatus status, string? output) | ||
{ | ||
Status = status; | ||
Output = output; | ||
} | ||
|
||
public GitCommandRunnerResultInfo(ProviderOperationStatus status, string? displayMessage, string? diagnosticText, Exception? ex, string? args) | ||
public GitCommandRunnerResultInfo(ProviderOperationStatus status, string? output, string? displayMessage, string? diagnosticText, Exception? ex, string? args, int? processExitCode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With so many nullable parameters can you split the constructor into multiple constructors so callers can more easily use this object.
I don't like calling constructors with multiple nullable parameters because the constructor does not tell me what combination of values ill throw an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding more constructors instead of more nullable parameters.
if (process.ExitCode != 0) | ||
{ | ||
Log.Error("Execute Git process exited unsuccessfully with exit code {ExitCode}", process.ExitCode); | ||
return new GitCommandRunnerResultInfo(ProviderOperationStatus.Failure, output, "Execute Git process exited unsuccessfully", string.Empty, null, arguments, process.ExitCode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: exited with a failure error code
"Exit unsuccessfully" tells me that the process was unsuccessful in exiting.
Log.Error("Execute Git process exited unsuccessfully with exit code {ExitCode}", process.ExitCode); | ||
return new GitCommandRunnerResultInfo(ProviderOperationStatus.Failure, output, "Execute Git process exited unsuccessfully", string.Empty, null, arguments, process.ExitCode); | ||
} | ||
|
||
return new GitCommandRunnerResultInfo(ProviderOperationStatus.Success, output); | ||
} | ||
else | ||
{ | ||
Log.Error("Failed to start the Git process: process is null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: remove process is null
The definition of a null process is one that did not start.
} | ||
catch (Exception ex) | ||
{ | ||
_log.Error("GitLocalRepositoryProviderFactory", "Failed to create GitLocalRepository", ex); | ||
_log.Error(ex, "GitLocalRepositoryProviderFactory: Failed to create GitLocalRepository"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: nameof(GitLocalRepository)
private Commit? _head; | ||
private readonly ILogger _log = Log.ForContext("SourceContext", nameof(RepositoryWrapper)); | ||
|
||
private string? _head; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline.
public void ValidateGitRepositoryRootPath(string rootFolder) | ||
{ | ||
var validateGitRootRepo = GitExecute.ExecuteGitCommand(_gitDetect.GitConfiguration.ReadInstallPath(), rootFolder, "rev-parse --show-toplevel"); | ||
var output = validateGitRootRepo.Output; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename output
to a name that describes the string. Maybe GitRootRepositoryPath
?
throw validateGitRootRepo.Ex ?? new ArgumentException($"Not a valid git repository root path: RootFolder: {rootFolder} Git output: {output}"); | ||
} | ||
|
||
if (WslIntegrator.IsWSLRepo(rootFolder)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the validation code and error reposting is the same. Maybe pull the call to get a normalized path and the error string into their own if block.
Then the error path check and error reporting can be de-duped.
var result = GitExecute.ExecuteGitCommand(_gitDetect.GitConfiguration.ReadInstallPath(), _workingDirectory, "rev-parse HEAD"); | ||
if (result.Status != ProviderOperationStatus.Success) | ||
{ | ||
throw result.Ex ?? new InvalidOperationException(result.ProcessExitCode?.ToString(CultureInfo.InvariantCulture) ?? "Unknown error while obtaining HEAD commit"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we provide any information to the user instead of "Unknown error while obtaining HEAD commit"? Maybe a call to action. Can they check logs somewhere else?
var result = GitExecute.ExecuteGitCommand(_gitDetect.GitConfiguration.ReadInstallPath(), _workingDirectory, "rev-parse HEAD"); | ||
if (result.Status != ProviderOperationStatus.Success) | ||
{ | ||
throw result.Ex ?? new InvalidOperationException(result.ProcessExitCode?.ToString(CultureInfo.InvariantCulture) ?? "Unknown error while obtaining HEAD commit"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed twice a check if the extension is not null. I thought the exception is always not null if the status is not success.
string? head = result.Output?.Trim(); | ||
if (string.IsNullOrEmpty(head)) | ||
{ | ||
throw new InvalidOperationException("Git command output is null or the repository has no commits"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No way to distinguish between a null value and a repo with no commits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A repository with no commits is a valid repository state.
string.Format(CultureInfo.CurrentCulture, _folderStatusDetached, _repo.Head.Tip.Sha[..7]) : | ||
string.Format(CultureInfo.CurrentCulture, _folderStatusBranch, _repo.Head.FriendlyName); | ||
if (_repo.Head.IsTracking) | ||
branchName = repoStatus.IsHeadDetached ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: rename repoStatus
to repositoryStatus
Thanks a lot for reviewing, everyone! I went through the PR comments and did not find any blocking issues. To speed up the selfhost of this functionality, I will go ahead and wrap up this PR now. I will be sure to address the minor suggestions in a future PR. |
Summary of the pull request
This PR contains the last set of changes to allow file explorer integration of a WSL git repository. It does this by using WSL command line to obtain all property information from git.
References and relevant issues
#3829
Detailed description of the pull request / Additional comments
This PR:
Note: This PR removes LibGit2Sharp usage where applicable and other unused library using statements. However, it does not completely clean usage of LibGit2Sharp library as the enum definitions from this library are being relied on such as FIleStatus etc. A separate bug has been created to track the complete removal of LibGit2Sharp from the git extension project (i.e. Create custom enum definitions for FileStatus, SubmoduleStatus to remove LibGit2Sharp dependency from git extension project · Issue #3894 · microsoft/devhome (github.com)). This improvement is not blocking to this PR.
Validation steps performed
Build of msix package
Unit Testing
Validation of functionality in VM
PR checklist