mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-20 10:29:30 -05:00
Move this function to types/ so we can write tests for it
This commit is contained in:
@@ -61,72 +61,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Promotes a starting directory provided to a WSL invocation to a commandline argument.
|
||||
// This is necessary because WSL has some modicum of support for linux-side directories (!) which
|
||||
// CreateProcess never will.
|
||||
static std::tuple<std::wstring, std::wstring> _tryMangleStartingDirectoryForWSL(std::wstring_view commandLine, std::wstring_view startingDirectory)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (startingDirectory.size() > 0 && commandLine.size() >= 3)
|
||||
{ // "wsl" is three characters; this is a safe bet. no point in doing it if there's no starting directory though!
|
||||
// Find the first space, quote or the end of the string -- we'll look for wsl before that.
|
||||
const auto terminator{ commandLine.find_first_of(LR"(" )", 1) }; // look past the first character in case it starts with "
|
||||
const auto start{ til::at(commandLine, 0) == L'"' ? 1 : 0 };
|
||||
const std::filesystem::path executablePath{ commandLine.substr(start, terminator - start) };
|
||||
const auto executableFilename{ executablePath.filename().wstring() };
|
||||
if (executableFilename == L"wsl" || executableFilename == L"wsl.exe")
|
||||
{
|
||||
// We've got a WSL -- let's just make sure it's the right one.
|
||||
if (executablePath.has_parent_path())
|
||||
{
|
||||
std::wstring systemDirectory{};
|
||||
if (FAILED(wil::GetSystemDirectoryW(systemDirectory)))
|
||||
{
|
||||
break; // just bail out.
|
||||
}
|
||||
if (executablePath.parent_path().wstring() != systemDirectory)
|
||||
{
|
||||
break; // it wasn't in system32!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume that unqualified WSL is the one in system32 (minor danger)
|
||||
}
|
||||
|
||||
const auto arguments{ terminator == std::wstring_view::npos ? std::wstring_view{} : commandLine.substr(terminator + 1) };
|
||||
if (arguments.find(L"--cd") != std::wstring_view::npos)
|
||||
{
|
||||
break; // they've already got a --cd!
|
||||
}
|
||||
|
||||
const auto tilde{ arguments.find_first_of(L'~') };
|
||||
if (tilde != std::wstring_view::npos)
|
||||
{
|
||||
if (tilde + 1 == arguments.size() || til::at(arguments, tilde + 1) == L' ')
|
||||
{
|
||||
// We want to suppress --cd if they have added a bare ~ to their commandline (they conflict).
|
||||
break;
|
||||
}
|
||||
// Tilde followed by non-space should be okay (like, wsl -d Debian ~/blah.sh)
|
||||
}
|
||||
|
||||
return {
|
||||
fmt::format(LR"("{}" --cd "{}" {})", executablePath.wstring(), startingDirectory, arguments),
|
||||
std::wstring{}
|
||||
};
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return {
|
||||
std::wstring{ commandLine },
|
||||
std::wstring{ startingDirectory }
|
||||
};
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - launches the client application attached to the new pseudoconsole
|
||||
HRESULT ConptyConnection::_LaunchAttachedClient() noexcept
|
||||
@@ -233,7 +167,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
siEx.StartupInfo.lpTitle = mutableTitle.data();
|
||||
}
|
||||
|
||||
auto [newCommandLine, newStartingDirectory] = _tryMangleStartingDirectoryForWSL(cmdline, _startingDirectory);
|
||||
auto [newCommandLine, newStartingDirectory] = Utils::MangleStartingDirectoryForWSL(cmdline, _startingDirectory);
|
||||
const wchar_t* const startingDirectory = newStartingDirectory.size() > 0 ? newStartingDirectory.c_str() : nullptr;
|
||||
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
|
||||
@@ -95,4 +95,13 @@ namespace Microsoft::Console::Utils
|
||||
GUID CreateV5Uuid(const GUID& namespaceGuid, const gsl::span<const gsl::byte> name);
|
||||
|
||||
bool IsElevated();
|
||||
|
||||
// This function is only ever used by the ConPTY connection in
|
||||
// TerminalConnection. However, that library does not have a good systen of
|
||||
// tests set up. Since this function has a plethora of edge cases that would
|
||||
// be beneficial to have tests for, we're hosting it in this lib, so it can
|
||||
// be easily tested.
|
||||
std::tuple<std::wstring, std::wstring> MangleStartingDirectoryForWSL(std::wstring_view commandLine,
|
||||
std::wstring_view startingDirectory);
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ class UtilsTests
|
||||
TEST_METHOD(TestStringToUint);
|
||||
TEST_METHOD(TestColorFromXTermColor);
|
||||
|
||||
TEST_METHOD(TestMangleWSLPaths);
|
||||
|
||||
void _VerifyXTermColorResult(const std::wstring_view wstr, DWORD colorValue);
|
||||
void _VerifyXTermColorInvalid(const std::wstring_view wstr);
|
||||
};
|
||||
@@ -332,3 +334,120 @@ void UtilsTests::_VerifyXTermColorInvalid(const std::wstring_view wstr)
|
||||
std::optional<til::color> color = ColorFromXTermColor(wstr);
|
||||
VERIFY_IS_FALSE(color.has_value());
|
||||
}
|
||||
|
||||
void UtilsTests::TestMangleWSLPaths()
|
||||
{
|
||||
// Continue on failures
|
||||
const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope;
|
||||
|
||||
const auto startingDirectory{ L"SENTINEL" };
|
||||
// MUST MANGLE
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" )", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl -d X ~/bin/sh)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" -d X ~/bin/sh)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl.exe)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl.exe" --cd "SENTINEL" )", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl.exe -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl.exe" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl.exe -d X ~/bin/sh)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl.exe" --cd "SENTINEL" -d X ~/bin/sh)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("wsl")", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" )", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("wsl.exe")", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl.exe" --cd "SENTINEL" )", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("wsl" -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("wsl.exe" -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl.exe" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("C:\Windows\system32\wsl.exe" -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("C:\Windows\system32\wsl.exe" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("C:\windows\system32\wsl" -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("C:\windows\system32\wsl" --cd "SENTINEL" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl ~/bin)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("wsl" --cd "SENTINEL" ~/bin)", commandline);
|
||||
VERIFY_ARE_EQUAL(L"", path);
|
||||
}
|
||||
|
||||
// MUST NOT MANGLE
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"("C:\wsl.exe" -d X)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"("C:\wsl.exe" -d X)", commandline);
|
||||
VERIFY_ARE_EQUAL(startingDirectory, path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(C:\wsl.exe)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"(C:\wsl.exe)", commandline);
|
||||
VERIFY_ARE_EQUAL(startingDirectory, path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl --cd C:\)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"(wsl --cd C:\)", commandline);
|
||||
VERIFY_ARE_EQUAL(startingDirectory, path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl ~)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"(wsl ~)", commandline);
|
||||
VERIFY_ARE_EQUAL(startingDirectory, path);
|
||||
}
|
||||
|
||||
{
|
||||
auto [commandline, path] = MangleStartingDirectoryForWSL(LR"(wsl ~ -d Ubuntu)", startingDirectory);
|
||||
VERIFY_ARE_EQUAL(LR"(wsl ~ -d Ubuntu)", commandline);
|
||||
VERIFY_ARE_EQUAL(startingDirectory, path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "inc/colorTable.hpp"
|
||||
|
||||
#include <wil/token_helpers.h>
|
||||
#include <til/string.h>
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
|
||||
@@ -591,3 +592,71 @@ bool Utils::IsElevated()
|
||||
}();
|
||||
return isElevated;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Promotes a starting directory provided to a WSL invocation to a commandline argument.
|
||||
// This is necessary because WSL has some modicum of support for linux-side directories (!) which
|
||||
// CreateProcess never will.
|
||||
std::tuple<std::wstring, std::wstring> Utils::MangleStartingDirectoryForWSL(std::wstring_view commandLine,
|
||||
std::wstring_view startingDirectory)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (startingDirectory.size() > 0 && commandLine.size() >= 3)
|
||||
{ // "wsl" is three characters; this is a safe bet. no point in doing it if there's no starting directory though!
|
||||
// Find the first space, quote or the end of the string -- we'll look for wsl before that.
|
||||
const auto terminator{ commandLine.find_first_of(LR"(" )", 1) }; // look past the first character in case it starts with "
|
||||
const auto start{ til::at(commandLine, 0) == L'"' ? 1 : 0 };
|
||||
const std::filesystem::path executablePath{ commandLine.substr(start, terminator - start) };
|
||||
const auto executableFilename{ executablePath.filename().wstring() };
|
||||
if (executableFilename == L"wsl" || executableFilename == L"wsl.exe")
|
||||
{
|
||||
// We've got a WSL -- let's just make sure it's the right one.
|
||||
if (executablePath.has_parent_path())
|
||||
{
|
||||
std::wstring systemDirectory{};
|
||||
if (FAILED(wil::GetSystemDirectoryW(systemDirectory)))
|
||||
{
|
||||
break; // just bail out.
|
||||
}
|
||||
|
||||
if (!til::equals_insensitive_ascii(executablePath.parent_path().c_str(), systemDirectory))
|
||||
{
|
||||
break; // it wasn't in system32!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume that unqualified WSL is the one in system32 (minor danger)
|
||||
}
|
||||
|
||||
const auto arguments{ terminator == std::wstring_view::npos ? std::wstring_view{} : commandLine.substr(terminator + 1) };
|
||||
if (arguments.find(L"--cd") != std::wstring_view::npos)
|
||||
{
|
||||
break; // they've already got a --cd!
|
||||
}
|
||||
|
||||
const auto tilde{ arguments.find_first_of(L'~') };
|
||||
if (tilde != std::wstring_view::npos)
|
||||
{
|
||||
if (tilde + 1 == arguments.size() || til::at(arguments, tilde + 1) == L' ')
|
||||
{
|
||||
// We want to suppress --cd if they have added a bare ~ to their commandline (they conflict).
|
||||
break;
|
||||
}
|
||||
// Tilde followed by non-space should be okay (like, wsl -d Debian ~/blah.sh)
|
||||
}
|
||||
|
||||
return {
|
||||
fmt::format(LR"("{}" --cd "{}" {})", executablePath.wstring(), startingDirectory, arguments),
|
||||
std::wstring{}
|
||||
};
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return {
|
||||
std::wstring{ commandLine },
|
||||
std::wstring{ startingDirectory }
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user