2017-01-28 04:49:09 +08:00
|
|
|
#include "pch.h"
|
2017-04-28 09:08:52 +08:00
|
|
|
|
2017-03-11 08:54:08 +08:00
|
|
|
#include "vcpkg_Checks.h"
|
2017-08-24 07:17:53 +08:00
|
|
|
#include "vcpkg_GlobalState.h"
|
2017-04-28 09:08:52 +08:00
|
|
|
#include "vcpkg_System.h"
|
2017-04-06 07:28:09 +08:00
|
|
|
#include "vcpkglib.h"
|
2016-09-19 11:50:08 +08:00
|
|
|
|
2017-01-06 04:47:08 +08:00
|
|
|
namespace vcpkg::System
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
2017-04-21 09:59:03 +08:00
|
|
|
tm get_current_date_time()
|
|
|
|
{
|
|
|
|
using std::chrono::system_clock;
|
|
|
|
std::time_t now_time = system_clock::to_time_t(system_clock::now());
|
|
|
|
tm parts;
|
|
|
|
localtime_s(&parts, &now_time);
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
2016-09-19 11:50:08 +08:00
|
|
|
fs::path get_exe_path_of_current_process()
|
|
|
|
{
|
2017-03-11 08:55:59 +08:00
|
|
|
wchar_t buf[_MAX_PATH];
|
2017-08-30 09:57:38 +08:00
|
|
|
const int bytes = GetModuleFileNameW(nullptr, buf, _MAX_PATH);
|
2017-04-28 09:08:52 +08:00
|
|
|
if (bytes == 0) std::abort();
|
2016-09-19 11:50:08 +08:00
|
|
|
return fs::path(buf, buf + bytes);
|
|
|
|
}
|
|
|
|
|
2017-05-04 07:33:02 +08:00
|
|
|
Optional<CPUArchitecture> to_cpu_architecture(CStringView arch)
|
|
|
|
{
|
2017-05-05 06:19:22 +08:00
|
|
|
if (Strings::case_insensitive_ascii_compare(arch, "x86") == 0) return CPUArchitecture::X86;
|
|
|
|
if (Strings::case_insensitive_ascii_compare(arch, "x64") == 0) return CPUArchitecture::X64;
|
|
|
|
if (Strings::case_insensitive_ascii_compare(arch, "amd64") == 0) return CPUArchitecture::X64;
|
|
|
|
if (Strings::case_insensitive_ascii_compare(arch, "arm") == 0) return CPUArchitecture::ARM;
|
|
|
|
if (Strings::case_insensitive_ascii_compare(arch, "arm64") == 0) return CPUArchitecture::ARM64;
|
2017-05-04 07:33:02 +08:00
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPUArchitecture get_host_processor()
|
|
|
|
{
|
|
|
|
auto w6432 = get_environment_variable(L"PROCESSOR_ARCHITEW6432");
|
2017-08-30 09:57:38 +08:00
|
|
|
if (const auto p = w6432.get()) return to_cpu_architecture(Strings::to_utf8(*p)).value_or_exit(VCPKG_LINE_INFO);
|
2017-05-04 07:33:02 +08:00
|
|
|
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto procarch = get_environment_variable(L"PROCESSOR_ARCHITECTURE").value_or_exit(VCPKG_LINE_INFO);
|
2017-05-04 07:33:02 +08:00
|
|
|
return to_cpu_architecture(Strings::to_utf8(procarch)).value_or_exit(VCPKG_LINE_INFO);
|
|
|
|
}
|
|
|
|
|
2017-08-24 18:26:42 +08:00
|
|
|
std::vector<CPUArchitecture> get_supported_host_architectures()
|
|
|
|
{
|
|
|
|
std::vector<CPUArchitecture> supported_architectures;
|
|
|
|
supported_architectures.push_back(get_host_processor());
|
|
|
|
|
2017-08-29 10:29:12 +08:00
|
|
|
// AMD64 machines support to run x86 applications
|
|
|
|
if (supported_architectures.back() == CPUArchitecture::X64)
|
2017-08-24 18:26:42 +08:00
|
|
|
{
|
|
|
|
supported_architectures.push_back(CPUArchitecture::X86);
|
|
|
|
}
|
|
|
|
|
|
|
|
return supported_architectures;
|
|
|
|
}
|
|
|
|
|
2017-04-04 05:21:51 +08:00
|
|
|
int cmd_execute_clean(const CWStringView cmd_line)
|
2017-03-11 08:55:59 +08:00
|
|
|
{
|
2017-08-30 09:57:38 +08:00
|
|
|
static const std::wstring SYSTEM_ROOT = get_environment_variable(L"SystemRoot").value_or_exit(VCPKG_LINE_INFO);
|
|
|
|
static const std::wstring SYSTEM_32 = SYSTEM_ROOT + LR"(\system32)";
|
|
|
|
static const std::wstring NEW_PATH = Strings::wformat(
|
|
|
|
LR"(Path=%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)", SYSTEM_32, SYSTEM_ROOT, SYSTEM_32, SYSTEM_32);
|
2017-03-11 08:55:59 +08:00
|
|
|
|
2017-04-28 09:08:52 +08:00
|
|
|
std::vector<std::wstring> env_wstrings = {
|
2017-03-11 08:55:59 +08:00
|
|
|
L"ALLUSERSPROFILE",
|
|
|
|
L"APPDATA",
|
|
|
|
L"CommonProgramFiles",
|
|
|
|
L"CommonProgramFiles(x86)",
|
|
|
|
L"CommonProgramW6432",
|
|
|
|
L"COMPUTERNAME",
|
|
|
|
L"ComSpec",
|
|
|
|
L"HOMEDRIVE",
|
|
|
|
L"HOMEPATH",
|
|
|
|
L"LOCALAPPDATA",
|
|
|
|
L"LOGONSERVER",
|
|
|
|
L"NUMBER_OF_PROCESSORS",
|
|
|
|
L"OS",
|
|
|
|
L"PATHEXT",
|
|
|
|
L"PROCESSOR_ARCHITECTURE",
|
2017-04-23 15:11:42 +08:00
|
|
|
L"PROCESSOR_ARCHITEW6432",
|
2017-03-11 08:55:59 +08:00
|
|
|
L"PROCESSOR_IDENTIFIER",
|
|
|
|
L"PROCESSOR_LEVEL",
|
|
|
|
L"PROCESSOR_REVISION",
|
|
|
|
L"ProgramData",
|
|
|
|
L"ProgramFiles",
|
|
|
|
L"ProgramFiles(x86)",
|
|
|
|
L"ProgramW6432",
|
|
|
|
L"PROMPT",
|
|
|
|
L"PSModulePath",
|
|
|
|
L"PUBLIC",
|
|
|
|
L"SystemDrive",
|
|
|
|
L"SystemRoot",
|
|
|
|
L"TEMP",
|
|
|
|
L"TMP",
|
|
|
|
L"USERDNSDOMAIN",
|
|
|
|
L"USERDOMAIN",
|
|
|
|
L"USERDOMAIN_ROAMINGPROFILE",
|
|
|
|
L"USERNAME",
|
|
|
|
L"USERPROFILE",
|
|
|
|
L"windir",
|
|
|
|
// Enables proxy information to be passed to Curl, the underlying download library in cmake.exe
|
|
|
|
L"HTTP_PROXY",
|
|
|
|
L"HTTPS_PROXY",
|
2017-04-06 05:10:01 +08:00
|
|
|
// Enables find_package(CUDA) in CMake
|
|
|
|
L"CUDA_PATH",
|
2017-03-11 08:55:59 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Flush stdout before launching external process
|
2017-08-24 07:17:53 +08:00
|
|
|
fflush(nullptr);
|
2017-03-11 08:55:59 +08:00
|
|
|
|
2017-08-25 03:06:28 +08:00
|
|
|
std::wstring env_cstr;
|
2017-03-11 08:55:59 +08:00
|
|
|
|
|
|
|
for (auto&& env_wstring : env_wstrings)
|
|
|
|
{
|
2017-05-05 05:58:18 +08:00
|
|
|
const Optional<std::wstring> value = System::get_environment_variable(env_wstring);
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto v = value.get();
|
2017-04-28 09:08:52 +08:00
|
|
|
if (!v || v->empty()) continue;
|
2017-03-11 08:55:59 +08:00
|
|
|
|
2017-08-25 03:06:28 +08:00
|
|
|
env_cstr.append(env_wstring);
|
|
|
|
env_cstr.push_back(L'=');
|
|
|
|
env_cstr.append(*v);
|
|
|
|
env_cstr.push_back(L'\0');
|
2017-03-11 08:55:59 +08:00
|
|
|
}
|
|
|
|
|
2017-08-30 09:57:38 +08:00
|
|
|
env_cstr.append(NEW_PATH);
|
2017-08-25 03:06:28 +08:00
|
|
|
env_cstr.push_back(L'\0');
|
|
|
|
|
|
|
|
STARTUPINFOW startup_info;
|
|
|
|
memset(&startup_info, 0, sizeof(STARTUPINFOW));
|
|
|
|
startup_info.cb = sizeof(STARTUPINFOW);
|
|
|
|
|
|
|
|
PROCESS_INFORMATION process_info;
|
|
|
|
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
|
2017-03-11 08:55:59 +08:00
|
|
|
|
|
|
|
// Basically we are wrapping it in quotes
|
2017-08-25 03:06:28 +08:00
|
|
|
std::wstring actual_cmd_line = Strings::wformat(LR"###(cmd.exe /c "%s")###", cmd_line);
|
|
|
|
Debug::println("CreateProcessW(%s)", Strings::to_utf8(actual_cmd_line));
|
|
|
|
bool succeeded = TRUE == CreateProcessW(nullptr,
|
|
|
|
actual_cmd_line.data(),
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
FALSE,
|
|
|
|
BELOW_NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
|
|
|
|
env_cstr.data(),
|
|
|
|
nullptr,
|
|
|
|
&startup_info,
|
|
|
|
&process_info);
|
|
|
|
|
|
|
|
Checks::check_exit(VCPKG_LINE_INFO, succeeded, "Process creation failed with error code: %lu", GetLastError());
|
|
|
|
|
|
|
|
CloseHandle(process_info.hThread);
|
|
|
|
|
2017-08-30 09:57:38 +08:00
|
|
|
const DWORD result = WaitForSingleObject(process_info.hProcess, INFINITE);
|
2017-08-25 03:06:28 +08:00
|
|
|
Checks::check_exit(VCPKG_LINE_INFO, result != WAIT_FAILED, "WaitForSingleObject failed");
|
|
|
|
|
|
|
|
DWORD exit_code = 0;
|
|
|
|
GetExitCodeProcess(process_info.hProcess, &exit_code);
|
|
|
|
|
|
|
|
Debug::println("CreateProcessW() returned %lu", exit_code);
|
2017-03-11 08:55:59 +08:00
|
|
|
return static_cast<int>(exit_code);
|
|
|
|
}
|
|
|
|
|
2017-04-04 05:21:51 +08:00
|
|
|
int cmd_execute(const CWStringView cmd_line)
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
2017-03-04 22:10:59 +08:00
|
|
|
// Flush stdout before launching external process
|
2017-08-24 07:17:53 +08:00
|
|
|
fflush(nullptr);
|
2017-02-15 11:09:09 +08:00
|
|
|
|
2016-09-19 11:50:08 +08:00
|
|
|
// Basically we are wrapping it in quotes
|
2016-09-30 10:28:00 +08:00
|
|
|
const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s")###", cmd_line);
|
2017-05-06 05:37:58 +08:00
|
|
|
Debug::println("_wsystem(%s)", Strings::to_utf8(actual_cmd_line));
|
2017-08-30 09:57:38 +08:00
|
|
|
const int exit_code = _wsystem(actual_cmd_line.c_str());
|
2017-05-06 05:37:58 +08:00
|
|
|
Debug::println("_wsystem() returned %d", exit_code);
|
2016-09-19 11:50:08 +08:00
|
|
|
return exit_code;
|
|
|
|
}
|
|
|
|
|
2017-04-04 07:30:11 +08:00
|
|
|
ExitCodeAndOutput cmd_execute_and_capture_output(const CWStringView cmd_line)
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
2017-03-04 22:10:59 +08:00
|
|
|
// Flush stdout before launching external process
|
|
|
|
fflush(stdout);
|
2017-02-15 11:09:09 +08:00
|
|
|
|
2017-03-14 07:17:47 +08:00
|
|
|
const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s 2>&1")###", cmd_line);
|
2016-09-19 11:50:08 +08:00
|
|
|
|
2017-06-15 13:06:52 +08:00
|
|
|
Debug::println("_wpopen(%s)", Strings::to_utf8(actual_cmd_line));
|
2017-08-26 14:34:44 +08:00
|
|
|
std::wstring output;
|
|
|
|
wchar_t buf[1024];
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto pipe = _wpopen(actual_cmd_line.c_str(), L"r");
|
2016-09-19 11:50:08 +08:00
|
|
|
if (pipe == nullptr)
|
|
|
|
{
|
2017-08-26 14:34:44 +08:00
|
|
|
return {1, Strings::to_utf8(output)};
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
2017-08-26 14:34:44 +08:00
|
|
|
while (fgetws(buf, 1024, pipe))
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
|
|
|
output.append(buf);
|
|
|
|
}
|
|
|
|
if (!feof(pipe))
|
|
|
|
{
|
2017-08-26 14:34:44 +08:00
|
|
|
return {1, Strings::to_utf8(output)};
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
2017-08-30 09:57:38 +08:00
|
|
|
|
|
|
|
const auto ec = _pclose(pipe);
|
2017-08-26 14:34:44 +08:00
|
|
|
Debug::println("_pclose() returned %d", ec);
|
|
|
|
return {ec, Strings::to_utf8(output)};
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-04-04 05:21:51 +08:00
|
|
|
std::wstring create_powershell_script_cmd(const fs::path& script_path, const CWStringView args)
|
2017-03-07 08:16:56 +08:00
|
|
|
{
|
|
|
|
// TODO: switch out ExecutionPolicy Bypass with "Remove Mark Of The Web" code and restore RemoteSigned
|
2017-04-28 09:08:52 +08:00
|
|
|
return Strings::wformat(
|
|
|
|
LR"(powershell -NoProfile -ExecutionPolicy Bypass -Command "& {& '%s' %s}")", script_path.native(), args);
|
2017-03-07 08:16:56 +08:00
|
|
|
}
|
|
|
|
|
2017-08-29 10:29:12 +08:00
|
|
|
void println() { println(Strings::EMPTY); }
|
|
|
|
|
2017-04-28 09:08:52 +08:00
|
|
|
void print(const CStringView message) { fputs(message, stdout); }
|
2016-09-19 11:50:08 +08:00
|
|
|
|
2017-04-04 05:21:51 +08:00
|
|
|
void println(const CStringView message)
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
|
|
|
print(message);
|
2017-02-23 21:33:21 +08:00
|
|
|
putchar('\n');
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-04-04 07:31:00 +08:00
|
|
|
void print(const Color c, const CStringView message)
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
2017-08-30 09:57:38 +08:00
|
|
|
const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
2016-09-19 11:50:08 +08:00
|
|
|
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo{};
|
|
|
|
GetConsoleScreenBufferInfo(hConsole, &consoleScreenBufferInfo);
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto original_color = consoleScreenBufferInfo.wAttributes;
|
2016-09-19 11:50:08 +08:00
|
|
|
|
2017-02-16 10:40:39 +08:00
|
|
|
SetConsoleTextAttribute(hConsole, static_cast<WORD>(c) | (original_color & 0xF0));
|
2017-02-23 21:33:21 +08:00
|
|
|
print(message);
|
2016-09-19 11:50:08 +08:00
|
|
|
SetConsoleTextAttribute(hConsole, original_color);
|
|
|
|
}
|
|
|
|
|
2017-04-04 07:31:00 +08:00
|
|
|
void println(const Color c, const CStringView message)
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
|
|
|
print(c, message);
|
2017-02-23 21:33:21 +08:00
|
|
|
putchar('\n');
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-05 05:58:18 +08:00
|
|
|
Optional<std::wstring> get_environment_variable(const CWStringView varname) noexcept
|
2016-09-19 11:50:08 +08:00
|
|
|
{
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto sz = GetEnvironmentVariableW(varname, nullptr, 0);
|
2017-04-28 09:08:52 +08:00
|
|
|
if (sz == 0) return nullopt;
|
2017-03-11 08:54:08 +08:00
|
|
|
|
2017-04-01 08:41:24 +08:00
|
|
|
std::wstring ret(sz, L'\0');
|
|
|
|
|
|
|
|
Checks::check_exit(VCPKG_LINE_INFO, MAXDWORD >= ret.size());
|
2017-08-30 09:57:38 +08:00
|
|
|
const auto sz2 = GetEnvironmentVariableW(varname, ret.data(), static_cast<DWORD>(ret.size()));
|
2017-03-14 08:38:04 +08:00
|
|
|
Checks::check_exit(VCPKG_LINE_INFO, sz2 + 1 == sz);
|
2017-04-01 08:41:24 +08:00
|
|
|
ret.pop_back();
|
|
|
|
return ret;
|
2016-09-19 11:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 07:43:54 +08:00
|
|
|
static bool is_string_keytype(DWORD hkey_type)
|
|
|
|
{
|
|
|
|
return hkey_type == REG_SZ || hkey_type == REG_MULTI_SZ || hkey_type == REG_EXPAND_SZ;
|
|
|
|
}
|
|
|
|
|
2017-04-04 07:27:51 +08:00
|
|
|
Optional<std::wstring> get_registry_string(HKEY base, const CWStringView subKey, const CWStringView valuename)
|
2017-03-11 07:43:54 +08:00
|
|
|
{
|
|
|
|
HKEY k = nullptr;
|
2017-08-30 09:57:38 +08:00
|
|
|
const LSTATUS ec = RegOpenKeyExW(base, subKey, NULL, KEY_READ, &k);
|
2017-04-28 09:08:52 +08:00
|
|
|
if (ec != ERROR_SUCCESS) return nullopt;
|
2017-03-11 07:43:54 +08:00
|
|
|
|
|
|
|
DWORD dwBufferSize = 0;
|
|
|
|
DWORD dwType = 0;
|
|
|
|
auto rc = RegQueryValueExW(k, valuename, nullptr, &dwType, nullptr, &dwBufferSize);
|
2017-04-28 09:08:52 +08:00
|
|
|
if (rc != ERROR_SUCCESS || !is_string_keytype(dwType) || dwBufferSize == 0 ||
|
|
|
|
dwBufferSize % sizeof(wchar_t) != 0)
|
2017-03-29 06:05:55 +08:00
|
|
|
return nullopt;
|
2017-03-11 07:43:54 +08:00
|
|
|
std::wstring ret;
|
|
|
|
ret.resize(dwBufferSize / sizeof(wchar_t));
|
|
|
|
|
|
|
|
rc = RegQueryValueExW(k, valuename, nullptr, &dwType, reinterpret_cast<LPBYTE>(ret.data()), &dwBufferSize);
|
|
|
|
if (rc != ERROR_SUCCESS || !is_string_keytype(dwType) || dwBufferSize != sizeof(wchar_t) * ret.size())
|
2017-03-29 06:05:55 +08:00
|
|
|
return nullopt;
|
2017-03-11 07:43:54 +08:00
|
|
|
|
|
|
|
ret.pop_back(); // remove extra trailing null byte
|
2017-03-29 06:05:55 +08:00
|
|
|
return ret;
|
2017-03-11 07:43:54 +08:00
|
|
|
}
|
2017-04-01 08:24:45 +08:00
|
|
|
|
|
|
|
static const fs::path& get_ProgramFiles()
|
|
|
|
{
|
2017-05-05 05:58:18 +08:00
|
|
|
static const fs::path p = System::get_environment_variable(L"PROGRAMFILES").value_or_exit(VCPKG_LINE_INFO);
|
2017-04-01 08:24:45 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
const fs::path& get_ProgramFiles_32_bit()
|
|
|
|
{
|
2017-04-28 09:08:52 +08:00
|
|
|
static const fs::path p = []() -> fs::path {
|
2017-05-05 05:58:18 +08:00
|
|
|
auto value = System::get_environment_variable(L"ProgramFiles(x86)");
|
2017-04-28 09:08:52 +08:00
|
|
|
if (auto v = value.get())
|
2017-04-01 08:24:45 +08:00
|
|
|
{
|
2017-04-28 09:08:52 +08:00
|
|
|
return std::move(*v);
|
|
|
|
}
|
|
|
|
return get_ProgramFiles();
|
|
|
|
}();
|
2017-04-01 08:24:45 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
const fs::path& get_ProgramFiles_platform_bitness()
|
|
|
|
{
|
2017-04-28 09:08:52 +08:00
|
|
|
static const fs::path p = []() -> fs::path {
|
2017-05-05 05:58:18 +08:00
|
|
|
auto value = System::get_environment_variable(L"ProgramW6432");
|
2017-04-28 09:08:52 +08:00
|
|
|
if (auto v = value.get())
|
2017-04-01 08:24:45 +08:00
|
|
|
{
|
2017-04-28 09:08:52 +08:00
|
|
|
return std::move(*v);
|
|
|
|
}
|
|
|
|
return get_ProgramFiles();
|
|
|
|
}();
|
2017-04-01 08:24:45 +08:00
|
|
|
return p;
|
|
|
|
}
|
2017-01-06 04:47:08 +08:00
|
|
|
}
|
2017-05-06 05:37:58 +08:00
|
|
|
|
|
|
|
namespace vcpkg::Debug
|
|
|
|
{
|
|
|
|
void println(const CStringView message)
|
|
|
|
{
|
2017-08-24 07:17:53 +08:00
|
|
|
if (GlobalState::debugging)
|
2017-05-06 05:37:58 +08:00
|
|
|
{
|
|
|
|
System::println("[DEBUG] %s", message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void println(const System::Color c, const CStringView message)
|
|
|
|
{
|
2017-08-24 07:17:53 +08:00
|
|
|
if (GlobalState::debugging)
|
2017-05-06 05:37:58 +08:00
|
|
|
{
|
|
|
|
System::println(c, "[DEBUG] %s", message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|