terminal/src/cascadia/TerminalApp/WslDistroGenerator.cpp
Carlos Zamora a51091c615
Make Profile a WinRT object (#7283)
Profile is now a WinRT object in the TerminalApp project.

As with ColorScheme, all of the serialization logic is not exposed via
the idl. TerminalSetingsModel will handle it when it's all moved over.

I removed the "Get" and "Set" prefixes from all of the Profile
functions. It just makes more sense to use the `GETSET_PROPERTY` macro
to do most of the work for us.

`CloseOnExitMode` is now an enum off of the Profile.idl.

`std::optional<wstring>` got converted to `hstring` (as opposed to
`IReference<hstring>`). `IReference<hstring>` is not valid to MIDL.

## References
#7141 - Profile is a settings object
#885 - this new settings object will be moved to a new TerminalSettingsModel project

## Validation Steps Performed
- [x] Tests passed
- [x] Deployment succeeded

Closes #7435
2020-08-28 01:09:22 +00:00

139 lines
5.3 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "WslDistroGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include <io.h>
#include <fcntl.h>
#include "DefaultProfileUtils.h"
static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" };
using namespace ::TerminalApp;
using namespace winrt::TerminalApp;
// Legacy GUIDs:
// - Debian 58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530
// - Ubuntu 2c4de342-38b7-51cf-b940-2309a097f518
// - Alpine 1777cdf0-b2c4-5a63-a204-eb60f349ea7c
// - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40
std::wstring_view WslDistroGenerator::GetNamespace()
{
return WslGeneratorNamespace;
}
// Method Description:
// - Enumerates all the installed WSL distros to create profiles for them.
// Arguments:
// - <none>
// Return Value:
// - a vector with all distros for all the installed WSL distros
std::vector<Profile> WslDistroGenerator::GenerateProfiles()
{
std::vector<Profile> profiles;
wil::unique_handle readPipe;
wil::unique_handle writePipe;
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true };
THROW_IF_WIN32_BOOL_FALSE(CreatePipe(&readPipe, &writePipe, &sa, 0));
STARTUPINFO si{ 0 };
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = writePipe.get();
si.hStdError = writePipe.get();
wil::unique_process_information pi;
wil::unique_cotaskmem_string systemPath;
THROW_IF_FAILED(wil::GetSystemDirectoryW(systemPath));
std::wstring command(systemPath.get());
command += L"\\wsl.exe --list";
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr,
const_cast<LPWSTR>(command.c_str()),
nullptr,
nullptr,
TRUE,
CREATE_NO_WINDOW,
nullptr,
nullptr,
&si,
&pi));
switch (WaitForSingleObject(pi.hProcess, 2000))
{
case WAIT_OBJECT_0:
break;
case WAIT_ABANDONED:
case WAIT_TIMEOUT:
return profiles;
case WAIT_FAILED:
THROW_LAST_ERROR();
default:
THROW_HR(ERROR_UNHANDLED_EXCEPTION);
}
DWORD exitCode;
if (!GetExitCodeProcess(pi.hProcess, &exitCode))
{
THROW_HR(E_INVALIDARG);
}
else if (exitCode != 0)
{
return profiles;
}
DWORD bytesAvailable;
THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr));
// "The _open_osfhandle call transfers ownership of the Win32 file handle to the file descriptor."
// (https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-osfhandle?view=vs-2019)
// so, we detach_from_smart_pointer it -- but...
// "File descriptors passed into _fdopen are owned by the returned FILE * stream.
// If _fdopen is successful, do not call _close on the file descriptor.
// Calling fclose on the returned FILE * also closes the file descriptor."
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fdopen-wfdopen?view=vs-2019
FILE* stdioPipeHandle = _wfdopen(_open_osfhandle((intptr_t)wil::detach_from_smart_pointer(readPipe), _O_WTEXT | _O_RDONLY), L"r");
auto closeFile = wil::scope_exit([&]() { fclose(stdioPipeHandle); });
std::wfstream pipe{ stdioPipeHandle };
std::wstring wline;
std::getline(pipe, wline); // remove the header from the output.
while (pipe.tellp() < bytesAvailable)
{
std::getline(pipe, wline);
std::wstringstream wlinestream(wline);
if (wlinestream)
{
std::wstring distName;
std::getline(wlinestream, distName, L'\r');
if (distName.substr(0, std::min(distName.size(), DockerDistributionPrefix.size())) == DockerDistributionPrefix)
{
// Docker for Windows creates some utility distributions to handle Docker commands.
// Pursuant to GH#3556, because they are _not_ user-facing we want to hide them.
continue;
}
const size_t firstChar = distName.find_first_of(L"( ");
// Some localizations don't have a space between the name and "(Default)"
// https://github.com/microsoft/terminal/issues/1168#issuecomment-500187109
if (firstChar < distName.size())
{
distName.resize(firstChar);
}
auto WSLDistro{ CreateDefaultProfile(distName) };
WSLDistro.Commandline(L"wsl.exe -d " + distName);
WSLDistro.ColorSchemeName(L"Campbell");
WSLDistro.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
WSLDistro.IconPath(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
profiles.emplace_back(WSLDistro);
}
}
return profiles;
}