Skip to content

Commit

Permalink
Use Directory.EnumerateFiles instead of Directory.GetFiles in Whi…
Browse files Browse the repository at this point in the history
…chUtil. (#2882)

* Use Directory.EnumerateFiles instead of Directory.GetFiles in WhichUtil.

* .

* .
  • Loading branch information
TingluoHuang authored Sep 26, 2023
1 parent bf445e2 commit 8f1c070
Show file tree
Hide file tree
Showing 4 changed files with 409 additions and 10 deletions.
4 changes: 4 additions & 0 deletions src/Runner.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public static class Runner
public static readonly OSPlatform Platform = OSPlatform.OSX;
#elif OS_WINDOWS
public static readonly OSPlatform Platform = OSPlatform.Windows;
#else
public static readonly OSPlatform Platform = OSPlatform.Linux;
#endif

#if X86
Expand All @@ -79,6 +81,8 @@ public static class Runner
public static readonly Architecture PlatformArchitecture = Architecture.Arm;
#elif ARM64
public static readonly Architecture PlatformArchitecture = Architecture.Arm64;
#else
public static readonly Architecture PlatformArchitecture = Architecture.X64;
#endif

public static readonly TimeSpan ExitOnUnloadTimeout = TimeSpan.FromSeconds(30);
Expand Down
129 changes: 128 additions & 1 deletion src/Runner.Sdk/Util/WhichUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,128 @@ public static string Which(string command, bool require = false, ITraceWriter tr
}
}

#if OS_WINDOWS
trace?.Info($"{command}: command not found. Make sure '{command}' is installed and its location included in the 'Path' environment variable.");
#else
trace?.Info($"{command}: command not found. Make sure '{command}' is installed and its location included in the 'PATH' environment variable.");
#endif
if (require)
{
throw new FileNotFoundException(
message: $"{command}: command not found",
fileName: command);
}

return null;
}

public static string Which2(string command, bool require = false, ITraceWriter trace = null, string prependPath = null)
{
ArgUtil.NotNullOrEmpty(command, nameof(command));
trace?.Info($"Which2: '{command}'");
if (Path.IsPathFullyQualified(command) && File.Exists(command))
{
trace?.Info($"Fully qualified path: '{command}'");
return command;
}
string path = Environment.GetEnvironmentVariable(PathUtil.PathVariable);
if (string.IsNullOrEmpty(path))
{
trace?.Info("PATH environment variable not defined.");
path = path ?? string.Empty;
}
if (!string.IsNullOrEmpty(prependPath))
{
path = PathUtil.PrependPath(prependPath, path);
}

string[] pathSegments = path.Split(new Char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < pathSegments.Length; i++)
{
pathSegments[i] = Environment.ExpandEnvironmentVariables(pathSegments[i]);
}

foreach (string pathSegment in pathSegments)
{
if (!string.IsNullOrEmpty(pathSegment) && Directory.Exists(pathSegment))
{
#if OS_WINDOWS
string pathExt = Environment.GetEnvironmentVariable("PATHEXT");
if (string.IsNullOrEmpty(pathExt))
{
// XP's system default value for PATHEXT system variable
pathExt = ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh";
}

string[] pathExtSegments = pathExt.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

// if command already has an extension.
if (pathExtSegments.Any(ext => command.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
{
try
{
foreach (var file in Directory.EnumerateFiles(pathSegment, command))
{
if (IsPathValid(file, trace))
{
trace?.Info($"Location: '{file}'");
return file;
}
}
}
catch (UnauthorizedAccessException ex)
{
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
trace?.Verbose(ex.ToString());
}
}
else
{
string searchPattern;
searchPattern = StringUtil.Format($"{command}.*");
try
{
foreach (var file in Directory.EnumerateFiles(pathSegment, searchPattern))
{
// add extension.
for (int i = 0; i < pathExtSegments.Length; i++)
{
string fullPath = Path.Combine(pathSegment, $"{command}{pathExtSegments[i]}");
if (string.Equals(file, fullPath, StringComparison.OrdinalIgnoreCase) && IsPathValid(fullPath, trace))
{
trace?.Info($"Location: '{fullPath}'");
return fullPath;
}
}
}
}
catch (UnauthorizedAccessException ex)
{
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
trace?.Verbose(ex.ToString());
}
}
#else
try
{
foreach (var file in Directory.EnumerateFiles(pathSegment, command))
{
if (IsPathValid(file, trace))
{
trace?.Info($"Location: '{file}'");
return file;
}
}
}
catch (UnauthorizedAccessException ex)
{
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
trace?.Verbose(ex.ToString());
}
#endif
}
}

#if OS_WINDOWS
trace?.Info($"{command}: command not found. Make sure '{command}' is installed and its location included in the 'Path' environment variable.");
#else
Expand All @@ -134,7 +256,12 @@ private static bool IsPathValid(string path, ITraceWriter trace = null)
{
var fileInfo = new FileInfo(path);
var linkTargetFullPath = fileInfo.Directory?.FullName + Path.DirectorySeparatorChar + fileInfo.LinkTarget;
if (fileInfo.LinkTarget == null || File.Exists(linkTargetFullPath) || File.Exists(fileInfo.LinkTarget)) return true;
if (fileInfo.LinkTarget == null ||
File.Exists(linkTargetFullPath) ||
File.Exists(fileInfo.LinkTarget))
{
return true;
}
trace?.Info($"the target '{fileInfo.LinkTarget}' of the symbolic link '{path}', does not exist");
return false;
}
Expand Down
81 changes: 72 additions & 9 deletions src/Runner.Worker/Handlers/ScriptHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,40 @@ protected override void PrintActionDetails(ActionRunStage stage)
shellCommand = "pwsh";
if (validateShellOnHost)
{
shellCommandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
shellCommandPath = WhichUtil.Which2(shellCommand, require: false, Trace, prependPath);
}
else
{
shellCommandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
}
if (string.IsNullOrEmpty(shellCommandPath))
{
shellCommand = "powershell";
Trace.Info($"Defaulting to {shellCommand}");
shellCommandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
shellCommandPath = WhichUtil.Which2(shellCommand, require: true, Trace, prependPath);
}
else
{
shellCommandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
}
}
}
#else
shellCommand = "sh";
if (validateShellOnHost)
{
shellCommandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
shellCommandPath = WhichUtil.Which2("bash", false, Trace, prependPath) ?? WhichUtil.Which2("sh", true, Trace, prependPath);
}
else
{
shellCommandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
}
}
#endif
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
Expand All @@ -106,7 +127,14 @@ protected override void PrintActionDetails(ActionRunStage stage)
shellCommand = parsed.shellCommand;
if (validateShellOnHost)
{
shellCommandPath = WhichUtil.Which(parsed.shellCommand, true, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
shellCommandPath = WhichUtil.Which2(parsed.shellCommand, true, Trace, prependPath);
}
else
{
shellCommandPath = WhichUtil.Which(parsed.shellCommand, true, Trace, prependPath);
}
}

argFormat = $"{parsed.shellArgs}".TrimStart();
Expand Down Expand Up @@ -188,17 +216,38 @@ public async Task RunAsync(ActionRunStage stage)
{
#if OS_WINDOWS
shellCommand = "pwsh";
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
commandPath = WhichUtil.Which2(shellCommand, require: false, Trace, prependPath);
}
else
{
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
}
if (string.IsNullOrEmpty(commandPath))
{
shellCommand = "powershell";
Trace.Info($"Defaulting to {shellCommand}");
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
commandPath = WhichUtil.Which2(shellCommand, require: true, Trace, prependPath);
}
else
{
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
}
}
ArgUtil.NotNullOrEmpty(commandPath, "Default Shell");
#else
shellCommand = "sh";
commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
commandPath = WhichUtil.Which2("bash", false, Trace, prependPath) ?? WhichUtil.Which2("sh", true, Trace, prependPath);
}
else
{
commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
}
#endif
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
}
Expand All @@ -209,7 +258,14 @@ public async Task RunAsync(ActionRunStage stage)
if (!IsActionStep && systemShells.Contains(shell))
{
shellCommand = shell;
commandPath = WhichUtil.Which(shell, !isContainerStepHost, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
commandPath = WhichUtil.Which2(shell, !isContainerStepHost, Trace, prependPath);
}
else
{
commandPath = WhichUtil.Which(shell, !isContainerStepHost, Trace, prependPath);
}
if (shell == "bash")
{
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat("sh");
Expand All @@ -224,7 +280,14 @@ public async Task RunAsync(ActionRunStage stage)
var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell);
shellCommand = parsed.shellCommand;
// For non-ContainerStepHost, the command must be located on the host by Which
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
{
commandPath = WhichUtil.Which2(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
}
else
{
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
}
argFormat = $"{parsed.shellArgs}".TrimStart();
if (string.IsNullOrEmpty(argFormat))
{
Expand Down
Loading

0 comments on commit 8f1c070

Please sign in to comment.