aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authorAlexander Karatarakis <alkarata@microsoft.com>2018-05-05 04:23:19 -0700
committerAlexander Karatarakis <alkarata@microsoft.com>2018-05-15 23:27:14 -0700
commit1b0682a39e1143660c3d5aa371f66591a64e8a5d (patch)
treefed8de963661a5176f70b74b91ab1cef7bf00a74 /toolsrc/src
parent52f01eefa6e1da7a9458807a1eb3d288ecd50613 (diff)
downloadvcpkg-1b0682a39e1143660c3d5aa371f66591a64e8a5d.tar.gz
vcpkg-1b0682a39e1143660c3d5aa371f66591a64e8a5d.zip
[vcpkg] Significantly reduce usage of powershell. Reduce console font switching bug
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/vcpkg/base/checks.cpp2
-rw-r--r--toolsrc/src/vcpkg/base/system.cpp19
-rw-r--r--toolsrc/src/vcpkg/build.cpp14
-rw-r--r--toolsrc/src/vcpkg/commands.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.fetch.cpp509
-rw-r--r--toolsrc/src/vcpkg/commands.hash.cpp7
-rw-r--r--toolsrc/src/vcpkg/export.cpp2
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp9
8 files changed, 416 insertions, 148 deletions
diff --git a/toolsrc/src/vcpkg/base/checks.cpp b/toolsrc/src/vcpkg/base/checks.cpp
index d96cb98ff..2ac5f9a15 100644
--- a/toolsrc/src/vcpkg/base/checks.cpp
+++ b/toolsrc/src/vcpkg/base/checks.cpp
@@ -16,6 +16,8 @@ namespace vcpkg::Checks
const auto elapsed_us = GlobalState::timer.lock()->microseconds();
+ Debug::println("Exiting after %d us", static_cast<int>(elapsed_us));
+
auto metrics = Metrics::g_metrics.lock();
metrics->track_metric("elapsed_us", elapsed_us);
GlobalState::debugging = false;
diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp
index 95c9511f9..4da4548af 100644
--- a/toolsrc/src/vcpkg/base/system.cpp
+++ b/toolsrc/src/vcpkg/base/system.cpp
@@ -155,6 +155,7 @@ namespace vcpkg::System
int cmd_execute_clean(const CStringView cmd_line, const std::unordered_map<std::string, std::string>& extra_env)
{
+ auto timer = Chrono::ElapsedTimer::create_started();
#if defined(_WIN32)
static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO);
static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)";
@@ -271,7 +272,7 @@ namespace vcpkg::System
DWORD exit_code = 0;
GetExitCodeProcess(process_info.hProcess, &exit_code);
- Debug::println("CreateProcessW() returned %lu", exit_code);
+ Debug::println("CreateProcessW() returned %lu after %d us", exit_code, static_cast<int>(timer.microseconds()));
return static_cast<int>(exit_code);
#else
Debug::println("system(%s)", cmd_line.c_str());
@@ -369,13 +370,20 @@ namespace vcpkg::System
#endif
}
+#if defined(_WIN32)
void powershell_execute(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters)
{
+ SetConsoleCP(437);
+ SetConsoleOutputCP(437);
+
const std::string cmd = make_powershell_cmd(script_path, parameters);
const int rc = System::cmd_execute(cmd);
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+
if (rc)
{
System::println(Color::error,
@@ -394,14 +402,22 @@ namespace vcpkg::System
Checks::exit_with_code(VCPKG_LINE_INFO, rc);
}
}
+#endif
+#if defined(_WIN32)
std::string powershell_execute_and_capture_output(const std::string& title,
const fs::path& script_path,
const std::vector<PowershellParameter>& parameters)
{
+ SetConsoleCP(437);
+ SetConsoleOutputCP(437);
+
const std::string cmd = make_powershell_cmd(script_path, parameters);
auto rc = System::cmd_execute_and_capture_output(cmd);
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+
if (rc.exit_code)
{
System::println(Color::error,
@@ -433,6 +449,7 @@ namespace vcpkg::System
return rc.output;
}
+#endif
void println() { putchar('\n'); }
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index 1ed5e744a..b8ccb15bf 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -461,9 +461,9 @@ namespace vcpkg::Build
abi_tag_entries.insert(abi_tag_entries.end(), dependency_abis.begin(), dependency_abis.end());
abi_tag_entries.emplace_back(
- AbiEntry{"portfile", Commands::Hash::get_file_hash(paths, config.port_dir / "portfile.cmake", "SHA1")});
+ AbiEntry{"portfile", Commands::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")});
abi_tag_entries.emplace_back(
- AbiEntry{"control", Commands::Hash::get_file_hash(paths, config.port_dir / "CONTROL", "SHA1")});
+ AbiEntry{"control", Commands::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")});
abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
@@ -498,7 +498,7 @@ namespace vcpkg::Build
const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt");
fs.write_contents(abi_file_path, full_abi_info);
- return AbiTagAndFile{Commands::Hash::get_file_hash(paths, abi_file_path, "SHA1"), abi_file_path};
+ return AbiTagAndFile{Commands::Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path};
}
System::println(
@@ -783,14 +783,12 @@ namespace vcpkg::Build
{
return it_hash->second;
}
- auto hash = Commands::Hash::get_file_hash(paths, triplet_file_path, "SHA1");
+ auto hash = Commands::Hash::get_file_hash(paths.get_filesystem(), triplet_file_path, "SHA1");
s_hash_cache.emplace(triplet_file_path, hash);
return hash;
}
- else
- {
- return std::string();
- }
+
+ return std::string();
}();
const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp
index 8b6ffb3d7..09da57705 100644
--- a/toolsrc/src/vcpkg/commands.cpp
+++ b/toolsrc/src/vcpkg/commands.cpp
@@ -43,7 +43,7 @@ namespace vcpkg::Commands
{"portsdiff", &PortsDiff::perform_and_exit},
{"autocomplete", &Autocomplete::perform_and_exit},
{"hash", &Hash::perform_and_exit},
- // {"fetch", &Fetch::perform_and_exit},
+ {"fetch", &Fetch::perform_and_exit},
};
return t;
}
diff --git a/toolsrc/src/vcpkg/commands.fetch.cpp b/toolsrc/src/vcpkg/commands.fetch.cpp
index a6cfec3f0..d50d13c59 100644
--- a/toolsrc/src/vcpkg/commands.fetch.cpp
+++ b/toolsrc/src/vcpkg/commands.fetch.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include <vcpkg/base/checks.h>
+#include <vcpkg/base/sortedvector.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.h>
#include <vcpkg/base/util.h>
@@ -19,6 +20,7 @@ namespace vcpkg::Commands::Fetch
fs::path exe_path;
std::string url;
fs::path download_path;
+ bool is_archive;
fs::path tool_dir_path;
std::string sha512;
};
@@ -41,20 +43,85 @@ namespace vcpkg::Commands::Fetch
return result;
}
- static Optional<std::string> extract_string_between_delimiters(const std::string& input,
- const std::string& left_delim,
- const std::string& right_delim,
- const size_t& starting_offset = 0)
+ struct VcpkgStringRange
{
- const size_t from = input.find(left_delim, starting_offset);
- if (from == std::string::npos) return nullopt;
+ VcpkgStringRange() = default;
- const size_t substring_start = from + left_delim.length();
+ // Implicit by design
+ VcpkgStringRange(const std::string& s) : begin(s.cbegin()), end(s.cend()) {}
- const size_t to = input.find(right_delim, substring_start);
- if (from == std::string::npos) return nullopt;
+ VcpkgStringRange(const std::string::const_iterator begin, const std::string::const_iterator end)
+ : begin(begin), end(end)
+ {
+ }
+
+ std::string::const_iterator begin;
+ std::string::const_iterator end;
+
+ std::string to_string() const { return std::string(this->begin, this->end); }
+ };
+
+ static std::vector<VcpkgStringRange> find_all_enclosed(const VcpkgStringRange& input,
+ const std::string& left_delim,
+ const std::string& right_delim)
+ {
+ std::string::const_iterator it_left = input.begin;
+ std::string::const_iterator it_right = input.begin;
+
+ std::vector<VcpkgStringRange> output;
- return input.substr(substring_start, to - substring_start);
+ while (true)
+ {
+ it_left = std::search(it_right, input.end, left_delim.cbegin(), left_delim.cend());
+ if (it_left == input.end) break;
+
+ it_left += left_delim.length();
+
+ it_right = std::search(it_left, input.end, right_delim.cbegin(), right_delim.cend());
+ if (it_right == input.end) break;
+
+ output.emplace_back(it_left, it_right);
+
+ ++it_right;
+ }
+
+ return output;
+ }
+
+ static VcpkgStringRange find_exactly_one_enclosed(const VcpkgStringRange& input,
+ const std::string& left_tag,
+ const std::string& right_tag)
+ {
+ std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ result.size() == 1,
+ "Found %d sets of %s.*%s but expected exactly 1, in block:\n%s",
+ result.size(),
+ left_tag,
+ right_tag,
+ input);
+ return std::move(result.front());
+ }
+
+ static Optional<VcpkgStringRange> find_at_most_one_enclosed(const VcpkgStringRange& input,
+ const std::string& left_tag,
+ const std::string& right_tag)
+ {
+ std::vector<VcpkgStringRange> result = find_all_enclosed(input, left_tag, right_tag);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ result.size() <= 1,
+ "Found %d sets of %s.*%s but expected at most 1, in block:\n%s",
+ result.size(),
+ left_tag,
+ right_tag,
+ input);
+
+ if (result.empty())
+ {
+ return nullopt;
+ }
+
+ return result.front();
}
static ToolData parse_tool_data_from_xml(const VcpkgPaths& paths, const std::string& tool)
@@ -72,21 +139,6 @@ namespace vcpkg::Commands::Fetch
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
static const std::string XML_VERSION = "2";
static const fs::path XML_PATH = paths.scripts / "vcpkgTools.xml";
-
- const auto get_string_inside_tags =
- [](const std::string& input, const std::string& left_delim, const std::string& right_delim) -> std::string {
- Optional<std::string> result = extract_string_between_delimiters(input, left_delim, right_delim);
- Checks::check_exit(VCPKG_LINE_INFO,
- result.has_value(),
- "Could not find tag <%s>.*<%s> in %s",
- left_delim,
- right_delim,
- XML_PATH.generic_string());
-
- auto r = *result.get();
- return Strings::trim(std::move(r));
- };
-
static const std::regex XML_VERSION_REGEX{R"###(<tools[\s]+version="([^"]+)">)###"};
static const std::string XML = paths.get_filesystem().read_contents(XML_PATH).value_or_exit(VCPKG_LINE_INFO);
std::smatch match_xml_version;
@@ -112,14 +164,14 @@ namespace vcpkg::Commands::Fetch
tool,
XML_PATH.generic_string());
- const std::string tool_data = get_string_inside_tags(XML, match_tool_entry[0], R"(</tool>)");
-
- const std::string version_as_string = get_string_inside_tags(tool_data, "<version>", R"(</version>)");
+ const std::string tool_data = find_exactly_one_enclosed(XML, match_tool_entry[0], "</tool>").to_string();
+ const std::string version_as_string =
+ find_exactly_one_enclosed(tool_data, "<version>", "</version>").to_string();
const std::string exe_relative_path =
- get_string_inside_tags(tool_data, "<exeRelativePath>", R"(</exeRelativePath>)");
- const std::string url = get_string_inside_tags(tool_data, "<url>", R"(</url>)");
- const std::string sha512 = get_string_inside_tags(tool_data, "<sha512>", R"(</sha512>)");
- auto archive_name = extract_string_between_delimiters(tool_data, "<archiveName>", R"(</archiveName>)");
+ find_exactly_one_enclosed(tool_data, "<exeRelativePath>", "</exeRelativePath>").to_string();
+ const std::string url = find_exactly_one_enclosed(tool_data, "<url>", "</url>").to_string();
+ const std::string sha512 = find_exactly_one_enclosed(tool_data, "<sha512>", "</sha512>").to_string();
+ auto archive_name = find_at_most_one_enclosed(tool_data, "<archiveName>", "</archiveName>");
const Optional<std::array<int, 3>> version = parse_version_string(version_as_string);
Checks::check_exit(VCPKG_LINE_INFO,
@@ -129,13 +181,14 @@ namespace vcpkg::Commands::Fetch
version_as_string);
const std::string tool_dir_name = Strings::format("%s-%s-%s", tool, version_as_string, OS_STRING);
- const fs::path tool_dir_path = paths.downloads / "tools" / tool_dir_name;
+ const fs::path tool_dir_path = paths.tools / tool_dir_name;
const fs::path exe_path = tool_dir_path / exe_relative_path;
return ToolData{*version.get(),
exe_path,
url,
- paths.downloads / archive_name.value_or(exe_relative_path),
+ paths.downloads / archive_name.value_or(exe_relative_path).to_string(),
+ archive_name.has_value(),
tool_dir_path,
sha512};
#endif
@@ -163,51 +216,87 @@ namespace vcpkg::Commands::Fetch
actual_version[2] >= expected_version[2]));
}
- static Optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths,
+ static Optional<fs::path> find_if_has_equal_or_greater_version(Files::Filesystem& fs,
+ const std::vector<fs::path>& candidate_paths,
const std::string& version_check_arguments,
const std::array<int, 3>& expected_version)
{
- auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
+ const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) {
+ if (!fs.exists(p)) return false;
const std::string cmd = Strings::format(R"("%s" %s)", p.u8string(), version_check_arguments);
return exists_and_has_equal_or_greater_version(cmd, expected_version);
});
if (it != candidate_paths.cend())
{
- return std::move(*it);
+ return *it;
}
return nullopt;
}
- static std::vector<std::string> keep_data_lines(const std::string& data_blob)
- {
- static const std::regex DATA_LINE_REGEX(R"(<sol>::(.+?)(?=::<eol>))");
-
- std::vector<std::string> data_lines;
-
- const std::sregex_iterator it(data_blob.cbegin(), data_blob.cend(), DATA_LINE_REGEX);
- const std::sregex_iterator end;
- for (std::sregex_iterator i = it; i != end; ++i)
- {
- const std::smatch match = *i;
- data_lines.push_back(match[1].str());
- }
-
- return data_lines;
- }
-
-#if !defined(_WIN32)
static void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path)
{
Files::Filesystem& fs = paths.get_filesystem();
const fs::path to_path_partial = to_path.u8string() + ".partial";
std::error_code ec;
+ fs.remove_all(to_path, ec);
fs.remove_all(to_path_partial, ec);
fs.create_directories(to_path_partial, ec);
-
const auto ext = archive.extension();
+#if defined(_WIN32)
+ if (ext == ".nupkg")
+ {
+ static bool recursion_limiter_sevenzip_old = false;
+ Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip_old);
+ recursion_limiter_sevenzip_old = true;
+ const auto nuget_exe = get_tool_path(paths, Tools::NUGET);
+
+ const std::string stem = archive.stem().u8string();
+ // assuming format of [name].[version in the form d.d.d]
+ // This assumption may not always hold
+ std::smatch match;
+ const bool has_match = std::regex_match(stem, match, std::regex{R"###(^(.+)\.(\d+\.\d+\.\d+)$)###"});
+ Checks::check_exit(VCPKG_LINE_INFO,
+ has_match,
+ "Could not deduce nuget id and version from filename: %s",
+ archive.u8string());
+
+ const std::string nugetid = match[1];
+ const std::string version = match[2];
+
+ const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format(
+ R"("%s" install %s -Version %s -OutputDirectory "%s" -Source "%s" -nocache -DirectDownload -NonInteractive -ForceEnglishOutput -PackageSaveMode nuspec)",
+ nuget_exe.u8string(),
+ nugetid,
+ version,
+ to_path_partial.u8string(),
+ paths.downloads.u8string()));
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ code_and_output.exit_code == 0,
+ "Failed to extract '%s' with message:\n%s",
+ archive.u8string(),
+ code_and_output.output);
+ recursion_limiter_sevenzip_old = false;
+ }
+ else
+ {
+ static bool recursion_limiter_sevenzip = false;
+ Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip);
+ recursion_limiter_sevenzip = true;
+ const auto seven_zip = get_tool_path(paths, Tools::SEVEN_ZIP);
+ const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format(
+ R"("%s" x "%s" -o"%s" -y)", seven_zip.u8string(), archive.u8string(), to_path_partial.u8string()));
+ Checks::check_exit(VCPKG_LINE_INFO,
+ code_and_output.exit_code == 0,
+ "7zip failed while extracting '%s' with message:\n%s",
+ archive.u8string(),
+ code_and_output.output);
+ recursion_limiter_sevenzip = false;
+ }
+#else
if (ext == ".gz" && ext.extension() != ".tar")
{
const auto code = System::cmd_execute(
@@ -224,16 +313,23 @@ namespace vcpkg::Commands::Fetch
{
Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string());
}
+#endif
- fs.rename(to_path_partial, to_path);
+ fs.rename(to_path_partial, to_path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !ec,
+ "Failed to do post-extract rename-in-place.\nfs.rename(%s, %s, %s)",
+ to_path_partial.u8string(),
+ to_path.u8string(),
+ ec.message());
}
- static void verify_hash(const VcpkgPaths& paths,
+ static void verify_hash(const Files::Filesystem& fs,
const std::string& url,
const fs::path& path,
const std::string& sha512)
{
- const std::string actual_hash = Hash::get_file_hash(paths, path, "SHA512");
+ const std::string actual_hash = Hash::get_file_hash(fs, path, "SHA512");
Checks::check_exit(VCPKG_LINE_INFO,
sha512 == actual_hash,
"File does not have the expected hash:\n"
@@ -247,24 +343,119 @@ namespace vcpkg::Commands::Fetch
actual_hash);
}
- static void download_file(const VcpkgPaths& paths,
+#if defined(_WIN32)
+ static void winhttp_download_file(Files::Filesystem& fs,
+ CStringView target_file_path,
+ CStringView hostname,
+ CStringView url_path)
+ {
+ // Make sure the directories are present, otherwise fopen_s fails
+ const auto dir = fs::path(target_file_path.c_str()).parent_path();
+ std::error_code ec;
+ fs.create_directories(dir, ec);
+ Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not create directories %s", dir.u8string());
+
+ FILE* f = nullptr;
+ const errno_t err = fopen_s(&f, target_file_path.c_str(), "wb");
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !err,
+ "Could not download https://%s%s. Failed to open file %s. Error code was %s",
+ hostname,
+ url_path,
+ target_file_path,
+ std::to_string(err));
+
+ auto hSession = WinHttpOpen(
+ L"vcpkg/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, hSession, "WinHttpOpen() failed: %d", GetLastError());
+
+ // Use Windows 10 defaults on Windows 7
+ DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
+ WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2);
+ WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols));
+
+ // Specify an HTTP server.
+ auto hConnect = WinHttpConnect(hSession, Strings::to_utf16(hostname).c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, hConnect, "WinHttpConnect() failed: %d", GetLastError());
+
+ // Create an HTTP request handle.
+ auto hRequest = WinHttpOpenRequest(hConnect,
+ L"GET",
+ Strings::to_utf16(url_path).c_str(),
+ nullptr,
+ WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ WINHTTP_FLAG_SECURE);
+ Checks::check_exit(VCPKG_LINE_INFO, hRequest, "WinHttpOpenRequest() failed: %d", GetLastError());
+
+ // Send a request.
+ auto bResults =
+ WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpSendRequest() failed: %d", GetLastError());
+
+ // End the request.
+ bResults = WinHttpReceiveResponse(hRequest, NULL);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReceiveResponse() failed: %d", GetLastError());
+
+ std::vector<char> buf;
+
+ size_t total_downloaded_size = 0;
+ DWORD dwSize = 0;
+ do
+ {
+ DWORD downloaded_size = 0;
+ bResults = WinHttpQueryDataAvailable(hRequest, &dwSize);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpQueryDataAvailable() failed: %d", GetLastError());
+
+ if (buf.size() < dwSize) buf.resize(dwSize * 2);
+
+ bResults = WinHttpReadData(hRequest, (LPVOID)buf.data(), dwSize, &downloaded_size);
+ Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReadData() failed: %d", GetLastError());
+ fwrite(buf.data(), 1, downloaded_size, f);
+
+ total_downloaded_size += downloaded_size;
+ } while (dwSize > 0);
+
+ WinHttpCloseHandle(hSession);
+ WinHttpCloseHandle(hConnect);
+ WinHttpCloseHandle(hRequest);
+ fflush(f);
+ fclose(f);
+ }
+#endif
+
+ static void download_file(Files::Filesystem& fs,
const std::string& url,
const fs::path& download_path,
const std::string& sha512)
{
- Files::Filesystem& fs = paths.get_filesystem();
const std::string download_path_part = download_path.u8string() + ".part";
std::error_code ec;
+ fs.remove(download_path, ec);
fs.remove(download_path_part, ec);
+#if defined(_WIN32)
+ auto url_no_proto = url.substr(8); // drop https://
+ auto path_begin = Util::find(url_no_proto, '/');
+ std::string hostname(url_no_proto.begin(), path_begin);
+ std::string path(path_begin, url_no_proto.end());
+
+ winhttp_download_file(fs, download_path_part.c_str(), hostname, path);
+#else
const auto code = System::cmd_execute(
Strings::format(R"(curl -L '%s' --create-dirs --output '%s')", url, download_path_part));
Checks::check_exit(VCPKG_LINE_INFO, code == 0, "Could not download %s", url);
+#endif
- verify_hash(paths, url, download_path_part, sha512);
- fs.rename(download_path_part, download_path);
+ verify_hash(fs, url, download_path_part, sha512);
+ fs.rename(download_path_part, download_path, ec);
+ Checks::check_exit(VCPKG_LINE_INFO,
+ !ec,
+ "Failed to do post-download rename-in-place.\nfs.rename(%s, %s, %s)",
+ download_path_part,
+ download_path.u8string(),
+ ec.message());
}
-#endif
static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data)
{
const std::array<int, 3>& version = tool_data.version;
@@ -280,50 +471,37 @@ namespace vcpkg::Commands::Fetch
version_as_string,
tool_name,
version_as_string);
-#if defined(_WIN32)
- const fs::path script = paths.scripts / "fetchtool.ps1";
- const std::string title = Strings::format(
- "Fetching %s version %s (No sufficient installed version was found)", tool_name, version_as_string);
- const System::PowershellParameter tool_param("tool", tool_name);
- const std::string output = System::powershell_execute_and_capture_output(title, script, {tool_param});
-
- const std::vector<std::string> tool_path = keep_data_lines(output);
- Checks::check_exit(VCPKG_LINE_INFO, tool_path.size() == 1, "Expected tool path, but got %s", output);
-
- const fs::path actual_downloaded_path = Strings::trim(std::string{tool_path.at(0)});
- const fs::path& expected_downloaded_path = tool_data.exe_path;
- std::error_code ec;
- const auto eq = fs::stdfs::equivalent(expected_downloaded_path, actual_downloaded_path, ec);
- Checks::check_exit(VCPKG_LINE_INFO,
- eq && !ec,
- "Expected tool downloaded path to be %s, but was %s",
- expected_downloaded_path.u8string(),
- actual_downloaded_path.u8string());
- return actual_downloaded_path;
-#else
- const auto& fs = paths.get_filesystem();
+ auto& fs = paths.get_filesystem();
if (!fs.exists(tool_data.download_path))
{
System::println("Downloading %s...", tool_name);
- download_file(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ download_file(fs, tool_data.url, tool_data.download_path, tool_data.sha512);
System::println("Downloading %s... done.", tool_name);
}
else
{
- verify_hash(paths, tool_data.url, tool_data.download_path, tool_data.sha512);
+ verify_hash(fs, tool_data.url, tool_data.download_path, tool_data.sha512);
}
- System::println("Extracting %s...", tool_name);
- extract_archive(paths, tool_data.download_path, tool_data.tool_dir_path);
- System::println("Extracting %s... done.", tool_name);
+ if (tool_data.is_archive)
+ {
+ System::println("Extracting %s...", tool_name);
+ extract_archive(paths, tool_data.download_path, tool_data.tool_dir_path);
+ System::println("Extracting %s... done.", tool_name);
+ }
+ else
+ {
+ std::error_code ec;
+ fs.create_directories(tool_data.exe_path.parent_path(), ec);
+ fs.rename(tool_data.download_path, tool_data.exe_path, ec);
+ }
Checks::check_exit(VCPKG_LINE_INFO,
fs.exists(tool_data.exe_path),
- "Expected %s to exist after extracting",
- tool_data.exe_path);
+ "Expected %s to exist after fetching",
+ tool_data.exe_path.u8string());
return tool_data.exe_path;
-#endif
}
static fs::path get_cmake_path(const VcpkgPaths& paths)
@@ -345,8 +523,8 @@ namespace vcpkg::Commands::Fetch
const auto& program_files_32_bit = System::get_program_files_32_bit();
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -378,7 +556,8 @@ namespace vcpkg::Commands::Fetch
const std::vector<fs::path> from_path = Files::find_from_PATH("ninja");
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "--version", TOOL_DATA.version);
+ auto path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, "--version", TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -396,7 +575,8 @@ namespace vcpkg::Commands::Fetch
const std::vector<fs::path> from_path = Files::find_from_PATH("nuget");
candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
- auto path = find_if_has_equal_or_greater_version(candidate_paths, "", TOOL_DATA.version);
+ auto path =
+ find_if_has_equal_or_greater_version(paths.get_filesystem(), candidate_paths, "", TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -422,8 +602,8 @@ namespace vcpkg::Commands::Fetch
const auto& program_files_32_bit = System::get_program_files_32_bit();
if (const auto pf = program_files_32_bit.get()) candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -448,8 +628,8 @@ namespace vcpkg::Commands::Fetch
// candidate_paths.push_back(fs::path(System::get_environment_variable("HOMEDRIVE").value_or("C:")) / "Qt" /
// "QtIFW-3.1.0" / "bin" / "installerbase.exe");
- const Optional<fs::path> path =
- find_if_has_equal_or_greater_version(candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
+ const Optional<fs::path> path = find_if_has_equal_or_greater_version(
+ paths.get_filesystem(), candidate_paths, VERSION_CHECK_ARGUMENTS, TOOL_DATA.version);
if (const auto p = path.get())
{
return *p;
@@ -460,48 +640,114 @@ namespace vcpkg::Commands::Fetch
struct VisualStudioInstance
{
+ enum class ReleaseType
+ {
+ STABLE,
+ PRERELEASE,
+ LEGACY
+ };
+
+ static bool prefered_first_comparator(const VisualStudioInstance& left, const VisualStudioInstance& right)
+ {
+ const auto get_preference_weight = [](const ReleaseType& type) -> int {
+ switch (type)
+ {
+ case ReleaseType::STABLE: return 3;
+ case ReleaseType::PRERELEASE: return 2;
+ case ReleaseType::LEGACY: return 1;
+ default: Checks::unreachable(VCPKG_LINE_INFO);
+ }
+ };
+
+ if (left.release_type != right.release_type)
+ {
+ return get_preference_weight(left.release_type) > get_preference_weight(right.release_type);
+ }
+
+ return left.version > right.version;
+ }
+
+ VisualStudioInstance(fs::path&& root_path, std::string&& version, const ReleaseType& release_type)
+ : root_path(std::move(root_path)), version(std::move(version)), release_type(release_type)
+ {
+ }
+
fs::path root_path;
std::string version;
- std::string release_type;
- std::string preference_weight; // Mostly unused, just for verification that order is as intended
+ ReleaseType release_type;
std::string major_version() const { return version.substr(0, 2); }
};
static std::vector<VisualStudioInstance> get_visual_studio_instances(const VcpkgPaths& paths)
{
- const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
- const std::string output =
- System::powershell_execute_and_capture_output("Detecting Visual Studio instances", script);
+ const auto& fs = paths.get_filesystem();
+
+ const auto& program_files_32_bit = System::get_program_files_32_bit().value_or_exit(VCPKG_LINE_INFO);
+ const fs::path vswhere_exe = program_files_32_bit / "Microsoft Visual Studio" / "Installer" / "vswhere.exe";
+ Checks::check_exit(
+ VCPKG_LINE_INFO, fs.exists(vswhere_exe), "Could not locate vswhere at %s", vswhere_exe.u8string());
+
+ const auto code_and_output = System::cmd_execute_and_capture_output(
+ Strings::format(R"("%s" -prerelease -legacy -products * -format xml)", vswhere_exe.u8string()));
- const std::vector<std::string> instances_as_strings = keep_data_lines(output);
Checks::check_exit(VCPKG_LINE_INFO,
- !instances_as_strings.empty(),
- "Could not detect any Visual Studio instances.\n"
- "Powershell script:\n"
- " %s\n"
- "returned:\n"
- "%s",
- script.generic_string(),
- output);
+ code_and_output.exit_code == 0,
+ "Running vswhere.exe failed with message:\n%s",
+ code_and_output.output);
+
+ const auto& xml_as_string = code_and_output.output;
+
+ const auto instance_entries = find_all_enclosed(xml_as_string, "<instance>", "</instance>");
std::vector<VisualStudioInstance> instances;
- for (const std::string& instance_as_string : instances_as_strings)
+ for (const VcpkgStringRange& instance : instance_entries)
{
- const std::vector<std::string> split = Strings::split(instance_as_string, "::");
- Checks::check_exit(VCPKG_LINE_INFO,
- split.size() == 4,
- "Invalid Visual Studio instance format.\n"
- "Expected: PreferenceWeight::ReleaseType::Version::PathToVisualStudio\n"
- "Actual : %s\n",
- instance_as_string);
- instances.push_back({split.at(3), split.at(2), split.at(1), split.at(0)});
+ auto maybe_is_prerelease = find_at_most_one_enclosed(instance, "<isPrerelease>", "</isPrerelease>");
+
+ VisualStudioInstance::ReleaseType release_type = VisualStudioInstance::ReleaseType::LEGACY;
+ if (auto p = maybe_is_prerelease.get())
+ {
+ auto s = p->to_string();
+ if (s == "0")
+ release_type = VisualStudioInstance::ReleaseType::STABLE;
+ else if (s == "1")
+ release_type = VisualStudioInstance::ReleaseType::PRERELEASE;
+ else
+ Checks::unreachable(VCPKG_LINE_INFO);
+ }
+
+ instances.emplace_back(
+ find_exactly_one_enclosed(instance, "<installationPath>", "</installationPath>").to_string(),
+ find_exactly_one_enclosed(instance, "<installationVersion>", "</installationVersion>").to_string(),
+ release_type);
}
+ const auto append_if_has_cl = [&](fs::path&& path_root) {
+ const auto cl_exe = path_root / "VC" / "bin" / "cl.exe";
+ const auto vcvarsall_bat = path_root / "VC" / "vcvarsall.bat";
+
+ if (fs.exists(cl_exe) && fs.exists(vcvarsall_bat))
+ instances.emplace_back(std::move(path_root), "14.0", VisualStudioInstance::ReleaseType::LEGACY);
+ };
+
+ auto maybe_vs140comntools = System::get_environment_variable("vs140comntools");
+ if (const auto path_as_string = maybe_vs140comntools.get())
+ {
+ // We want lexically_normal(), but it is not available
+ // Correct root path might be 2 or 3 levels up, depending on if the path has trailing backslash. Try both.
+ auto common7_tools = fs::path{*path_as_string};
+ append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path());
+ append_if_has_cl(fs::path{*path_as_string}.parent_path().parent_path().parent_path());
+ }
+
+ append_if_has_cl(program_files_32_bit / "Microsoft Visual Studio 14.0");
+
return instances;
}
- std::vector<Toolset> find_toolset_instances(const VcpkgPaths& paths)
+#if defined(_WIN32)
+ std::vector<Toolset> find_toolset_instances_prefered_first(const VcpkgPaths& paths)
{
using CPU = System::CPUArchitecture;
@@ -513,12 +759,14 @@ namespace vcpkg::Commands::Fetch
std::vector<Toolset> found_toolsets;
std::vector<Toolset> excluded_toolsets;
- const std::vector<VisualStudioInstance> vs_instances = get_visual_studio_instances(paths);
- const bool v140_is_available = Util::find_if(vs_instances, [&](const VisualStudioInstance& vs_instance) {
+ const SortedVector<VisualStudioInstance> sorted{get_visual_studio_instances(paths),
+ VisualStudioInstance::prefered_first_comparator};
+
+ const bool v140_is_available = Util::find_if(sorted, [&](const VisualStudioInstance& vs_instance) {
return vs_instance.major_version() == "14";
- }) != vs_instances.cend();
+ }) != sorted.end();
- for (const VisualStudioInstance& vs_instance : vs_instances)
+ for (const VisualStudioInstance& vs_instance : sorted)
{
const std::string major_version = vs_instance.major_version();
if (major_version == "15")
@@ -672,6 +920,7 @@ namespace vcpkg::Commands::Fetch
return found_toolsets;
}
+#endif
fs::path get_tool_path(const VcpkgPaths& paths, const std::string& tool)
{
diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp
index 1f709f87b..d7d653ca3 100644
--- a/toolsrc/src/vcpkg/commands.hash.cpp
+++ b/toolsrc/src/vcpkg/commands.hash.cpp
@@ -154,10 +154,9 @@ namespace vcpkg::Commands::Hash
};
}
- std::string get_file_hash(const VcpkgPaths& paths, const fs::path& path, const std::string& hash_type)
+ std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type)
{
- Checks::check_exit(
- VCPKG_LINE_INFO, paths.get_filesystem().exists(path), "File %s does not exist", path.u8string());
+ Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string());
return BCryptHasher{hash_type}.hash_file(path);
}
@@ -239,7 +238,7 @@ namespace vcpkg::Commands::Hash
const fs::path file_to_hash = args.command_arguments[0];
const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512";
- const std::string hash = get_file_hash(paths, file_to_hash, algorithm);
+ const std::string hash = get_file_hash(paths.get_filesystem(), file_to_hash, algorithm);
System::println(hash);
Checks::exit_success(VCPKG_LINE_INFO);
}
diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp
index 152252018..b13140de2 100644
--- a/toolsrc/src/vcpkg/export.cpp
+++ b/toolsrc/src/vcpkg/export.cpp
@@ -227,8 +227,6 @@ namespace vcpkg::Export
{fs::path{"scripts"} / "buildsystems" / "vcpkg.cmake"},
{fs::path{"scripts"} / "cmake" / "vcpkg_get_windows_sdk.cmake"},
{fs::path{"scripts"} / "getWindowsSDK.ps1"},
- {fs::path{"scripts"} / "getProgramFilesPlatformBitness.ps1"},
- {fs::path{"scripts"} / "getProgramFiles32bit.ps1"},
{fs::path{"scripts"} / "VcpkgPowershellUtils.ps1"},
};
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index 0903c2d76..caf09f526 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -39,6 +39,7 @@ namespace vcpkg
paths.triplets = paths.root / "triplets";
paths.scripts = paths.root / "scripts";
+ paths.tools = paths.downloads / "tools";
paths.buildsystems = paths.scripts / "buildsystems";
paths.buildsystems_msbuild_targets = paths.buildsystems / "msbuild" / "vcpkg.targets";
@@ -113,9 +114,11 @@ namespace vcpkg
return external_toolset;
}
- // Invariant: toolsets are non-empty and sorted with newest at back()
+#if !defined(_WIN32)
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot build windows triplets from non-windows.");
+#else
const std::vector<Toolset>& vs_toolsets =
- this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances(*this); });
+ this->toolsets.get_lazy([this]() { return Commands::Fetch::find_toolset_instances_prefered_first(*this); });
std::vector<const Toolset*> candidates = Util::element_pointers(vs_toolsets);
const auto tsv = prebuildinfo.platform_toolset.get();
@@ -159,6 +162,8 @@ namespace vcpkg
Checks::check_exit(VCPKG_LINE_INFO, !candidates.empty(), "No suitable Visual Studio instances were found");
return *candidates.front();
+
+#endif
}
Files::Filesystem& VcpkgPaths::get_filesystem() const { return Files::get_real_filesystem(); }