mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Fix WSLENV environment variable duplication in ConptyConnection (#19167)
This PR fixes issue #7130 where WT_SESSION and WT_PROFILE_ID environment variables were being duplicated in the WSLENV environment variable when multiple terminal sessions were created. The previous implementation always appended WT_SESSION:WT_PROFILE_ID: to WSLENV without checking if these variables already existed, causing duplication. Closes #7130 Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
This commit is contained in:
parent
65788d9099
commit
7d6e0c8b8e
@ -66,10 +66,41 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||||||
|
|
||||||
// WSLENV is a colon-delimited list of environment variables (+flags) that should appear inside WSL
|
// WSLENV is a colon-delimited list of environment variables (+flags) that should appear inside WSL
|
||||||
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
|
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
|
||||||
std::wstring wslEnv{ L"WT_SESSION:WT_PROFILE_ID:" };
|
|
||||||
|
// WSLENV.1: Get a handle to the WSLENV environment variable.
|
||||||
|
auto& wslEnv = environment.as_map()[L"WSLENV"];
|
||||||
|
std::wstring additionalWslEnv;
|
||||||
|
|
||||||
|
// WSLENV.2: Figure out what variables are already in WSLENV.
|
||||||
|
std::unordered_set<std::wstring_view> wslEnvVars;
|
||||||
|
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
|
||||||
|
{
|
||||||
|
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
|
||||||
|
// We only care about the variable name for WSLENV.
|
||||||
|
const auto key = til::safe_slice_len(part, 0, part.rfind(L'/'));
|
||||||
|
wslEnvVars.emplace(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WSLENV.3: Add our terminal-specific environment variables to WSLENV.
|
||||||
|
static constexpr std::wstring_view builtinWslEnvVars[] = {
|
||||||
|
L"WT_SESSION",
|
||||||
|
L"WT_PROFILE_ID",
|
||||||
|
};
|
||||||
|
// Misdiagnosis in MSVC 14.44.35207. No pointer arithmetic in sight.
|
||||||
|
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||||
|
for (const auto& key : builtinWslEnvVars)
|
||||||
|
{
|
||||||
|
if (wslEnvVars.emplace(key).second)
|
||||||
|
{
|
||||||
|
additionalWslEnv.append(key);
|
||||||
|
additionalWslEnv.push_back(L':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_environment)
|
if (_environment)
|
||||||
{
|
{
|
||||||
// Order the environment variable names so that resolution order is consistent
|
// Order the environment variable names so that resolution order is consistent
|
||||||
|
// NOTE(lhecker): I'm like 99% sure that this is unnecessary.
|
||||||
std::set<std::wstring, til::env_key_sorter> keys{};
|
std::set<std::wstring, til::env_key_sorter> keys{};
|
||||||
for (const auto item : _environment)
|
for (const auto item : _environment)
|
||||||
{
|
{
|
||||||
@ -85,18 +116,39 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||||||
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
|
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
|
||||||
|
|
||||||
environment.set_user_environment_var(key.c_str(), value.c_str());
|
environment.set_user_environment_var(key.c_str(), value.c_str());
|
||||||
// For each environment variable added to the environment, also add it to WSLENV
|
|
||||||
wslEnv += key + L":";
|
// WSLENV.4: Add custom user environment variables to WSLENV.
|
||||||
|
if (wslEnvVars.emplace(key).second)
|
||||||
|
{
|
||||||
|
additionalWslEnv.append(key);
|
||||||
|
additionalWslEnv.push_back(L':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CATCH_LOG();
|
CATCH_LOG();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to prepend new environment variables to WSLENV - that way if a variable already
|
if (!additionalWslEnv.empty())
|
||||||
// exists in WSLENV but with a flag, the flag will be respected.
|
{
|
||||||
// (This behaviour was empirically observed)
|
// WSLENV.5: In the next step we'll prepend `additionalWslEnv` to `wslEnv`,
|
||||||
wslEnv += environment.as_map()[L"WSLENV"];
|
// so make sure that we have a single colon in between them.
|
||||||
environment.as_map().insert_or_assign(L"WSLENV", wslEnv);
|
const auto hasColon = additionalWslEnv.ends_with(L':');
|
||||||
|
const auto needsColon = !wslEnv.starts_with(L':');
|
||||||
|
if (hasColon != needsColon)
|
||||||
|
{
|
||||||
|
if (hasColon)
|
||||||
|
{
|
||||||
|
additionalWslEnv.pop_back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
additionalWslEnv.push_back(L':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WSLENV.6: Prepend our additional environment variables to WSLENV.
|
||||||
|
wslEnv.insert(0, additionalWslEnv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newEnvVars = environment.to_string();
|
auto newEnvVars = environment.to_string();
|
||||||
|
|||||||
@ -55,20 +55,22 @@
|
|||||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||||
{
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
as_view_t<T> safe_slice_abs(const T& view, size_t beg, size_t end)
|
as_view_t<T> safe_slice_abs(const T& view, size_t beg, size_t end) noexcept
|
||||||
{
|
{
|
||||||
const size_t len = view.size();
|
const size_t len = view.size();
|
||||||
end = std::min(end, len);
|
end = std::min(end, len);
|
||||||
beg = std::min(beg, end);
|
beg = std::min(beg, end);
|
||||||
|
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||||
return { view.data() + beg, end - beg };
|
return { view.data() + beg, end - beg };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
as_view_t<T> safe_slice_len(const T& view, size_t start, size_t count)
|
as_view_t<T> safe_slice_len(const T& view, size_t start, size_t count) noexcept
|
||||||
{
|
{
|
||||||
const size_t len = view.size();
|
const size_t len = view.size();
|
||||||
start = std::min(start, len);
|
start = std::min(start, len);
|
||||||
count = std::min(count, len - start);
|
count = std::min(count, len - start);
|
||||||
|
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||||
return { view.data() + start, count };
|
return { view.data() + start, count };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user