Skip to content

Commit

Permalink
GitExecute changes for WSL (#3839)
Browse files Browse the repository at this point in the history
* GitExecute changes for WSL

* address PR comments

* incorporate feedback

* incorporate feedback continued

* address PR feedback

* changes
  • Loading branch information
ssparach authored Sep 19, 2024
1 parent 51815ec commit c60dc85
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Diagnostics;
using FileExplorerGitIntegration.Models;

namespace FileExplorerGitIntegration.UnitTest;

[TestClass]
public class WslIntegratorUnitTests
{
[TestMethod]
[DataRow(@"\\wsl$\Ubuntu-20.04\home\user\repo")]
[DataRow(@"\\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"\\wsl$\Ubuntu\home\user\repo")]
[DataRow(@"\\wsl.localhost\Ubuntu\home\user\repo")]
[DataRow(@"\\wsl.localhost\Debian\home\user\repo")]
[DataRow(@"\\wsl$\kali-linux\home\user\repo")]
[DataRow(@"\\wsl$\Ubuntu-18.04\home\user\testRepo")]
[DataRow(@"\\wsl.localhost\Ubuntu-18.04\home\user\testRepo")]
[DataRow(@"\\WSL.LOCALHOST\Ubuntu-18.04\home\user\testRepo")]
[DataRow(@"\\WSL$\Ubuntu-18.04\home\user\testRepo")]
[DataRow(@"\\WsL.loCaLHoST\Ubuntu-18.04\home\user\testRepo")]
[DataRow(@"\\WsL$\Ubuntu-18.04\home\user\testRepo")]
public void IsWSLRepoPositiveTests(string repositoryPath)
{
Assert.IsTrue(WslIntegrator.IsWSLRepo(repositoryPath));
}

[TestMethod]
[DataRow(@"//wsl$/kali-linux/home/user/repo")]
[DataRow(@"C:\Users\foo\bar")]
[DataRow(@"\\wsl$*\Ubuntu\home\user\repo")]
[DataRow(@"D:\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"\\wsl.test\Ubuntu\home\user\repo")]
[DataRow("")]
[DataRow(@"\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"wsl$\Ubuntu-20.04\home\user\repo")]
public void IsWslRepoNegativeTests(string repositoryPath)
{
Assert.IsFalse(WslIntegrator.IsWSLRepo(repositoryPath));
}

[TestMethod]
[DataRow(@"\\wsl$\Ubuntu-20.04\home\user\repo", "Ubuntu-20.04")]
[DataRow(@"\\wsl.localhost\Ubuntu-20.04\home\user\repo", "Ubuntu-20.04")]
[DataRow(@"\\wsl$\Debian\home\user\repo", "Debian")]
[DataRow(@"\\wsl.localhost\kali-linux\home\user\repo", "kali-linux")]
[DataRow(@"\\wsl.localhost\UbuntuTest\home\user\testRepo", "UbuntuTest")]
[DataRow(@"\\wsl$\CustomDistribution\home\user\testRepo", "CustomDistribution")]
public void GetDistributionNamePositiveTest(string repositoryPath, string value)
{
var distributionName = WslIntegrator.GetWslDistributionName(repositoryPath);
Assert.AreEqual(value, distributionName);
}

[TestMethod]
[DataRow(@"C:\Distribution\home\user\testRepo")]
[DataRow(@"\\Ubuntu-18.04\wsl$\home\user\testRepo")]
[DataRow(@"wslg\Ubuntu-18.04\wsl.localhost\home\user\testRepo")]
[DataRow("")]
[DataRow(@"\\wsl$")]
[DataRow(@"\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"wsl$\Ubuntu-20.04\home\user\repo")]
public void GetDistributionNameNegativeTest(string repositoryPath)
{
Trace.Listeners.Clear();
Assert.ThrowsException<ArgumentException>(() => WslIntegrator.GetWslDistributionName(repositoryPath));
}

[TestMethod]
[DataRow(@"\\wsl$\Ubuntu-20.04\home\user\repo", @"\\wsl$\Ubuntu-20.04\home\user\repo")]
[DataRow(@"\\wsl.localhost\Ubuntu-20.04\home\user\repo", @"\\wsl$\Ubuntu-20.04\home\user\repo")]
[DataRow(@"\\wsl$\Debian\home\user\repo", @"\\wsl$\Debian\home\user\repo")]
[DataRow(@"\\wsl.localhost\kali-linux\home\user\repo", @"\\wsl$\kali-linux\home\user\repo")]
[DataRow(@"\\wsl.localhost\customDistribution\home\user\testRepo", @"\\wsl$\customDistribution\home\user\testRepo")]
[DataRow(@"\\wsl$\Ubuntu-18.04\home\user\dir1\dir2\DIR3\testRepo", @"\\wsl$\Ubuntu-18.04\home\user\dir1\dir2\DIR3\testRepo")]
public void GetWorkingDirectoryPositiveTest(string repositoryPath, string value)
{
var workingDirPath = WslIntegrator.GetWorkingDirectory(repositoryPath);
Assert.AreEqual(value, workingDirPath);
}

[TestMethod]
[DataRow(@"C:\Distribution\home\user\testRepo")]
[DataRow(@"\\Ubuntu-18.04\wsl$\home\user\testRepo")]
[DataRow(@"wslg\Ubuntu-18.04\wsl.localhost\home\user\testRepo")]
[DataRow("")]
[DataRow(@"\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"wsl$\Ubuntu-20.04\home\user\repo")]
public void GetWorkingDirectoryNegativeTest(string repositoryPath)
{
Trace.Listeners.Clear();
Assert.ThrowsException<ArgumentException>(() => WslIntegrator.GetWorkingDirectory(repositoryPath));
}

[TestMethod]
[DataRow(@"\\wsl$\Ubuntu-20.04\home\user\repo", "-d Ubuntu-20.04 git ")]
[DataRow(@"\\wsl.localhost\Ubuntu-20.04\home\user\repo", "-d Ubuntu-20.04 git ")]
[DataRow(@"\\wsl$\Debian\home\user\repo", "-d Debian git ")]
[DataRow(@"\\wsl.localhost\kali-linux\home\user\repo", "-d kali-linux git ")]
[DataRow(@"\\wsl$\Ubuntu-18.04\home\user\testRepo", "-d Ubuntu-18.04 git ")]
[DataRow(@"\\wsl.localhost\Ubuntu-18.04\home\user\testRepo", "-d Ubuntu-18.04 git ")]
[DataRow(@"\\wsl.localhost\CustomDistribution\home\user\testRepo", "-d CustomDistribution git ")]
public void GetArgumentPrefixForWslPositiveTest(string repositoryPath, string value)
{
var prefix = WslIntegrator.GetArgumentPrefixForWsl(repositoryPath);
Assert.AreEqual(value, prefix);
}

[TestMethod]
[DataRow("")]
[DataRow(@"\\wsl.localhost")]
[DataRow(@"C:\Users\foo\bar")]
[DataRow(@"\wsl.localhost\Ubuntu-20.04\home\user\repo")]
[DataRow(@"wsl$\Ubuntu-20.04\home\user\repo")]
public void GetArgumentPrefixForWslNegativeTest(string repositoryPath)
{
Trace.Listeners.Clear();
Assert.ThrowsException<ArgumentException>(() => WslIntegrator.GetArgumentPrefixForWsl(repositoryPath));
}

[TestMethod]
[DataRow(@"\\wsl$\Ubuntu-20.04\home\user\repo", "/home/user/repo")]
[DataRow(@"\\wsl.localhost\Ubuntu-20.04\home\user\repo", "/home/user/repo")]
[DataRow(@"\\wsl$\Debian\home\user\repo", "/home/user/repo")]
[DataRow(@"\\wsl.localhost\kali-linux\home\user\repo", "/home/user/repo")]
[DataRow(@"\\WSL.LOCALHOST\UBUNTU-18.04\HOME\USER\TESTREPO", "/HOME/USER/TESTREPO")]
[DataRow(@"\\WSL$\UBUNTU-18.04\HOME\USER\TESTREPO", "/HOME/USER/TESTREPO")]
[DataRow(@"\\WSL.LOCALHOST\UBUNTU-18.04\HoME\USeR\TeSTREpO", "/HoME/USeR/TeSTREpO")]
[DataRow(@"\\wsl.localhost\kali-linux\home\user\dir1\dir2\dir3\dir4\repo", "/home/user/dir1/dir2/dir3/dir4/repo")]
[DataRow("", "")]
public void GetNormalizedLinuxPathTest(string repositoryPath, string value)
{
var normalizedPath = WslIntegrator.GetNormalizedLinuxPath(repositoryPath);
Assert.AreEqual(value, normalizedPath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,25 @@ public static GitCommandRunnerResultInfo ExecuteGitCommand(string gitApplication
{
try
{
var processStartInfo = new ProcessStartInfo
var processStartInfo = new ProcessStartInfo();
if (!WslIntegrator.IsWSLRepo(repositoryDirectory))
{
FileName = gitApplication,
Arguments = arguments,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = repositoryDirectory ?? string.Empty,
StandardOutputEncoding = System.Text.Encoding.UTF8,
};
processStartInfo.FileName = gitApplication;
processStartInfo.Arguments = arguments;
processStartInfo.WorkingDirectory = repositoryDirectory;
}
else
{
Log.Information("Wsl.exe will be invoked to obtain property information from git");
processStartInfo.FileName = "wsl";
processStartInfo.Arguments = string.Concat(WslIntegrator.GetArgumentPrefixForWsl(repositoryDirectory), arguments);
processStartInfo.WorkingDirectory = WslIntegrator.GetWorkingDirectory(repositoryDirectory);
}

processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
processStartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;

using var process = Process.Start(processStartInfo);
if (process != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Diagnostics;
using Serilog;

namespace FileExplorerGitIntegration.Models;

public class WslIntegrator
{
private static readonly string[] _wslPathPrefixes = { @"\\wsl$\", @"\\wsl.localhost\" };
private static readonly ILogger _log = Log.ForContext<WslIntegrator>();

public static bool IsWSLRepo(string repositoryPath)
{
if (string.IsNullOrEmpty(repositoryPath))
{
_log.Debug($"The repository path is empty");
return false;
}

if (repositoryPath.Contains(Path.AltDirectorySeparatorChar))
{
_log.Debug($"The repository path is not in the expected format: {repositoryPath}");
return false;
}

// Check if the repository path contains any of the WSL path prefixes
foreach (string prefix in _wslPathPrefixes)
{
if (repositoryPath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

_log.Debug(repositoryPath + " is not a WSL path");
return false;
}

public static string GetWslDistributionName(string repositoryPath)
{
if (string.IsNullOrEmpty(repositoryPath))
{
_log.Debug("The repository path is empty");
throw new ArgumentException("Repository path is empty");
}

Debug.Assert(IsWSLRepo(repositoryPath), "the repository path must be a valid wsl path");
if (!IsWSLRepo(repositoryPath))
{
throw new ArgumentException($"Not a valid WSL path: {repositoryPath}");
}

// Parse the repository path to get the distribution name
string[] pathParts = repositoryPath.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);
if (pathParts.Length > 1)
{
return pathParts[1];
}

_log.Debug($"Failed to get the distribution name from the repository path: {repositoryPath}");
throw new ArgumentException("Failed to get the distribution name from the repository path");
}

public static string GetWorkingDirectory(string repositoryPath)
{
if (string.IsNullOrEmpty(repositoryPath))
{
throw new ArgumentException("Repository path is empty");
}

Debug.Assert(IsWSLRepo(repositoryPath), "the repository path must be a valid wsl path");
if (!IsWSLRepo(repositoryPath))
{
throw new ArgumentException($"Not a valid WSL path: {repositoryPath}");
}

string[] pathParts = repositoryPath.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);

// Ensure the first part is replaced with "\\wsl$"
if (pathParts.Length > 0)
{
pathParts[0] = Path.DirectorySeparatorChar + "\\wsl$";
}

var workingDirPath = string.Join(Path.DirectorySeparatorChar.ToString(), pathParts);
return workingDirPath;
}

public static string GetNormalizedLinuxPath(string repositoryPath)
{
if (string.IsNullOrEmpty(repositoryPath))
{
_log.Debug("The repository path is empty");
return string.Empty;
}

string[] pathParts = repositoryPath.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);
var workingDirPath = string.Join(Path.DirectorySeparatorChar.ToString(), pathParts.Skip(2));
workingDirPath = workingDirPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
workingDirPath = workingDirPath.Insert(0, Path.AltDirectorySeparatorChar.ToString());
return workingDirPath;
}

public static string GetArgumentPrefixForWsl(string repositoryPath)
{
if (string.IsNullOrEmpty(repositoryPath))
{
throw new ArgumentException("Repository path is empty");
}

Debug.Assert(IsWSLRepo(repositoryPath), "the repository path must be a valid wsl path");
if (!IsWSLRepo(repositoryPath))
{
throw new ArgumentException($"Not a valid WSL path: {repositoryPath}");
}

return $"-d {GetWslDistributionName(repositoryPath)} git ";
}
}

0 comments on commit c60dc85

Please sign in to comment.