Skip to content

Commit

Permalink
Use assembly API to build executable path
Browse files Browse the repository at this point in the history
  • Loading branch information
rjmholt committed Jul 9, 2019
1 parent 3a46ca0 commit b86ef4d
Showing 1 changed file with 33 additions and 18 deletions.
51 changes: 33 additions & 18 deletions src/powershell/Program.cs
Expand Up @@ -114,13 +114,13 @@ private static bool HasLoginSpecified(string[] args, out int loginIndex)
private static int ExecPwshLogin(string[] args, int loginArgIndex)
{
// We need the path to the current pwsh executable
string pwshPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
string pwshDllPath = Assembly.GetEntryAssembly().Location;

// Create input for /bin/sh that execs pwsh
int quotedPwshPathLength = GetQuotedPathLength(pwshPath);
int quotedPwshPathLength = GetQuotedPwshPathLength(pwshDllPath);
string pwshInvocation = string.Create(
10 + quotedPwshPathLength, // exec '{pwshPath}' "$@"
(pwshPath, quotedPwshPathLength),
(pwshDllPath, quotedPwshPathLength),
CreatePwshInvocation);

// Set up the arguments for /bin/sh
Expand Down Expand Up @@ -162,24 +162,32 @@ private static int ExecPwshLogin(string[] args, int loginArgIndex)
}

/// <summary>
/// Gets what the length of the given string will be if it's
/// Gets what the length of the path to pwsh will be when it's
/// quote escaped for /bin/sh.
/// </summary>
/// <param name="str">The string to quote escape.</param>
/// <param name="pwshDllPath">The path to pwsh.dll.</param>
/// <returns>The length of the string when it's quote escaped.</returns>
private static int GetQuotedPathLength(string str)
private static int GetQuotedPwshPathLength(string pwshDllPath)
{
int length = 2;
foreach (char c in str)
foreach (char c in pwshDllPath)
{
length++;
if (c == '\'') { length++; }
}

return length;
// Subtract 4, since that's the difference between
// "pwsh" and "pwsh.dll", of which we need the former
return length - 4;
}

private static void CreatePwshInvocation(Span<char> strBuf, (string path, int quotedLength) pwshPath)
/// <summary>
/// Creates the invocation string for pwsh in the exec script.
/// This method is to be used as the SpanAction in a string.Create call.
/// </summary>
/// <param name="strBuf">The internal string buffer to write to.</param>
/// <param name="pwshDllPath">A value tuple containing the pwsh.dll path and the anticipated quoted length.</param>
private static void CreatePwshInvocation(Span<char> strBuf, (string path, int quotedLength) pwshDllPath)
{
// "exec "
strBuf[0] = 'e';
Expand All @@ -189,11 +197,11 @@ private static void CreatePwshInvocation(Span<char> strBuf, (string path, int qu
strBuf[4] = ' ';

// The quoted path to pwsh, like "'/opt/microsoft/powershell/7/pwsh'"
Span<char> pathSpan = strBuf.Slice(5, pwshPath.quotedLength);
QuoteAndWriteToSpan(pwshPath.path, pathSpan);
Span<char> pathSpan = strBuf.Slice(5, pwshDllPath.quotedLength);
QuoteAndWritePwshPathToSpan(pwshDllPath.path, pathSpan);

// ' "$@"' the argument vector splat to pass pwsh arguments through
int argIndex = 5 + pwshPath.quotedLength;
int argIndex = 5 + pwshDllPath.quotedLength;
strBuf[argIndex] = ' ';
strBuf[argIndex + 1] = '"';
strBuf[argIndex + 2] = '$';
Expand All @@ -202,19 +210,21 @@ private static void CreatePwshInvocation(Span<char> strBuf, (string path, int qu
}

/// <summary>
/// Quotes (and sh quote escapes) a string and writes it to the given span.
/// Writes the sh-quote-escaped path to pwsh into the given span.
/// </summary>
/// <param name="arg">The string to quote.</param>
/// <param name="pwshDllPath">The path to pwsh.dll</param>
/// <param name="span">The span to write to.</param>
private static void QuoteAndWriteToSpan(string arg, Span<char> span)
private static void QuoteAndWritePwshPathToSpan(string pwshDllPath, Span<char> span)
{
int psHomeEndIndex = pwshDllPath.LastIndexOf('/');

span[0] = '\'';

int i = 0;
int j = 1;
for (; i < arg.Length; i++, j++)
for (; i < psHomeEndIndex; i++, j++)
{
char c = arg[i];
char c = pwshDllPath[i];

if (c == '\'')
{
Expand All @@ -226,7 +236,12 @@ private static void QuoteAndWriteToSpan(string arg, Span<char> span)
span[j] = c;
}

span[j] = '\'';
span[j++] = '/';
span[j++] = 'p';
span[j++] = 'w';
span[j++] = 's';
span[j++] = 'h';
span[j] = '\'';
}

/// <summary>
Expand Down

0 comments on commit b86ef4d

Please sign in to comment.