aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authorThomas Fussell <thomas.fussell@gmail.com>2017-03-12 17:44:06 -0400
committerThomas Fussell <thomas.fussell@gmail.com>2017-03-12 17:44:06 -0400
commit2f42035ab43dd50cd863b51944aa099a99ae60f0 (patch)
tree4b6cfd43955e946721c58028fd8564c861d5c331 /toolsrc/src
parente02e85626f3206feda86a6f5757009005e0cfe3e (diff)
parent1c9873a0daf625f67474aaf3e163c592c27ecb65 (diff)
downloadvcpkg-2f42035ab43dd50cd863b51944aa099a99ae60f0.tar.gz
vcpkg-2f42035ab43dd50cd863b51944aa099a99ae60f0.zip
Merge branch 'master' of git://github.com/Microsoft/vcpkg
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/BinaryParagraph.cpp19
-rw-r--r--toolsrc/src/BuildInfo.cpp164
-rw-r--r--toolsrc/src/MachineType.cpp42
-rw-r--r--toolsrc/src/Paragraphs.cpp84
-rw-r--r--toolsrc/src/PostBuildLint.cpp (renamed from toolsrc/src/post_build_lint.cpp)182
-rw-r--r--toolsrc/src/PostBuildLint_BuildInfo.cpp48
-rw-r--r--toolsrc/src/PostBuildLint_BuildPolicies.cpp70
-rw-r--r--toolsrc/src/PostBuildLint_BuildType.cpp85
-rw-r--r--toolsrc/src/PostBuildLint_ConfigurationType.cpp26
-rw-r--r--toolsrc/src/PostBuildLint_LinkageType.cpp41
-rw-r--r--toolsrc/src/SourceParagraph.cpp5
-rw-r--r--toolsrc/src/StatusParagraph.cpp1
-rw-r--r--toolsrc/src/StatusParagraphs.cpp8
-rw-r--r--toolsrc/src/coff_file_reader.cpp8
-rw-r--r--toolsrc/src/commands_available_commands.cpp46
-rw-r--r--toolsrc/src/commands_build.cpp183
-rw-r--r--toolsrc/src/commands_build_external.cpp20
-rw-r--r--toolsrc/src/commands_cache.cpp8
-rw-r--r--toolsrc/src/commands_ci.cpp120
-rw-r--r--toolsrc/src/commands_contact.cpp21
-rw-r--r--toolsrc/src/commands_create.cpp34
-rw-r--r--toolsrc/src/commands_edit.cpp56
-rw-r--r--toolsrc/src/commands_hash.cpp8
-rw-r--r--toolsrc/src/commands_help.cpp89
-rw-r--r--toolsrc/src/commands_helpers.cpp7
-rw-r--r--toolsrc/src/commands_import.cpp34
-rw-r--r--toolsrc/src/commands_install.cpp247
-rw-r--r--toolsrc/src/commands_installation.cpp368
-rw-r--r--toolsrc/src/commands_integrate.cpp (renamed from toolsrc/src/commands_integration.cpp)90
-rw-r--r--toolsrc/src/commands_list.cpp10
-rw-r--r--toolsrc/src/commands_other.cpp103
-rw-r--r--toolsrc/src/commands_owns.cpp10
-rw-r--r--toolsrc/src/commands_portsdiff.cpp77
-rw-r--r--toolsrc/src/commands_remove.cpp201
-rw-r--r--toolsrc/src/commands_search.cpp62
-rw-r--r--toolsrc/src/commands_update.cpp34
-rw-r--r--toolsrc/src/commands_version.cpp37
-rw-r--r--toolsrc/src/main.cpp248
-rw-r--r--toolsrc/src/metrics.cpp53
-rw-r--r--toolsrc/src/opt_bool.cpp29
-rw-r--r--toolsrc/src/package_spec.cpp15
-rw-r--r--toolsrc/src/package_spec_parse_result.cpp4
-rw-r--r--toolsrc/src/pch.cpp1
-rw-r--r--toolsrc/src/tests_paragraph.cpp4
-rw-r--r--toolsrc/src/triplet.cpp7
-rw-r--r--toolsrc/src/vcpkg.cpp368
-rw-r--r--toolsrc/src/vcpkg_Checks.cpp21
-rw-r--r--toolsrc/src/vcpkg_Chrono.cpp (renamed from toolsrc/src/Stopwatch.cpp)61
-rw-r--r--toolsrc/src/vcpkg_Dependencies.cpp99
-rw-r--r--toolsrc/src/vcpkg_Enums.cpp21
-rw-r--r--toolsrc/src/vcpkg_Environment.cpp219
-rw-r--r--toolsrc/src/vcpkg_Files.cpp11
-rw-r--r--toolsrc/src/vcpkg_Input.cpp9
-rw-r--r--toolsrc/src/vcpkg_Strings.cpp88
-rw-r--r--toolsrc/src/vcpkg_System.cpp171
-rw-r--r--toolsrc/src/vcpkg_cmd_arguments.cpp26
-rw-r--r--toolsrc/src/vcpkg_info.cpp34
-rw-r--r--toolsrc/src/vcpkg_metrics_uploader.cpp8
-rw-r--r--toolsrc/src/vcpkg_paths.cpp166
-rw-r--r--toolsrc/src/vcpkglib.cpp215
-rw-r--r--toolsrc/src/vcpkglib_helpers.cpp7
61 files changed, 2717 insertions, 1816 deletions
diff --git a/toolsrc/src/BinaryParagraph.cpp b/toolsrc/src/BinaryParagraph.cpp
index ad85a1f8a..8605cd276 100644
--- a/toolsrc/src/BinaryParagraph.cpp
+++ b/toolsrc/src/BinaryParagraph.cpp
@@ -1,3 +1,4 @@
+#include "pch.h"
#include "BinaryParagraph.h"
#include "vcpkglib_helpers.h"
#include "vcpkg_Checks.h"
@@ -22,22 +23,6 @@ namespace vcpkg
static const std::string DEPENDS = "Depends";
}
- static const std::vector<std::string>& get_list_of_valid_fields()
- {
- static const std::vector<std::string> valid_fields =
- {
- BinaryParagraphRequiredField::PACKAGE,
- BinaryParagraphRequiredField::VERSION,
- BinaryParagraphRequiredField::ARCHITECTURE,
-
- BinaryParagraphOptionalField::DESCRIPTION,
- BinaryParagraphOptionalField::MAINTAINER,
- BinaryParagraphOptionalField::DEPENDS
- };
-
- return valid_fields;
- }
-
BinaryParagraph::BinaryParagraph() = default;
BinaryParagraph::BinaryParagraph(std::unordered_map<std::string, std::string> fields)
@@ -70,7 +55,7 @@ namespace vcpkg
std::string BinaryParagraph::displayname() const
{
- return Strings::format("%s:%s", this->spec.name(), this->spec.target_triplet());
+ return this->spec.display_name();
}
std::string BinaryParagraph::dir() const
diff --git a/toolsrc/src/BuildInfo.cpp b/toolsrc/src/BuildInfo.cpp
deleted file mode 100644
index f151a3ea5..000000000
--- a/toolsrc/src/BuildInfo.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#include "BuildInfo.h"
-#include "vcpkg_Checks.h"
-#include "vcpkglib_helpers.h"
-
-namespace vcpkg { namespace PostBuildLint
-{
- const ConfigurationType& BuildType::config() const
- {
- return this->m_config;
- }
-
- const LinkageType& BuildType::linkage() const
- {
- return this->m_linkage;
- }
-
- std::regex BuildType::crt_regex() const
- {
- const std::regex r(this->m_crt_regex_as_string, std::regex_constants::icase);
- return r;
- }
-
- std::string BuildType::toString() const
- {
- const std::string s = Strings::format("[%s,%s]", to_string(this->m_config), to_string(this->m_linkage));
- return s;
- }
-
- bool operator==(const BuildType& lhs, const BuildType& rhs)
- {
- return lhs.config() == rhs.config() && lhs.linkage() == rhs.linkage();
- }
-
- bool operator!=(const BuildType& lhs, const BuildType& rhs)
- {
- return !(lhs == rhs);
- }
-
- //
- namespace BuildInfoRequiredField
- {
- static const std::string CRT_LINKAGE = "CRTLinkage";
- static const std::string LIBRARY_LINKAGE = "LibraryLinkage";
- }
-
- BuildInfo BuildInfo::create(const std::unordered_map<std::string, std::string>& pgh)
- {
- BuildInfo build_info;
- build_info.crt_linkage = details::required_field(pgh, BuildInfoRequiredField::CRT_LINKAGE);
- build_info.library_linkage = details::required_field(pgh, BuildInfoRequiredField::LIBRARY_LINKAGE);
-
- return build_info;
- }
-
- const BuildType BuildType::DEBUG_STATIC = BuildType(ConfigurationType::DEBUG, LinkageType::STATIC, R"(/DEFAULTLIB:LIBCMTD)");
- const BuildType BuildType::DEBUG_DYNAMIC = BuildType(ConfigurationType::DEBUG, LinkageType::DYNAMIC, R"(/DEFAULTLIB:MSVCRTD)");
- const BuildType BuildType::RELEASE_STATIC = BuildType(ConfigurationType::RELEASE, LinkageType::STATIC, R"(/DEFAULTLIB:LIBCMT[^D])");
- const BuildType BuildType::RELEASE_DYNAMIC = BuildType(ConfigurationType::RELEASE, LinkageType::DYNAMIC, R"(/DEFAULTLIB:MSVCRT[^D])");
-
- LinkageType linkage_type_value_of(const std::string& as_string)
-
- {
- if (as_string == "dynamic")
- {
- return LinkageType::DYNAMIC;
- }
-
- if (as_string == "static")
- {
- return LinkageType::STATIC;
- }
-
- return LinkageType::UNKNOWN;
- }
-
- std::string to_string(const LinkageType& build_info)
- {
- switch (build_info)
- {
- case LinkageType::STATIC:
- return "static";
- case LinkageType::DYNAMIC:
- return "dynamic";
- default:
- Checks::unreachable();
- }
- }
-
- std::string to_string(const ConfigurationType& conf)
- {
- switch (conf)
- {
- case ConfigurationType::DEBUG:
- return "Debug";
- case ConfigurationType::RELEASE:
- return "Release";
- default:
- Checks::unreachable();
- }
- }
-
- BuildType BuildType::value_of(const ConfigurationType& config, const LinkageType& linkage)
- {
- if (config == ConfigurationType::DEBUG && linkage == LinkageType::STATIC)
- {
- return DEBUG_STATIC;
- }
-
- if (config == ConfigurationType::DEBUG && linkage == LinkageType::DYNAMIC)
- {
- return DEBUG_DYNAMIC;
- }
-
- if (config == ConfigurationType::RELEASE && linkage == LinkageType::STATIC)
- {
- return RELEASE_STATIC;
- }
-
- if (config == ConfigurationType::RELEASE && linkage == LinkageType::DYNAMIC)
- {
- return RELEASE_DYNAMIC;
- }
-
- Checks::unreachable();
- }
-
- BuildInfo read_build_info(const fs::path& filepath)
- {
- const std::vector<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_paragraphs(filepath);
- Checks::check_exit(pghs.size() == 1, "Invalid BUILD_INFO file for package");
-
- return BuildInfo::create(pghs[0]);
- }
-
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP100_DLL = OutdatedDynamicCrt("msvcp100.dll", R"(msvcp100\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP100D_DLL = OutdatedDynamicCrt("msvcp100d.dll", R"(msvcp100d\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP110_DLL = OutdatedDynamicCrt("msvcp110.dll", R"(msvcp110\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP110_WIN_DLL = OutdatedDynamicCrt("msvcp110_win.dll", R"(msvcp110_win\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP120_DLL = OutdatedDynamicCrt("msvcp120.dll", R"(msvcp120\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP120_CLR0400_DLL = OutdatedDynamicCrt("msvcp120_clr0400.dll", R"(msvcp120_clr0400\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP60_DLL = OutdatedDynamicCrt("msvcp60.dll", R"(msvcp60\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCP_WIN_DLL = OutdatedDynamicCrt("msvcp60.dll", R"(msvcp60\.dll)");;
-
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR100_DLL = OutdatedDynamicCrt("msvcr100.dll", R"(msvcr100\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR100D_DLL = OutdatedDynamicCrt("msvcr100d.dll", R"(msvcr100d\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR100_CLR0400_DLL = OutdatedDynamicCrt("msvcr100_clr0400.dll", R"(msvcr100_clr0400\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR110_DLL = OutdatedDynamicCrt("msvcr110.dll", R"(msvcr110\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR120_DLL = OutdatedDynamicCrt("msvcr120.dll", R"(msvcr120\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCR120_CLR0400_DLL = OutdatedDynamicCrt("msvcr120_clr0400.dll", R"(msvcr120_clr0400\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCRT_DLL = OutdatedDynamicCrt("msvcrt.dll", R"(msvcrt\.dll)");
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCRT20_DLL = OutdatedDynamicCrt("msvcrt20.dll", R"(msvcrt20\.dll)");;
- const OutdatedDynamicCrt OutdatedDynamicCrt::MSVCRT40_DLL = OutdatedDynamicCrt("msvcrt40.dll", R"(msvcrt40\.dll)");;
-
- std::regex OutdatedDynamicCrt::crt_regex() const
- {
- const std::regex r(this->m_crt_regex_as_string, std::regex_constants::icase);
- return r;
- }
-
- const std::string& OutdatedDynamicCrt::toString() const
- {
- return this->m_dll_name;
- }
-}}
diff --git a/toolsrc/src/MachineType.cpp b/toolsrc/src/MachineType.cpp
new file mode 100644
index 000000000..81012234d
--- /dev/null
+++ b/toolsrc/src/MachineType.cpp
@@ -0,0 +1,42 @@
+#include "pch.h"
+#include "MachineType.h"
+#include "vcpkg_Checks.h"
+
+namespace vcpkg
+{
+ MachineType getMachineType(const uint16_t value)
+ {
+ MachineType t = static_cast<MachineType>(value);
+ switch (t)
+ {
+ case MachineType::UNKNOWN:
+ case MachineType::AM33:
+ case MachineType::AMD64:
+ case MachineType::ARM:
+ case MachineType::ARM64:
+ case MachineType::ARMNT:
+ case MachineType::EBC:
+ case MachineType::I386:
+ case MachineType::IA64:
+ case MachineType::M32R:
+ case MachineType::MIPS16:
+ case MachineType::MIPSFPU:
+ case MachineType::MIPSFPU16:
+ case MachineType::POWERPC:
+ case MachineType::POWERPCFP:
+ case MachineType::R4000:
+ case MachineType::RISCV32:
+ case MachineType::RISCV64:
+ case MachineType::RISCV128:
+ case MachineType::SH3:
+ case MachineType::SH3DSP:
+ case MachineType::SH4:
+ case MachineType::SH5:
+ case MachineType::THUMB:
+ case MachineType::WCEMIPSV2:
+ return t;
+ default:
+ Checks::exit_with_message("Unknown machine type code 0x%x", value);
+ }
+ }
+}
diff --git a/toolsrc/src/Paragraphs.cpp b/toolsrc/src/Paragraphs.cpp
index 823b4a85e..cb90ed1ec 100644
--- a/toolsrc/src/Paragraphs.cpp
+++ b/toolsrc/src/Paragraphs.cpp
@@ -1,13 +1,12 @@
+#include "pch.h"
#include "Paragraphs.h"
#include "vcpkg_Files.h"
-namespace vcpkg { namespace Paragraphs
+namespace vcpkg::Paragraphs
{
struct Parser
{
- Parser(const char* c, const char* e) : cur(c), end(e)
- {
- }
+ Parser(const char* c, const char* e) : cur(c), end(e) { }
private:
const char* cur;
@@ -41,8 +40,8 @@ namespace vcpkg { namespace Paragraphs
static bool is_alphanum(char ch)
{
return (ch >= 'A' && ch <= 'Z')
- || (ch >= 'a' && ch <= 'z')
- || (ch >= '0' && ch <= '9');
+ || (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9');
}
static bool is_lineend(char ch)
@@ -100,7 +99,7 @@ namespace vcpkg { namespace Paragraphs
auto begin_fieldname = cur;
while (is_alphanum(ch) || ch == '-')
next(ch);
- Checks::check_throw(ch == ':', "Expected ':'");
+ Checks::check_exit(ch == ':', "Expected ':'");
fieldname = std::string(begin_fieldname, cur);
// skip ': '
@@ -118,7 +117,7 @@ namespace vcpkg { namespace Paragraphs
get_fieldname(ch, fieldname);
auto it = fields.find(fieldname);
- Checks::check_throw(it == fields.end(), "Duplicate field");
+ Checks::check_exit(it == fields.end(), "Duplicate field");
get_fieldvalue(ch, fieldvalue);
@@ -153,11 +152,76 @@ namespace vcpkg { namespace Paragraphs
std::vector<std::unordered_map<std::string, std::string>> get_paragraphs(const fs::path& control_path)
{
- return parse_paragraphs(Files::read_contents(control_path).get_or_throw());
+ const expected<std::string> contents = Files::read_contents(control_path);
+ if (auto spgh = contents.get())
+ {
+ return parse_paragraphs(*spgh);
+ }
+
+ Checks::exit_with_message("Error while reading %s: %s", control_path.generic_string(), contents.error_code().message());
}
std::vector<std::unordered_map<std::string, std::string>> parse_paragraphs(const std::string& str)
{
return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs();
}
-}}
+
+ expected<SourceParagraph> try_load_port(const fs::path& path)
+ {
+ try
+ {
+ auto pghs = get_paragraphs(path / "CONTROL");
+ Checks::check_exit(pghs.size() == 1, "Invalid control file at %s\\CONTROL", path.string());
+ return SourceParagraph(pghs[0]);
+ }
+ catch (std::runtime_error const&) {}
+
+ return std::errc::no_such_file_or_directory;
+ }
+
+ expected<BinaryParagraph> try_load_cached_package(const vcpkg_paths& paths, const package_spec& spec)
+ {
+ const fs::path path = paths.package_dir(spec) / "CONTROL";
+
+ auto control_contents_maybe = Files::read_contents(path);
+ if (auto control_contents = control_contents_maybe.get())
+ {
+ std::vector<std::unordered_map<std::string, std::string>> pghs;
+ try
+ {
+ pghs = parse_paragraphs(*control_contents);
+ }
+ catch (std::runtime_error) {}
+ Checks::check_exit(pghs.size() == 1, "Invalid control file at %s", path.string());
+ return BinaryParagraph(pghs[0]);
+ }
+ return control_contents_maybe.error_code();
+ }
+
+ std::vector<SourceParagraph> load_all_ports(const fs::path& ports_dir)
+ {
+ std::vector<SourceParagraph> output;
+ for (auto it = fs::directory_iterator(ports_dir); it != fs::directory_iterator(); ++it)
+ {
+ const fs::path& path = it->path();
+ expected<SourceParagraph> source_paragraph = try_load_port(path);
+ if (auto srcpgh = source_paragraph.get())
+ {
+ output.emplace_back(std::move(*srcpgh));
+ }
+ }
+
+ return output;
+ }
+
+ std::map<std::string, std::string> extract_port_names_and_versions(const std::vector<SourceParagraph>& source_paragraphs)
+ {
+ std::map<std::string, std::string> names_and_versions;
+ for (const SourceParagraph& port : source_paragraphs)
+ {
+ names_and_versions.emplace(port.name, port.version);
+ }
+
+ return names_and_versions;
+ }
+}
diff --git a/toolsrc/src/post_build_lint.cpp b/toolsrc/src/PostBuildLint.cpp
index 4f0adf677..8abf71bb3 100644
--- a/toolsrc/src/post_build_lint.cpp
+++ b/toolsrc/src/PostBuildLint.cpp
@@ -1,13 +1,14 @@
+#include "pch.h"
#include "vcpkg_paths.h"
#include "package_spec.h"
#include "vcpkg_Files.h"
-#include <functional>
#include "vcpkg_System.h"
+#include "vcpkg_Environment.h"
#include "coff_file_reader.h"
-#include "BuildInfo.h"
-#include <regex>
+#include "PostBuildLint_BuildInfo.h"
+#include "PostBuildLint_BuildType.h"
-namespace vcpkg { namespace PostBuildLint
+namespace vcpkg::PostBuildLint
{
enum class lint_status
{
@@ -15,7 +16,41 @@ namespace vcpkg { namespace PostBuildLint
ERROR_DETECTED = 1
};
- static const fs::path DUMPBIN_EXE = R"(%VS140COMNTOOLS%\..\..\VC\bin\dumpbin.exe)";
+ struct OutdatedDynamicCrt
+ {
+ std::string name;
+ std::regex regex;
+
+ OutdatedDynamicCrt(const std::string& name, const std::string& regex_as_string)
+ : name(name),
+ regex(std::regex(regex_as_string, std::regex_constants::icase)) {}
+ };
+
+ const std::vector<OutdatedDynamicCrt>& get_outdated_dynamic_crts()
+ {
+ static const std::vector<OutdatedDynamicCrt> v = {
+ { "msvcp100.dll", R"(msvcp100\.dll)" },
+ { "msvcp100d.dll", R"(msvcp100d\.dll)" },
+ { "msvcp110.dll", R"(msvcp110\.dll)" },
+ { "msvcp110_win.dll", R"(msvcp110_win\.dll)" },
+ { "msvcp120.dll", R"(msvcp120\.dll)" },
+ { "msvcp120_clr0400.dll", R"(msvcp120_clr0400\.dll)" },
+ { "msvcp60.dll", R"(msvcp60\.dll)" },
+ { "msvcp60.dll", R"(msvcp60\.dll)" },
+
+ { "msvcr100.dll", R"(msvcr100\.dll)" },
+ { "msvcr100d.dll", R"(msvcr100d\.dll)" },
+ { "msvcr100_clr0400.dll", R"(msvcr100_clr0400\.dll)" },
+ { "msvcr110.dll", R"(msvcr110\.dll)" },
+ { "msvcr120.dll", R"(msvcr120\.dll)" },
+ { "msvcr120_clr0400.dll", R"(msvcr120_clr0400\.dll)" },
+ { "msvcrt.dll", R"(msvcrt\.dll)" },
+ { "msvcrt20.dll", R"(msvcrt20\.dll)" },
+ { "msvcrt40.dll", R"(msvcrt40\.dll)" }
+ };
+
+ return v;
+ }
static lint_status check_for_files_in_include_directory(const fs::path& package_dir)
{
@@ -185,12 +220,12 @@ namespace vcpkg { namespace PostBuildLint
return lint_status::SUCCESS;
}
- static lint_status check_exports_of_dlls(const std::vector<fs::path>& dlls)
+ static lint_status check_exports_of_dlls(const std::vector<fs::path>& dlls, const fs::path& dumpbin_exe)
{
std::vector<fs::path> dlls_with_no_exports;
for (const fs::path& dll : dlls)
{
- const std::wstring cmd_line = Strings::wformat(LR"("%s" /exports "%s")", DUMPBIN_EXE.native(), dll.native());
+ const std::wstring cmd_line = Strings::wformat(LR"("%s" /exports "%s")", dumpbin_exe.native(), dll.native());
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
@@ -211,7 +246,7 @@ namespace vcpkg { namespace PostBuildLint
return lint_status::SUCCESS;
}
- static lint_status check_uwp_bit_of_dlls(const std::string& expected_system_name, const std::vector<fs::path>& dlls)
+ static lint_status check_uwp_bit_of_dlls(const std::string& expected_system_name, const std::vector<fs::path>& dlls, const fs::path dumpbin_exe)
{
if (expected_system_name != "uwp")
{
@@ -221,7 +256,7 @@ namespace vcpkg { namespace PostBuildLint
std::vector<fs::path> dlls_with_improper_uwp_bit;
for (const fs::path& dll : dlls)
{
- const std::wstring cmd_line = Strings::wformat(LR"("%s" /headers "%s")", DUMPBIN_EXE.native(), dll.native());
+ const std::wstring cmd_line = Strings::wformat(LR"("%s" /headers "%s")", dumpbin_exe.native(), dll.native());
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
@@ -289,7 +324,7 @@ namespace vcpkg { namespace PostBuildLint
if (expected_architecture != actual_architecture)
{
- binaries_with_invalid_architecture.push_back({file, actual_architecture});
+ binaries_with_invalid_architecture.push_back({ file, actual_architecture });
}
}
@@ -315,7 +350,7 @@ namespace vcpkg { namespace PostBuildLint
const std::string actual_architecture = get_actual_architecture(info.machine_types.at(0));
if (expected_architecture != actual_architecture)
{
- binaries_with_invalid_architecture.push_back({file, actual_architecture});
+ binaries_with_invalid_architecture.push_back({ file, actual_architecture });
}
}
@@ -370,29 +405,20 @@ namespace vcpkg { namespace PostBuildLint
return lint_status::ERROR_DETECTED;
}
- static lint_status check_lib_files_are_available_if_dlls_are_available(const size_t lib_count, const size_t dll_count, const fs::path& lib_dir)
+ static lint_status check_lib_files_are_available_if_dlls_are_available(const std::map<BuildPolicies::type, opt_bool_t>& policies, const size_t lib_count, const size_t dll_count, const fs::path& lib_dir)
{
- if (lib_count == 0 && dll_count != 0)
+ auto it = policies.find(BuildPolicies::DLLS_WITHOUT_LIBS);
+ if (it != policies.cend() && it->second == opt_bool_t::DISABLED)
{
- System::println(System::color::warning, "Import libs were not present in %s", lib_dir.generic_string());
- return lint_status::ERROR_DETECTED;
+ return lint_status::SUCCESS;
}
- return lint_status::SUCCESS;
- }
-
- static lint_status check_no_subdirectories(const fs::path& dir)
- {
- const std::vector<fs::path> subdirectories = Files::recursive_find_matching_paths_in_dir(dir, [&](const fs::path& current)
- {
- return fs::is_directory(current);
- });
-
- if (!subdirectories.empty())
+ if (lib_count == 0 && dll_count != 0)
{
- System::println(System::color::warning, "Directory %s should have no subdirectories", dir.generic_string());
- System::println("The following subdirectories were found: ");
- Files::print_paths(subdirectories);
+ System::println(System::color::warning, "Import libs were not present in %s", lib_dir.generic_string());
+ System::println(System::color::warning,
+ "If this is intended, add the following line in the portfile:\n"
+ " SET(%s disabled)", BuildPolicies::DLLS_WITHOUT_LIBS.cmake_variable());
return lint_status::ERROR_DETECTED;
}
@@ -443,7 +469,7 @@ namespace vcpkg { namespace PostBuildLint
System::println("The following empty directories were found: ");
Files::print_paths(empty_directories);
System::println(System::color::warning, "If a directory should be populated but is not, this might indicate an error in the portfile.\n"
- "If the directories are not needed and their creation cannot be disabled, use something like this in the portfile to remove them)\n"
+ "If the directories are not needed and their creation cannot be disabled, use something like this in the portfile to remove them:\n"
"\n"
R"###( file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/a/dir ${CURRENT_PACKAGES_DIR}/some/other/dir))###""\n"
"\n");
@@ -456,27 +482,27 @@ namespace vcpkg { namespace PostBuildLint
struct BuildType_and_file
{
fs::path file;
- BuildType build_type;
+ BuildType::type build_type;
};
- static lint_status check_crt_linkage_of_libs(const BuildType& expected_build_type, const std::vector<fs::path>& libs)
+ static lint_status check_crt_linkage_of_libs(const BuildType::type& expected_build_type, const std::vector<fs::path>& libs, const fs::path dumpbin_exe)
{
- std::vector<BuildType> bad_build_types = BuildType::values();
+ std::vector<BuildType::type> bad_build_types(BuildType::values.cbegin(), BuildType::values.cend());
bad_build_types.erase(std::remove(bad_build_types.begin(), bad_build_types.end(), expected_build_type), bad_build_types.end());
std::vector<BuildType_and_file> libs_with_invalid_crt;
for (const fs::path& lib : libs)
{
- const std::wstring cmd_line = Strings::wformat(LR"("%s" /directives "%s")", DUMPBIN_EXE.native(), lib.native());
+ const std::wstring cmd_line = Strings::wformat(LR"("%s" /directives "%s")", dumpbin_exe.native(), lib.native());
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
- for (const BuildType& bad_build_type : bad_build_types)
+ for (const BuildType::type& bad_build_type : bad_build_types)
{
if (std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), bad_build_type.crt_regex()))
{
- libs_with_invalid_crt.push_back({lib, bad_build_type});
+ libs_with_invalid_crt.push_back({ lib, bad_build_type });
break;
}
}
@@ -503,25 +529,27 @@ namespace vcpkg { namespace PostBuildLint
{
fs::path file;
OutdatedDynamicCrt outdated_crt;
+
+ OutdatedDynamicCrt_and_file() = delete;
};
- static lint_status check_outdated_crt_linkage_of_dlls(const std::vector<fs::path>& dlls)
+ static lint_status check_outdated_crt_linkage_of_dlls(const std::vector<fs::path>& dlls, const fs::path dumpbin_exe)
{
- const std::vector<OutdatedDynamicCrt>& outdated_crts = OutdatedDynamicCrt::values();
+ const std::vector<OutdatedDynamicCrt>& outdated_crts = get_outdated_dynamic_crts();
std::vector<OutdatedDynamicCrt_and_file> dlls_with_outdated_crt;
for (const fs::path& dll : dlls)
{
- const std::wstring cmd_line = Strings::wformat(LR"("%s" /dependents "%s")", DUMPBIN_EXE.native(), dll.native());
+ const std::wstring cmd_line = Strings::wformat(LR"("%s" /dependents "%s")", dumpbin_exe.native(), dll.native());
System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd_line);
Checks::check_exit(ec_data.exit_code == 0, "Running command:\n %s\n failed", Strings::utf16_to_utf8(cmd_line));
for (const OutdatedDynamicCrt& outdated_crt : outdated_crts)
{
- if (std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), outdated_crt.crt_regex()))
+ if (std::regex_search(ec_data.output.cbegin(), ec_data.output.cend(), outdated_crt.regex))
{
- dlls_with_outdated_crt.push_back({dll, outdated_crt});
+ dlls_with_outdated_crt.push_back({ dll, outdated_crt });
break;
}
}
@@ -533,7 +561,7 @@ namespace vcpkg { namespace PostBuildLint
System::println("");
for (const OutdatedDynamicCrt_and_file btf : dlls_with_outdated_crt)
{
- System::println(" %s: %s", btf.file.generic_string(), btf.outdated_crt.toString());
+ System::println(" %s: %s", btf.file.generic_string(), btf.outdated_crt.name);
}
System::println("");
@@ -573,14 +601,32 @@ namespace vcpkg { namespace PostBuildLint
left += static_cast<size_t>(right);
}
- void perform_all_checks(const package_spec& spec, const vcpkg_paths& paths)
+ template <class T>
+ static bool contains_and_enabled(const std::map<T, opt_bool_t> map, const T& key)
{
- System::println("-- Performing post-build validation");
+ auto it = map.find(key);
+ if (it != map.cend() && it->second == opt_bool_t::ENABLED)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ static size_t perform_all_checks_and_return_error_count(const package_spec& spec, const vcpkg_paths& paths)
+ {
+ const fs::path dumpbin_exe = Environment::get_dumpbin_exe(paths);
BuildInfo build_info = read_build_info(paths.build_info_file_path(spec));
const fs::path package_dir = paths.package_dir(spec);
size_t error_count = 0;
+
+ if (contains_and_enabled(build_info.policies, BuildPolicies::EMPTY_PACKAGE))
+ {
+ return error_count;
+ }
+
error_count += check_for_files_in_include_directory(package_dir);
error_count += check_for_files_in_debug_include_directory(package_dir);
error_count += check_for_files_in_debug_share_directory(package_dir);
@@ -607,30 +653,30 @@ namespace vcpkg { namespace PostBuildLint
error_count += check_lib_architecture(spec.target_triplet().architecture(), libs);
- switch (linkage_type_value_of(build_info.library_linkage))
+ switch (build_info.library_linkage)
{
- case LinkageType::DYNAMIC:
+ case LinkageType::backing_enum_t::DYNAMIC:
{
const std::vector<fs::path> debug_dlls = Files::recursive_find_files_with_extension_in_dir(debug_bin_dir, ".dll");
const std::vector<fs::path> release_dlls = Files::recursive_find_files_with_extension_in_dir(release_bin_dir, ".dll");
error_count += check_matching_debug_and_release_binaries(debug_dlls, release_dlls);
- error_count += check_lib_files_are_available_if_dlls_are_available(debug_libs.size(), debug_dlls.size(), debug_lib_dir);
- error_count += check_lib_files_are_available_if_dlls_are_available(release_libs.size(), release_dlls.size(), release_lib_dir);
+ error_count += check_lib_files_are_available_if_dlls_are_available(build_info.policies, debug_libs.size(), debug_dlls.size(), debug_lib_dir);
+ error_count += check_lib_files_are_available_if_dlls_are_available(build_info.policies, release_libs.size(), release_dlls.size(), release_lib_dir);
std::vector<fs::path> dlls;
dlls.insert(dlls.cend(), debug_dlls.cbegin(), debug_dlls.cend());
dlls.insert(dlls.cend(), release_dlls.cbegin(), release_dlls.cend());
- error_count += check_exports_of_dlls(dlls);
- error_count += check_uwp_bit_of_dlls(spec.target_triplet().system(), dlls);
+ error_count += check_exports_of_dlls(dlls, dumpbin_exe);
+ error_count += check_uwp_bit_of_dlls(spec.target_triplet().system(), dlls, dumpbin_exe);
error_count += check_dll_architecture(spec.target_triplet().architecture(), dlls);
- error_count += check_outdated_crt_linkage_of_dlls(dlls);
+ error_count += check_outdated_crt_linkage_of_dlls(dlls, dumpbin_exe);
break;
}
- case LinkageType::STATIC:
+ case LinkageType::backing_enum_t::STATIC:
{
std::vector<fs::path> dlls;
Files::recursive_find_files_with_extension_in_dir(package_dir, ".dll", &dlls);
@@ -638,34 +684,36 @@ namespace vcpkg { namespace PostBuildLint
error_count += check_bin_folders_are_not_present_in_static_build(package_dir);
- error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::DEBUG, linkage_type_value_of(build_info.crt_linkage)), debug_libs);
- error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::RELEASE, linkage_type_value_of(build_info.crt_linkage)), release_libs);
- break;
- }
- case LinkageType::UNKNOWN:
- {
- error_count += 1;
- System::println(System::color::warning, "Unknown library_linkage architecture: [ %s ]", build_info.library_linkage);
+ if (!contains_and_enabled(build_info.policies, BuildPolicies::ONLY_RELEASE_CRT))
+ {
+ error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::DEBUG, build_info.crt_linkage), debug_libs, dumpbin_exe);
+ }
+ error_count += check_crt_linkage_of_libs(BuildType::value_of(ConfigurationType::RELEASE, build_info.crt_linkage), release_libs, dumpbin_exe);
break;
}
+ case LinkageType::backing_enum_t::NULLVALUE:
default:
Checks::unreachable();
}
-#if 0
- error_count += check_no_subdirectories(package_dir / "lib");
- error_count += check_no_subdirectories(package_dir / "debug" / "lib");
-#endif
error_count += check_no_empty_folders(package_dir);
error_count += check_no_files_in_package_dir_and_debug_dir(package_dir);
+ return error_count;
+ }
+
+ size_t perform_all_checks(const package_spec& spec, const vcpkg_paths& paths)
+ {
+ System::println("-- Performing post-build validation");
+ const size_t error_count = perform_all_checks_and_return_error_count(spec, paths);
+ System::println("-- Performing post-build validation done");
+
if (error_count != 0)
{
const fs::path portfile = paths.ports / spec.name() / "portfile.cmake";
System::println(System::color::error, "Found %u error(s). Please correct the portfile:\n %s", error_count, portfile.string());
- exit(EXIT_FAILURE);
}
- System::println("-- Performing post-build validation done");
+ return error_count;
}
-}}
+}
diff --git a/toolsrc/src/PostBuildLint_BuildInfo.cpp b/toolsrc/src/PostBuildLint_BuildInfo.cpp
new file mode 100644
index 000000000..0d1d480b8
--- /dev/null
+++ b/toolsrc/src/PostBuildLint_BuildInfo.cpp
@@ -0,0 +1,48 @@
+#include "pch.h"
+#include "PostBuildLint_BuildInfo.h"
+#include "vcpkg_Checks.h"
+#include "opt_bool.h"
+#include "vcpkglib_helpers.h"
+#include "Paragraphs.h"
+
+namespace vcpkg::PostBuildLint
+{
+ //
+ namespace BuildInfoRequiredField
+ {
+ static const std::string CRT_LINKAGE = "CRTLinkage";
+ static const std::string LIBRARY_LINKAGE = "LibraryLinkage";
+ }
+
+ BuildInfo BuildInfo::create(std::unordered_map<std::string, std::string> pgh)
+ {
+ BuildInfo build_info;
+ const std::string crt_linkage_as_string = details::remove_required_field(&pgh, BuildInfoRequiredField::CRT_LINKAGE);
+ build_info.crt_linkage = LinkageType::value_of(crt_linkage_as_string);
+ Checks::check_exit(build_info.crt_linkage != LinkageType::NULLVALUE, "Invalid crt linkage type: [%s]", crt_linkage_as_string);
+
+ const std::string library_linkage_as_string = details::remove_required_field(&pgh, BuildInfoRequiredField::LIBRARY_LINKAGE);
+ build_info.library_linkage = LinkageType::value_of(library_linkage_as_string);
+ Checks::check_exit(build_info.library_linkage != LinkageType::NULLVALUE, "Invalid library linkage type: [%s]", library_linkage_as_string);
+
+ // The remaining entries are policies
+ for (const std::unordered_map<std::string, std::string>::value_type& p : pgh)
+ {
+ const BuildPolicies::type policy = BuildPolicies::parse(p.first);
+ Checks::check_exit(policy != BuildPolicies::NULLVALUE, "Unknown policy found: %s", p.first);
+ const opt_bool_t status = opt_bool::parse(p.second);
+ build_info.policies.emplace(policy, status);
+ }
+
+ return build_info;
+ }
+
+ BuildInfo read_build_info(const fs::path& filepath)
+ {
+ const std::vector<std::unordered_map<std::string, std::string>> pghs = Paragraphs::get_paragraphs(filepath);
+ Checks::check_exit(pghs.size() == 1, "Invalid BUILD_INFO file for package");
+
+ return BuildInfo::create(pghs[0]);
+ }
+
+}
diff --git a/toolsrc/src/PostBuildLint_BuildPolicies.cpp b/toolsrc/src/PostBuildLint_BuildPolicies.cpp
new file mode 100644
index 000000000..f070a2a42
--- /dev/null
+++ b/toolsrc/src/PostBuildLint_BuildPolicies.cpp
@@ -0,0 +1,70 @@
+#include "pch.h"
+#include "PostBuildLint_BuildPolicies.h"
+#include "vcpkg_Enums.h"
+
+namespace vcpkg::PostBuildLint::BuildPolicies
+{
+ static const std::string NULLVALUE_STRING = Enums::nullvalue_toString(ENUM_NAME);
+
+ static const std::string NAME_EMPTY_PACKAGE = "PolicyEmptyPackage";
+ static const std::string NAME_DLLS_WITHOUT_LIBS = "PolicyDLLsWithoutLIBs";
+ static const std::string NAME_ONLY_RELEASE_CRT = "PolicyOnlyReleaseCRT";
+
+ const std::string& type::toString() const
+ {
+ switch (this->backing_enum)
+ {
+ case EMPTY_PACKAGE:
+ return NAME_EMPTY_PACKAGE;
+ case DLLS_WITHOUT_LIBS:
+ return NAME_DLLS_WITHOUT_LIBS;
+ case ONLY_RELEASE_CRT:
+ return NAME_ONLY_RELEASE_CRT;
+ case NULLVALUE:
+ return NULLVALUE_STRING;
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+
+ const std::string& type::cmake_variable() const
+ {
+ static const std::string CMAKE_VARIABLE_EMPTY_PACKAGE = "VCPKG_POLICY_EMPTY_PACKAGE";
+ static const std::string CMAKE_VARIABLE_DLLS_WITHOUT_LIBS = "VCPKG_POLICY_DLLS_WITHOUT_LIBS";
+ static const std::string CMAKE_VARIABLE_ONLY_RELEASE_CRT = "VCPKG_POLICY_ONLY_RELEASE_CRT";
+
+ switch (this->backing_enum)
+ {
+ case EMPTY_PACKAGE:
+ return CMAKE_VARIABLE_EMPTY_PACKAGE;
+ case DLLS_WITHOUT_LIBS:
+ return CMAKE_VARIABLE_DLLS_WITHOUT_LIBS;
+ case ONLY_RELEASE_CRT:
+ return CMAKE_VARIABLE_ONLY_RELEASE_CRT;
+ case NULLVALUE:
+ Enums::nullvalue_used(ENUM_NAME);
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+
+ type parse(const std::string& s)
+ {
+ if (s == NAME_EMPTY_PACKAGE)
+ {
+ return BuildPolicies::EMPTY_PACKAGE;
+ }
+
+ if (s == NAME_DLLS_WITHOUT_LIBS)
+ {
+ return BuildPolicies::DLLS_WITHOUT_LIBS;
+ }
+
+ if (s == NAME_ONLY_RELEASE_CRT)
+ {
+ return BuildPolicies::ONLY_RELEASE_CRT;
+ }
+
+ return BuildPolicies::NULLVALUE;
+ }
+}
diff --git a/toolsrc/src/PostBuildLint_BuildType.cpp b/toolsrc/src/PostBuildLint_BuildType.cpp
new file mode 100644
index 000000000..f2fb292d7
--- /dev/null
+++ b/toolsrc/src/PostBuildLint_BuildType.cpp
@@ -0,0 +1,85 @@
+#include "pch.h"
+#include "PostBuildLint_BuildType.h"
+#include "vcpkg_Enums.h"
+
+namespace vcpkg::PostBuildLint::BuildType
+{
+ type value_of(const ConfigurationType::type& config, const LinkageType::type& linkage)
+ {
+ if (config == ConfigurationType::DEBUG && linkage == LinkageType::STATIC)
+ {
+ return DEBUG_STATIC;
+ }
+
+ if (config == ConfigurationType::DEBUG && linkage == LinkageType::DYNAMIC)
+ {
+ return DEBUG_DYNAMIC;
+ }
+
+ if (config == ConfigurationType::RELEASE && linkage == LinkageType::STATIC)
+ {
+ return RELEASE_STATIC;
+ }
+
+ if (config == ConfigurationType::RELEASE && linkage == LinkageType::DYNAMIC)
+ {
+ return RELEASE_DYNAMIC;
+ }
+
+ Enums::unreachable(ENUM_NAME);
+ }
+
+ const ConfigurationType::type& type::config() const
+ {
+ return this->m_config;
+ }
+
+ const LinkageType::type& type::linkage() const
+ {
+ return this->m_linkage;
+ }
+
+ const std::regex& type::crt_regex() const
+ {
+ static const std::regex REGEX_DEBUG_STATIC(R"(/DEFAULTLIB:LIBCMTD)", std::regex_constants::icase);
+ static const std::regex REGEX_DEBUG_DYNAMIC(R"(/DEFAULTLIB:MSVCRTD)", std::regex_constants::icase);
+ static const std::regex REGEX_RELEASE_STATIC(R"(/DEFAULTLIB:LIBCMT[^D])", std::regex_constants::icase);
+ static const std::regex REGEX_RELEASE_DYNAMIC(R"(/DEFAULTLIB:MSVCRT[^D])", std::regex_constants::icase);
+
+ switch (backing_enum)
+ {
+ case BuildType::DEBUG_STATIC:
+ return REGEX_DEBUG_STATIC;
+ case BuildType::DEBUG_DYNAMIC:
+ return REGEX_DEBUG_DYNAMIC;
+ case BuildType::RELEASE_STATIC:
+ return REGEX_RELEASE_STATIC;
+ case BuildType::RELEASE_DYNAMIC:
+ return REGEX_RELEASE_DYNAMIC;
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+
+ const std::string& type::toString() const
+ {
+ static const std::string NAME_DEBUG_STATIC("Debug,Static");
+ static const std::string NAME_DEBUG_DYNAMIC("Debug,Dynamic");
+ static const std::string NAME_RELEASE_STATIC("Release,Static");
+ static const std::string NAME_RELEASE_DYNAMIC("Release,Dynamic");
+
+ switch (backing_enum)
+ {
+ case BuildType::DEBUG_STATIC:
+ return NAME_DEBUG_STATIC;
+ case BuildType::DEBUG_DYNAMIC:
+ return NAME_DEBUG_DYNAMIC;
+ case BuildType::RELEASE_STATIC:
+ return NAME_RELEASE_STATIC;
+ case BuildType::RELEASE_DYNAMIC:
+ return NAME_RELEASE_DYNAMIC;
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+}
diff --git a/toolsrc/src/PostBuildLint_ConfigurationType.cpp b/toolsrc/src/PostBuildLint_ConfigurationType.cpp
new file mode 100644
index 000000000..990b10a37
--- /dev/null
+++ b/toolsrc/src/PostBuildLint_ConfigurationType.cpp
@@ -0,0 +1,26 @@
+#include "pch.h"
+#include "PostBuildLint_ConfigurationType.h"
+#include "vcpkg_Enums.h"
+
+namespace vcpkg::PostBuildLint::ConfigurationType
+{
+ static const std::string NULLVALUE_STRING = Enums::nullvalue_toString(ENUM_NAME);
+
+ static const std::string NAME_DEBUG = "Debug";
+ static const std::string NAME_RELEASE = "Release";
+
+ const std::string& type::toString() const
+ {
+ switch (this->backing_enum)
+ {
+ case ConfigurationType::DEBUG:
+ return NAME_DEBUG;
+ case ConfigurationType::RELEASE:
+ return NAME_RELEASE;
+ case ConfigurationType::NULLVALUE:
+ return NULLVALUE_STRING;
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+}
diff --git a/toolsrc/src/PostBuildLint_LinkageType.cpp b/toolsrc/src/PostBuildLint_LinkageType.cpp
new file mode 100644
index 000000000..6d2c2c935
--- /dev/null
+++ b/toolsrc/src/PostBuildLint_LinkageType.cpp
@@ -0,0 +1,41 @@
+#include "pch.h"
+#include "PostBuildLint_LinkageType.h"
+#include "vcpkg_Enums.h"
+
+namespace vcpkg::PostBuildLint::LinkageType
+{
+ static const std::string NULLVALUE_STRING = Enums::nullvalue_toString(ENUM_NAME);
+
+ static const std::string NAME_DYNAMIC = "dynamic";
+ static const std::string NAME_STATIC = "static";
+
+ const std::string& type::toString() const
+ {
+ switch (this->backing_enum)
+ {
+ case LinkageType::DYNAMIC:
+ return NAME_DYNAMIC;
+ case LinkageType::STATIC:
+ return NAME_STATIC;
+ case LinkageType::NULLVALUE:
+ return NULLVALUE_STRING;
+ default:
+ Enums::unreachable(ENUM_NAME);
+ }
+ }
+
+ type value_of(const std::string& as_string)
+ {
+ if (as_string == NAME_DYNAMIC)
+ {
+ return LinkageType::DYNAMIC;
+ }
+
+ if (as_string == NAME_STATIC)
+ {
+ return LinkageType::STATIC;
+ }
+
+ return LinkageType::NULLVALUE;
+ }
+}
diff --git a/toolsrc/src/SourceParagraph.cpp b/toolsrc/src/SourceParagraph.cpp
index bdf15a737..4d144191f 100644
--- a/toolsrc/src/SourceParagraph.cpp
+++ b/toolsrc/src/SourceParagraph.cpp
@@ -1,3 +1,4 @@
+#include "pch.h"
#include "SourceParagraph.h"
#include "vcpkglib_helpers.h"
#include "vcpkg_System.h"
@@ -52,8 +53,8 @@ namespace vcpkg
const std::vector<std::string> remaining_fields = Maps::extract_keys(fields);
const std::vector<std::string>& valid_fields = get_list_of_valid_fields();
- const std::string remaining_fields_as_string = Strings::join(remaining_fields, "\n ");
- const std::string valid_fields_as_string = Strings::join(valid_fields, "\n ");
+ const std::string remaining_fields_as_string = Strings::join("\n ", remaining_fields);
+ const std::string valid_fields_as_string = Strings::join("\n ", valid_fields);
System::println(System::color::error, "Error: There are invalid fields in the Source Paragraph of %s", this->name);
System::println("The following fields were not expected:\n\n %s\n\n", remaining_fields_as_string);
diff --git a/toolsrc/src/StatusParagraph.cpp b/toolsrc/src/StatusParagraph.cpp
index bf12ae89a..3f07689ca 100644
--- a/toolsrc/src/StatusParagraph.cpp
+++ b/toolsrc/src/StatusParagraph.cpp
@@ -1,3 +1,4 @@
+#include "pch.h"
#include "StatusParagraph.h"
#include "vcpkglib_helpers.h"
diff --git a/toolsrc/src/StatusParagraphs.cpp b/toolsrc/src/StatusParagraphs.cpp
index 3e23c519a..9a440fbb8 100644
--- a/toolsrc/src/StatusParagraphs.cpp
+++ b/toolsrc/src/StatusParagraphs.cpp
@@ -1,5 +1,5 @@
+#include "pch.h"
#include "StatusParagraphs.h"
-#include <algorithm>
#include "vcpkg_Checks.h"
namespace vcpkg
@@ -29,9 +29,9 @@ namespace vcpkg
});
}
- StatusParagraphs::iterator StatusParagraphs::find_installed(const std::string& name, const triplet& target_triplet)
+ StatusParagraphs::const_iterator StatusParagraphs::find_installed(const std::string& name, const triplet& target_triplet) const
{
- auto it = find(name, target_triplet);
+ const const_iterator it = find(name, target_triplet);
if (it != end() && (*it)->want == want_t::install)
{
return it;
@@ -42,7 +42,7 @@ namespace vcpkg
StatusParagraphs::iterator StatusParagraphs::insert(std::unique_ptr<StatusParagraph> pgh)
{
- Checks::check_throw(pgh != nullptr, "Inserted null paragraph");
+ Checks::check_exit(pgh != nullptr, "Inserted null paragraph");
const package_spec& spec = pgh->package.spec;
auto ptr = find(spec.name(), spec.target_triplet());
if (ptr == end())
diff --git a/toolsrc/src/coff_file_reader.cpp b/toolsrc/src/coff_file_reader.cpp
index 1f30ea70b..f48f912c1 100644
--- a/toolsrc/src/coff_file_reader.cpp
+++ b/toolsrc/src/coff_file_reader.cpp
@@ -1,12 +1,10 @@
+#include "pch.h"
#include "coff_file_reader.h"
-#include <iostream>
#include "vcpkg_Checks.h"
-#include <set>
-#include <fstream>
using namespace std;
-namespace vcpkg { namespace COFFFileReader
+namespace vcpkg::COFFFileReader
{
template <class T>
static T reinterpret_bytes(const char* data)
@@ -306,4 +304,4 @@ namespace vcpkg { namespace COFFFileReader
return {std::vector<MachineType>(machine_types.cbegin(), machine_types.cend())};
}
-}}
+}
diff --git a/toolsrc/src/commands_available_commands.cpp b/toolsrc/src/commands_available_commands.cpp
new file mode 100644
index 000000000..4c7e0df2c
--- /dev/null
+++ b/toolsrc/src/commands_available_commands.cpp
@@ -0,0 +1,46 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+
+namespace vcpkg::Commands
+{
+ const std::vector<package_name_and_function<command_type_a>>& get_available_commands_type_a()
+ {
+ static std::vector<package_name_and_function<command_type_a>> t = {
+ {"install", &Install::perform_and_exit},
+ { "ci", &CI::perform_and_exit },
+ {"remove", &Remove::perform_and_exit},
+ {"build", &Build::perform_and_exit},
+ {"build_external", &BuildExternal::perform_and_exit}
+ };
+ return t;
+ }
+
+ const std::vector<package_name_and_function<command_type_b>>& get_available_commands_type_b()
+ {
+ static std::vector<package_name_and_function<command_type_b>> t = {
+ {"/?", &Help::perform_and_exit},
+ {"help", &Help::perform_and_exit},
+ {"search", &Search::perform_and_exit},
+ {"list", &List::perform_and_exit},
+ {"integrate", &Integrate::perform_and_exit},
+ {"owns", &Owns::perform_and_exit},
+ {"update", &Update::perform_and_exit},
+ {"edit", &Edit::perform_and_exit},
+ {"create", &Create::perform_and_exit},
+ {"import", &Import::perform_and_exit},
+ {"cache", &Cache::perform_and_exit},
+ {"portsdiff", &PortsDiff::perform_and_exit}
+ };
+ return t;
+ }
+
+ const std::vector<package_name_and_function<command_type_c>>& get_available_commands_type_c()
+ {
+ static std::vector<package_name_and_function<command_type_c>> t = {
+ {"version", &Version::perform_and_exit},
+ {"contact", &Contact::perform_and_exit},
+ {"hash", &Hash::perform_and_exit},
+ };
+ return t;
+ }
+}
diff --git a/toolsrc/src/commands_build.cpp b/toolsrc/src/commands_build.cpp
new file mode 100644
index 000000000..a47083cbd
--- /dev/null
+++ b/toolsrc/src/commands_build.cpp
@@ -0,0 +1,183 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "StatusParagraphs.h"
+#include "vcpkglib.h"
+#include "vcpkg_Input.h"
+#include "PostBuildLint.h"
+#include "vcpkg_Dependencies.h"
+#include "vcpkg_System.h"
+#include "vcpkg_Chrono.h"
+#include "vcpkg_Environment.h"
+#include "metrics.h"
+#include "vcpkg_Enums.h"
+#include "Paragraphs.h"
+
+namespace vcpkg::Commands::Build
+{
+ using Dependencies::package_spec_with_install_plan;
+ using Dependencies::install_plan_type;
+
+ static const std::string OPTION_CHECKS_ONLY = "--checks-only";
+
+ static void create_binary_control_file(const vcpkg_paths& paths, const SourceParagraph& source_paragraph, const triplet& target_triplet)
+ {
+ const BinaryParagraph bpgh = BinaryParagraph(source_paragraph, target_triplet);
+ const fs::path binary_control_file = paths.packages / bpgh.dir() / "CONTROL";
+ std::ofstream(binary_control_file) << bpgh;
+ }
+
+ BuildResult build_package(const SourceParagraph& source_paragraph, const package_spec& spec, const vcpkg_paths& paths, const fs::path& port_dir, const StatusParagraphs& status_db)
+ {
+ Checks::check_exit(spec.name() == source_paragraph.name, "inconsistent arguments to build_package()");
+
+ const triplet& target_triplet = spec.target_triplet();
+ for (auto&& dep : source_paragraph.depends)
+ {
+ if (status_db.find_installed(dep.name, target_triplet) == status_db.end())
+ {
+ return BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES;
+ }
+ }
+
+ const fs::path& cmake_exe_path = paths.get_cmake_exe();
+ const fs::path& git_exe_path = paths.get_git_exe();
+
+ const fs::path ports_cmake_script_path = paths.ports_cmake;
+ const Environment::vcvarsall_and_platform_toolset vcvarsall_bat = Environment::get_vcvarsall_bat(paths);
+ const std::wstring cmd_set_environment = Strings::wformat(LR"("%s" %s >nul 2>&1)", vcvarsall_bat.path.native(), Strings::utf8_to_utf16(target_triplet.architecture()));
+
+ const std::wstring cmd_launch_cmake = make_cmake_cmd(cmake_exe_path, ports_cmake_script_path,
+ {
+ { L"CMD", L"BUILD" },
+ { L"PORT", source_paragraph.name },
+ { L"CURRENT_PORT_DIR", port_dir / "/." },
+ { L"TARGET_TRIPLET", target_triplet.canonical_name() },
+ { L"VCPKG_PLATFORM_TOOLSET", vcvarsall_bat.platform_toolset },
+ { L"GIT", git_exe_path }
+ });
+
+ const std::wstring command = Strings::wformat(LR"(%s && %s)", cmd_set_environment, cmd_launch_cmake);
+
+ const ElapsedTime timer = ElapsedTime::createStarted();
+
+ int return_code = System::cmd_execute_clean(command);
+ auto buildtimeus = timer.microseconds();
+ TrackMetric("buildtimeus-" + spec.toString(), buildtimeus);
+
+ if (return_code != 0)
+ {
+ TrackProperty("error", "build failed");
+ TrackProperty("build_error", spec.toString());
+ return BuildResult::BUILD_FAILED;
+ }
+
+ const size_t error_count = PostBuildLint::perform_all_checks(spec, paths);
+
+ if (error_count != 0)
+ {
+ return BuildResult::POST_BUILD_CHECKS_FAILED;
+ }
+
+ create_binary_control_file(paths, source_paragraph, target_triplet);
+
+ // const fs::path port_buildtrees_dir = paths.buildtrees / spec.name;
+ // delete_directory(port_buildtrees_dir);
+
+ return BuildResult::SUCCEEDED;
+ }
+
+ const std::string& to_string(const BuildResult build_result)
+ {
+ static const std::string NULLVALUE_STRING = Enums::nullvalue_toString("vcpkg::Commands::Build::BuildResult");
+ static const std::string SUCCEEDED_STRING = "SUCCEEDED";
+ static const std::string BUILD_FAILED_STRING = "BUILD_FAILED";
+ static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED";
+ static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES";
+
+ switch (build_result)
+ {
+ case BuildResult::NULLVALUE: return NULLVALUE_STRING;
+ case BuildResult::SUCCEEDED: return SUCCEEDED_STRING;
+ case BuildResult::BUILD_FAILED: return BUILD_FAILED_STRING;
+ case BuildResult::POST_BUILD_CHECKS_FAILED: return POST_BUILD_CHECKS_FAILED_STRING;
+ case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING;
+ default: Checks::unreachable();
+ }
+ }
+
+ std::string create_error_message(const BuildResult build_result, const package_spec& spec)
+ {
+ return Strings::format("Error: Building package %s failed with: %s", spec.toString(), Build::to_string(build_result));
+ }
+
+ std::string create_user_troubleshooting_message(const package_spec& spec)
+ {
+ return Strings::format("Please ensure sure you're using the latest portfiles with `.\\vcpkg update`, then\n"
+ "submit an issue at https://github.com/Microsoft/vcpkg/issues including:\n"
+ " Package: %s\n"
+ " Vcpkg version: %s\n"
+ "\n"
+ "Additionally, attach any relevant sections from the log files above."
+ , spec.toString(), Version::version());
+ }
+
+ void perform_and_exit(const package_spec& spec, const fs::path& port_dir, const std::unordered_set<std::string>& options, const vcpkg_paths& paths)
+ {
+ if (options.find(OPTION_CHECKS_ONLY) != options.end())
+ {
+ const size_t error_count = PostBuildLint::perform_all_checks(spec, paths);
+ if (error_count > 0)
+ {
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+ const expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(port_dir);
+ Checks::check_exit(!maybe_spgh.error_code(), "Could not find package named %s: %s", spec, maybe_spgh.error_code().message());
+ const SourceParagraph& spgh = *maybe_spgh.get();
+
+ StatusParagraphs status_db = database_load_check(paths);
+ const BuildResult result = build_package(spgh, spec, paths, paths.port_dir(spec), status_db);
+ if (result == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES)
+ {
+ std::vector<package_spec_with_install_plan> unmet_dependencies = Dependencies::create_install_plan(paths, { spec }, status_db);
+ unmet_dependencies.erase(
+ std::remove_if(unmet_dependencies.begin(), unmet_dependencies.end(), [&spec](const package_spec_with_install_plan& p)
+ {
+ return (p.spec == spec) || (p.plan.plan_type == install_plan_type::ALREADY_INSTALLED);
+ }),
+ unmet_dependencies.end());
+
+ Checks::check_exit(!unmet_dependencies.empty());
+ System::println(System::color::error, "The build command requires all dependencies to be already installed.");
+ System::println("The following dependencies are missing:");
+ System::println("");
+ for (const package_spec_with_install_plan& p : unmet_dependencies)
+ {
+ System::println(" %s", p.spec.toString());
+ }
+ System::println("");
+ exit(EXIT_FAILURE);
+ }
+
+ if (result != BuildResult::SUCCEEDED)
+ {
+ System::println(System::color::error, Build::create_error_message(result, spec));
+ System::println(Build::create_user_troubleshooting_message(spec));
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ {
+ static const std::string example = Commands::Help::create_example_string("build zlib:x64-windows");
+ args.check_exact_arg_count(1, example); // Build only takes a single package and all dependencies must already be installed
+ const package_spec spec = Input::check_and_get_package_spec(args.command_arguments.at(0), default_target_triplet, example);
+ Input::check_triplet(spec.target_triplet(), paths);
+ const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({ OPTION_CHECKS_ONLY });
+ perform_and_exit(spec, paths.port_dir(spec), options, paths);
+ }
+}
diff --git a/toolsrc/src/commands_build_external.cpp b/toolsrc/src/commands_build_external.cpp
new file mode 100644
index 000000000..06bd1374c
--- /dev/null
+++ b/toolsrc/src/commands_build_external.cpp
@@ -0,0 +1,20 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "vcpkg_System.h"
+#include "vcpkg_Environment.h"
+#include "vcpkg_Input.h"
+
+namespace vcpkg::Commands::BuildExternal
+{
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ {
+ static const std::string example = Commands::Help::create_example_string(R"(build_external zlib2 C:\path\to\dir\with\controlfile\)");
+ args.check_exact_arg_count(2, example);
+ const package_spec spec = Input::check_and_get_package_spec(args.command_arguments.at(0), default_target_triplet, example);
+ Input::check_triplet(spec.target_triplet(), paths);
+ const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({});
+
+ const fs::path port_dir = args.command_arguments.at(1);
+ Build::perform_and_exit(spec, port_dir, options, paths);
+ }
+}
diff --git a/toolsrc/src/commands_cache.cpp b/toolsrc/src/commands_cache.cpp
index 1a10b93cf..e255b5dff 100644
--- a/toolsrc/src/commands_cache.cpp
+++ b/toolsrc/src/commands_cache.cpp
@@ -1,10 +1,11 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
#include "vcpkg_Files.h"
#include "Paragraphs.h"
#include "BinaryParagraph.h"
-namespace vcpkg
+namespace vcpkg::Commands::Cache
{
static std::vector<BinaryParagraph> read_all_binary_paragraphs(const vcpkg_paths& paths)
{
@@ -34,11 +35,12 @@ namespace vcpkg
return output;
}
- void cache_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
static const std::string example = Strings::format(
- "The argument should be a substring to search for, or no argument to display all cached libraries.\n%s", create_example_string("cache png"));
+ "The argument should be a substring to search for, or no argument to display all cached libraries.\n%s", Commands::Help::create_example_string("cache png"));
args.check_max_arg_count(1, example);
+ args.check_and_get_optional_command_arguments({});
const std::vector<BinaryParagraph> binary_paragraphs = read_all_binary_paragraphs(paths);
if (binary_paragraphs.empty())
diff --git a/toolsrc/src/commands_ci.cpp b/toolsrc/src/commands_ci.cpp
new file mode 100644
index 000000000..315308a62
--- /dev/null
+++ b/toolsrc/src/commands_ci.cpp
@@ -0,0 +1,120 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "vcpkglib.h"
+#include "vcpkg_Files.h"
+#include "vcpkg_System.h"
+#include "vcpkg_Dependencies.h"
+#include "vcpkg_Input.h"
+#include "vcpkg_Chrono.h"
+#include "Paragraphs.h"
+
+namespace vcpkg::Commands::CI
+{
+ using Dependencies::package_spec_with_install_plan;
+ using Dependencies::install_plan_type;
+ using Build::BuildResult;
+
+ static std::vector<package_spec> load_all_package_specs(const fs::path& ports_directory, const triplet& target_triplet)
+ {
+ std::vector<SourceParagraph> ports = Paragraphs::load_all_ports(ports_directory);
+ std::vector<package_spec> specs;
+ for (const SourceParagraph& p : ports)
+ {
+ specs.push_back(package_spec::from_name_and_triplet(p.name, target_triplet).get_or_throw());
+ }
+
+ return specs;
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ {
+ static const std::string example = Commands::Help::create_example_string("ci x64-windows");
+ args.check_max_arg_count(1, example);
+ const triplet target_triplet = args.command_arguments.size() == 1 ? triplet::from_canonical_name(args.command_arguments.at(0)) : default_target_triplet;
+ Input::check_triplet(target_triplet, paths);
+ args.check_and_get_optional_command_arguments({});
+ const std::vector<package_spec> specs = load_all_package_specs(paths.ports, target_triplet);
+
+ StatusParagraphs status_db = database_load_check(paths);
+ const std::vector<package_spec_with_install_plan> install_plan = Dependencies::create_install_plan(paths, specs, status_db);
+ Checks::check_exit(!install_plan.empty(), "Install plan cannot be empty");
+
+ std::vector<BuildResult> results;
+ std::vector<std::chrono::milliseconds::rep> timing;
+ const ElapsedTime timer = ElapsedTime::createStarted();
+ size_t counter = 0;
+ const size_t package_count = install_plan.size();
+ for (const package_spec_with_install_plan& action : install_plan)
+ {
+ const ElapsedTime build_timer = ElapsedTime::createStarted();
+ counter++;
+ System::println("Starting package %d/%d: %s", counter, package_count, action.spec.toString());
+
+ timing.push_back(-1);
+ results.push_back(BuildResult::NULLVALUE);
+
+ try
+ {
+ if (action.plan.plan_type == install_plan_type::ALREADY_INSTALLED)
+ {
+ results.back() = BuildResult::SUCCEEDED;
+ System::println(System::color::success, "Package %s is already installed", action.spec);
+ }
+ else if (action.plan.plan_type == install_plan_type::BUILD_AND_INSTALL)
+ {
+ const BuildResult result = Commands::Build::build_package(*action.plan.source_pgh, action.spec, paths, paths.port_dir(action.spec), status_db);
+ timing.back() = build_timer.elapsed<std::chrono::milliseconds>().count();
+ results.back() = result;
+ if (result != BuildResult::SUCCEEDED)
+ {
+ System::println(System::color::error, Build::create_error_message(result, action.spec));
+ continue;
+ }
+ const BinaryParagraph bpgh = Paragraphs::try_load_cached_package(paths, action.spec).get_or_throw();
+ Install::install_package(paths, bpgh, &status_db);
+ System::println(System::color::success, "Package %s is installed", action.spec);
+ }
+ else if (action.plan.plan_type == install_plan_type::INSTALL)
+ {
+ results.back() = BuildResult::SUCCEEDED;
+ Install::install_package(paths, *action.plan.binary_pgh, &status_db);
+ System::println(System::color::success, "Package %s is installed from cache", action.spec);
+ }
+ else
+ Checks::unreachable();
+ }
+ catch (const std::exception& e)
+ {
+ System::println(System::color::error, "Error: Could not install package %s: %s", action.spec, e.what());
+ results.back() = BuildResult::NULLVALUE;
+ }
+ System::println("Elapsed time for package %s: %s", action.spec, build_timer.toString());
+ }
+
+ System::println("Total time taken: %s", timer.toString());
+
+ for (size_t i = 0; i < results.size(); i++)
+ {
+ System::println("%s: %s: %dms", install_plan[i].spec.toString(), Build::to_string(results[i]), timing[i]);
+ }
+
+ std::map<BuildResult, int> summary;
+ for (const BuildResult& v : Build::BuildResult_values)
+ {
+ summary[v] = 0;
+ }
+
+ for (const BuildResult& r : results)
+ {
+ summary[r]++;
+ }
+
+ System::println("\n\nSUMMARY");
+ for (const std::pair<const BuildResult, int>& entry : summary)
+ {
+ System::println(" %s: %d", Build::to_string(entry.first), entry.second);
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+}
diff --git a/toolsrc/src/commands_contact.cpp b/toolsrc/src/commands_contact.cpp
new file mode 100644
index 000000000..29f0d4d27
--- /dev/null
+++ b/toolsrc/src/commands_contact.cpp
@@ -0,0 +1,21 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "vcpkg_System.h"
+
+namespace vcpkg::Commands::Contact
+{
+ const std::string& email()
+ {
+ static const std::string s_email = R"(vcpkg@microsoft.com)";
+ return s_email;
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args)
+ {
+ args.check_exact_arg_count(0);
+ args.check_and_get_optional_command_arguments({});
+
+ System::println("Send an email to %s with any feedback.", email());
+ exit(EXIT_SUCCESS);
+ }
+}
diff --git a/toolsrc/src/commands_create.cpp b/toolsrc/src/commands_create.cpp
index ad00cd676..b74693ed5 100644
--- a/toolsrc/src/commands_create.cpp
+++ b/toolsrc/src/commands_create.cpp
@@ -1,37 +1,41 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
#include "vcpkg_Environment.h"
#include "vcpkg_Files.h"
#include "vcpkg_Input.h"
+#include "vcpkglib.h"
-namespace vcpkg
+namespace vcpkg::Commands::Create
{
- void create_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = create_example_string(R"###(create zlib2 http://zlib.net/zlib128.zip "zlib128-2.zip")###");
+ static const std::string example = Commands::Help::create_example_string(R"###(create zlib2 http://zlib.net/zlib1211.zip "zlib1211-2.zip")###");
args.check_max_arg_count(3, example);
args.check_min_arg_count(2, example);
-
+ args.check_and_get_optional_command_arguments({});
const std::string port_name = args.command_arguments.at(0);
- Environment::ensure_utilities_on_path(paths);
+ const std::string url = args.command_arguments.at(1);
+
+ const fs::path& cmake_exe = paths.get_cmake_exe();
+
+ std::vector<CMakeVariable> cmake_args
+ {
+ { L"CMD", L"CREATE" },
+ { L"PORT", port_name },
+ { L"URL", url }
+ };
- // Space OR define the FILENAME with proper spacing
- std::wstring custom_filename = L" ";
if (args.command_arguments.size() >= 3)
{
const std::string& zip_file_name = args.command_arguments.at(2);
Checks::check_exit(!Files::has_invalid_chars_for_filesystem(zip_file_name),
R"(Filename cannot contain invalid chars %s, but was %s)",
Files::FILESYSTEM_INVALID_CHARACTERS, zip_file_name);
- custom_filename = Strings::wformat(LR"( -DFILENAME="%s" )", Strings::utf8_to_utf16(zip_file_name));
+ cmake_args.push_back({ L"FILENAME", zip_file_name });
}
- const std::wstring cmdline = Strings::wformat(LR"(cmake -DCMD=CREATE -DPORT=%s -DURL=%s%s-P "%s")",
- Strings::utf8_to_utf16(port_name),
- Strings::utf8_to_utf16(args.command_arguments.at(1)),
- custom_filename,
- paths.ports_cmake.generic_wstring());
-
- exit(System::cmd_execute(cmdline));
+ const std::wstring cmd_launch_cmake = make_cmake_cmd(cmake_exe, paths.ports_cmake, cmake_args);
+ exit(System::cmd_execute_clean(cmd_launch_cmake));
}
}
diff --git a/toolsrc/src/commands_edit.cpp b/toolsrc/src/commands_edit.cpp
index fbf4eab62..ce0557e09 100644
--- a/toolsrc/src/commands_edit.cpp
+++ b/toolsrc/src/commands_edit.cpp
@@ -1,33 +1,71 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
#include "vcpkg_Input.h"
+#include "vcpkg_Environment.h"
-namespace vcpkg
+namespace vcpkg::Commands::Edit
{
- void edit_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = create_example_string("edit zlib");
+ static const std::string example = Commands::Help::create_example_string("edit zlib");
args.check_exact_arg_count(1, example);
+ args.check_and_get_optional_command_arguments({});
const std::string port_name = args.command_arguments.at(0);
const fs::path portpath = paths.ports / port_name;
+ Checks::check_exit(fs::is_directory(portpath), R"(Could not find port named "%s")", port_name);
+
+ // Find the user's selected editor
+ std::wstring env_EDITOR;
+
+ if (env_EDITOR.empty())
+ {
+ const optional<std::wstring> env_EDITOR_optional = System::get_environmental_variable(L"EDITOR");
+ if (env_EDITOR_optional)
+ {
+ env_EDITOR = *env_EDITOR_optional;
+ }
+ }
- // Find editor
- std::wstring env_EDITOR = System::wdupenv_str(L"EDITOR");
if (env_EDITOR.empty())
{
- static const std::wstring CODE_EXE_PATH = LR"(C:\Program Files (x86)\Microsoft VS Code\Code.exe)";
+ const fs::path CODE_EXE_PATH = Environment::get_ProgramFiles_32_bit() / "Microsoft VS Code/Code.exe";
if (fs::exists(CODE_EXE_PATH))
{
env_EDITOR = CODE_EXE_PATH;
}
- else
+ }
+
+ if (env_EDITOR.empty())
+ {
+ static const std::array<const wchar_t*, 4> regkeys = {
+ LR"(SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{C26E74D1-022E-4238-8B9D-1E7564A36CC9}_is1)",
+ LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C26E74D1-022E-4238-8B9D-1E7564A36CC9}_is1)",
+ LR"(SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{F8A2A208-72B3-4D61-95FC-8A65D340689B}_is1)",
+ LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F8A2A208-72B3-4D61-95FC-8A65D340689B}_is1)",
+ };
+ for (auto&& keypath : regkeys)
{
- Checks::exit_with_message("Visual Studio Code was not found and the environmental variable EDITOR is not set");
+ auto code_installpath = System::get_registry_string(HKEY_LOCAL_MACHINE, keypath, L"InstallLocation");
+ if (code_installpath)
+ {
+ auto p = fs::path(*code_installpath) / "Code.exe";
+ if (fs::exists(p))
+ {
+ env_EDITOR = p.native();
+ break;
+ }
+ }
}
}
- std::wstring cmdLine = Strings::wformat(LR"("%s" "%s" "%s")", env_EDITOR, portpath.native(), (portpath / "portfile.cmake").native());
+ if (env_EDITOR.empty())
+ {
+ Checks::exit_with_message("Visual Studio Code was not found and the environment variable EDITOR is not set");
+ }
+
+ std::wstring cmdLine = Strings::wformat(LR"("%s" "%s" "%s" -n)", env_EDITOR, portpath.native(), (portpath / "portfile.cmake").native());
exit(System::cmd_execute(cmdLine));
}
}
diff --git a/toolsrc/src/commands_hash.cpp b/toolsrc/src/commands_hash.cpp
index 0e3e8a77c..805da4153 100644
--- a/toolsrc/src/commands_hash.cpp
+++ b/toolsrc/src/commands_hash.cpp
@@ -1,7 +1,8 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
-namespace vcpkg
+namespace vcpkg::Commands::Hash
{
static void do_file_hash(fs::path const& path, std::wstring const& hashType)
{
@@ -23,12 +24,13 @@ namespace vcpkg
System::println(hash);
}
- void hash_command(const vcpkg_cmd_arguments& args)
+ void perform_and_exit(const vcpkg_cmd_arguments& args)
{
static const std::string example = Strings::format(
- "The argument should be a file path\n%s", create_example_string("hash boost_1_62_0.tar.bz2"));
+ "The argument should be a file path\n%s", Commands::Help::create_example_string("hash boost_1_62_0.tar.bz2"));
args.check_min_arg_count(1, example);
args.check_max_arg_count(2, example);
+ args.check_and_get_optional_command_arguments({});
if (args.command_arguments.size() == 1)
{
diff --git a/toolsrc/src/commands_help.cpp b/toolsrc/src/commands_help.cpp
index fd02d948e..49b5697c3 100644
--- a/toolsrc/src/commands_help.cpp
+++ b/toolsrc/src/commands_help.cpp
@@ -1,22 +1,74 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
-#include "vcpkg_info.h"
-namespace vcpkg
+namespace vcpkg::Commands::Help
{
- void version_command(const vcpkg_cmd_arguments& args)
+ void help_topic_valid_triplet(const vcpkg_paths& paths)
{
- args.check_exact_arg_count(0);
- System::println("Vcpkg package management program version %s\n"
- "\n"
- "See LICENSE.txt for license information.", Info::version()
- );
- exit(EXIT_SUCCESS);
+ System::println("Available architecture triplets:");
+ auto it = fs::directory_iterator(paths.triplets);
+ for (; it != fs::directory_iterator(); ++it)
+ {
+ System::println(" %s", it->path().stem().filename().string());
+ }
+ }
+
+ void print_usage()
+ {
+ System::println(
+ "Commands:\n"
+ " vcpkg search [pat] Search for packages available to be built\n"
+ " vcpkg install <pkg> Install a package\n"
+ " vcpkg remove <pkg> Uninstall a package. \n"
+ " vcpkg remove --purge <pkg> Uninstall and delete a package. \n"
+ " vcpkg list List installed packages\n"
+ " vcpkg update Display list of packages for updating\n"
+ " vcpkg hash <file> [alg] Hash a file by specific algorithm, default SHA512\n"
+ "\n"
+ "%s" // Integration help
+ "\n"
+ " vcpkg edit <pkg> Open up a port for editing (uses %%EDITOR%%, default 'code')\n"
+ " vcpkg import <pkg> Import a pre-built library\n"
+ " vcpkg create <pkg> <url>\n"
+ " [archivename] Create a new package\n"
+ " vcpkg owns <pat> Search for files in installed packages\n"
+ " vcpkg cache List cached compiled packages\n"
+ " vcpkg version Display version information\n"
+ " vcpkg contact Display contact information to send feedback\n"
+ "\n"
+ //"internal commands:\n"
+ //" --check-build-deps <controlfile>\n"
+ //" --create-binary-control <controlfile>\n"
+ //"\n"
+ "Options:\n"
+ " --triplet <t> Specify the target architecture triplet.\n"
+ " (default: %%VCPKG_DEFAULT_TRIPLET%%, see 'vcpkg help triplet')\n"
+ "\n"
+ " --vcpkg-root <path> Specify the vcpkg root directory\n"
+ " (default: %%VCPKG_ROOT%%)\n"
+ "\n"
+ "For more help (including examples) see the accompanying README.md."
+ , Integrate::INTEGRATE_COMMAND_HELPSTRING);
+ }
+
+ std::string create_example_string(const std::string& command_and_arguments)
+ {
+ std::string cs = Strings::format("Example:\n"
+ " vcpkg %s", command_and_arguments);
+ return cs;
+ }
+
+ void print_example(const std::string& command_and_arguments)
+ {
+ System::println(create_example_string(command_and_arguments));
}
- void help_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
args.check_max_arg_count(1);
+ args.check_and_get_optional_command_arguments({});
+
if (args.command_arguments.empty())
{
print_usage();
@@ -35,21 +87,4 @@ namespace vcpkg
}
exit(EXIT_SUCCESS);
}
-
- void contact_command(const vcpkg_cmd_arguments& args)
- {
- args.check_exact_arg_count(0);
- System::println("Send an email to %s with any feedback.", Info::email());
- exit(EXIT_SUCCESS);
- }
-
- void help_topic_valid_triplet(const vcpkg_paths& paths)
- {
- System::println("Available architecture triplets:");
- auto it = fs::directory_iterator(paths.triplets);
- for (; it != fs::directory_iterator(); ++it)
- {
- System::println(" %s", it->path().stem().filename().string());
- }
- }
}
diff --git a/toolsrc/src/commands_helpers.cpp b/toolsrc/src/commands_helpers.cpp
new file mode 100644
index 000000000..0c7ce15bb
--- /dev/null
+++ b/toolsrc/src/commands_helpers.cpp
@@ -0,0 +1,7 @@
+#include "vcpkg_Commands.h"
+#include "vcpkg_System.h"
+
+namespace vcpkg::Commands::Helpers
+{
+
+}
diff --git a/toolsrc/src/commands_import.cpp b/toolsrc/src/commands_import.cpp
index 3832f0e7b..11924b4b2 100644
--- a/toolsrc/src/commands_import.cpp
+++ b/toolsrc/src/commands_import.cpp
@@ -1,10 +1,10 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "Paragraphs.h"
#include "StatusParagraph.h"
#include "vcpkg_Files.h"
-#include <fstream>
-namespace vcpkg
+namespace vcpkg::Commands::Import
{
struct Binaries
{
@@ -12,26 +12,13 @@ namespace vcpkg
std::vector<fs::path> libs;
};
- static Binaries detect_files_in_directory_ending_with(const fs::path& path)
+ static Binaries find_binaries_in_dir(const fs::path& path)
{
Files::check_is_directory(path);
Binaries binaries;
-
- for (auto it = fs::recursive_directory_iterator(path); it != fs::recursive_directory_iterator(); ++it)
- {
- fs::path file = *it;
- // Skip if directory ?????
- if (file.extension() == ".dll")
- {
- binaries.dlls.push_back(file);
- }
- else if (file.extension() == ".lib")
- {
- binaries.libs.push_back(file);
- }
- }
-
+ binaries.dlls = Files::recursive_find_files_with_extension_in_dir(path, ".dll");
+ binaries.libs = Files::recursive_find_files_with_extension_in_dir(path, ".lib");
return binaries;
}
@@ -51,8 +38,8 @@ namespace vcpkg
Files::check_is_directory(include_directory);
Files::check_is_directory(project_directory);
Files::check_is_directory(destination_path);
- Binaries debug_binaries = detect_files_in_directory_ending_with(project_directory / "Debug");
- Binaries release_binaries = detect_files_in_directory_ending_with(project_directory / "Release");
+ Binaries debug_binaries = find_binaries_in_dir(project_directory / "Debug");
+ Binaries release_binaries = find_binaries_in_dir(project_directory / "Release");
fs::path destination_include_directory = destination_path / "include";
fs::copy(include_directory, destination_include_directory, fs::copy_options::recursive | fs::copy_options::overwrite_existing);
@@ -75,17 +62,18 @@ namespace vcpkg
std::ofstream(control_file_path) << control_file_data;
}
- void import_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = create_example_string(R"(import C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)");
+ static const std::string example = Commands::Help::create_example_string(R"(import C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)");
args.check_exact_arg_count(3, example);
+ args.check_and_get_optional_command_arguments({});
const fs::path control_file_path(args.command_arguments[0]);
const fs::path include_directory(args.command_arguments[1]);
const fs::path project_directory(args.command_arguments[2]);
auto pghs = Paragraphs::get_paragraphs(control_file_path);
- Checks::check_throw(pghs.size() == 1, "Invalid control file for package");
+ Checks::check_exit(pghs.size() == 1, "Invalid control file %s for package", control_file_path.generic_string());
StatusParagraph spgh;
spgh.package = BinaryParagraph(pghs[0]);
diff --git a/toolsrc/src/commands_install.cpp b/toolsrc/src/commands_install.cpp
new file mode 100644
index 000000000..bb3df943c
--- /dev/null
+++ b/toolsrc/src/commands_install.cpp
@@ -0,0 +1,247 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "vcpkglib.h"
+#include "metrics.h"
+#include "vcpkg_Files.h"
+#include "vcpkg_System.h"
+#include "vcpkg_Dependencies.h"
+#include "vcpkg_Input.h"
+#include "Paragraphs.h"
+
+namespace vcpkg::Commands::Install
+{
+ using Dependencies::package_spec_with_install_plan;
+ using Dependencies::install_plan_type;
+
+ static void install_and_write_listfile(const vcpkg_paths& paths, const BinaryParagraph& bpgh)
+ {
+ std::vector<std::string> output;
+
+ const fs::path package_prefix_path = paths.package_dir(bpgh.spec);
+ const size_t prefix_length = package_prefix_path.native().size();
+
+ const triplet& target_triplet = bpgh.spec.target_triplet();
+ const std::string& target_triplet_as_string = target_triplet.canonical_name();
+ std::error_code ec;
+ fs::create_directory(paths.installed / target_triplet_as_string, ec);
+ output.push_back(Strings::format(R"(%s/)", target_triplet_as_string));
+
+ for (auto it = fs::recursive_directory_iterator(package_prefix_path); it != fs::recursive_directory_iterator(); ++it)
+ {
+ const std::string filename = it->path().filename().generic_string();
+ if (fs::is_regular_file(it->status()) && (_stricmp(filename.c_str(), "CONTROL") == 0 || _stricmp(filename.c_str(), "BUILD_INFO") == 0))
+ {
+ // Do not copy the control file
+ continue;
+ }
+
+ const std::string suffix = it->path().generic_u8string().substr(prefix_length + 1);
+ const fs::path target = paths.installed / target_triplet_as_string / suffix;
+
+ auto status = it->status(ec);
+ if (ec)
+ {
+ System::println(System::color::error, "failed: %s: %s", it->path().u8string(), ec.message());
+ continue;
+ }
+
+ if (fs::is_directory(status))
+ {
+ fs::create_directory(target, ec);
+ if (ec)
+ {
+ System::println(System::color::error, "failed: %s: %s", target.u8string(), ec.message());
+ }
+
+ // Trailing backslash for directories
+ output.push_back(Strings::format(R"(%s/%s/)", target_triplet_as_string, suffix));
+ continue;
+ }
+
+ if (fs::is_regular_file(status))
+ {
+ if (fs::exists(target))
+ {
+ System::println(System::color::warning, "File %s was already present and will be overwritten", target.u8string(), ec.message());
+ }
+ fs::copy_file(*it, target, fs::copy_options::overwrite_existing, ec);
+ if (ec)
+ {
+ System::println(System::color::error, "failed: %s: %s", target.u8string(), ec.message());
+ }
+ output.push_back(Strings::format(R"(%s/%s)", target_triplet_as_string, suffix));
+ continue;
+ }
+
+ if (!fs::status_known(status))
+ {
+ System::println(System::color::error, "failed: %s: unknown status", it->path().u8string());
+ continue;
+ }
+
+ System::println(System::color::error, "failed: %s: cannot handle file type", it->path().u8string());
+ }
+
+ std::sort(output.begin(), output.end());
+
+ Files::write_all_lines(paths.listfile_path(bpgh), output);
+ }
+
+ static void remove_first_n_chars(std::vector<std::string>* strings, const size_t n)
+ {
+ for (std::string& s : *strings)
+ {
+ s.erase(0, n);
+ }
+ };
+
+ static std::vector<std::string> extract_files_in_triplet(const std::vector<StatusParagraph_and_associated_files>& pgh_and_files, const triplet& triplet)
+ {
+ std::vector<std::string> output;
+ for (const StatusParagraph_and_associated_files& t : pgh_and_files)
+ {
+ if (t.pgh.package.spec.target_triplet() != triplet)
+ {
+ continue;
+ }
+
+ output.insert(output.end(), t.files.cbegin(), t.files.cend());
+ }
+
+ std::sort(output.begin(), output.end());
+ return output;
+ }
+
+ static ImmutableSortedVector<std::string> build_list_of_package_files(const fs::path& package_dir)
+ {
+ const std::vector<fs::path> package_file_paths = Files::recursive_find_all_files_in_dir(package_dir);
+ std::vector<std::string> package_files;
+ const size_t package_remove_char_count = package_dir.generic_string().size() + 1; // +1 for the slash
+ std::transform(package_file_paths.cbegin(), package_file_paths.cend(), std::back_inserter(package_files), [package_remove_char_count](const fs::path& path)
+ {
+ std::string as_string = path.generic_string();
+ as_string.erase(0, package_remove_char_count);
+ return std::move(as_string);
+ });
+
+ return ImmutableSortedVector<std::string>::create(std::move(package_files));
+ }
+
+ static ImmutableSortedVector<std::string> build_list_of_installed_files(const std::vector<StatusParagraph_and_associated_files>& pgh_and_files, const triplet& triplet)
+ {
+ std::vector<std::string> installed_files = extract_files_in_triplet(pgh_and_files, triplet);
+ const size_t installed_remove_char_count = triplet.canonical_name().size() + 1; // +1 for the slash
+ remove_first_n_chars(&installed_files, installed_remove_char_count);
+
+ return ImmutableSortedVector<std::string>::create(std::move(installed_files));
+ }
+
+ void install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs* status_db)
+ {
+ const fs::path package_dir = paths.package_dir(binary_paragraph.spec);
+ const triplet& triplet = binary_paragraph.spec.target_triplet();
+ const std::vector<StatusParagraph_and_associated_files> pgh_and_files = get_installed_files(paths, *status_db);
+
+ const ImmutableSortedVector<std::string> package_files = build_list_of_package_files(package_dir);
+ const ImmutableSortedVector<std::string> installed_files = build_list_of_installed_files(pgh_and_files, triplet);
+
+ std::vector<std::string> intersection;
+ std::set_intersection(package_files.cbegin(), package_files.cend(),
+ installed_files.cbegin(), installed_files.cend(),
+ std::back_inserter(intersection));
+
+ if (!intersection.empty())
+ {
+ const fs::path triplet_install_path = paths.installed / triplet.canonical_name();
+ System::println(System::color::error, "The following files are already installed in %s and are in conflict with %s",
+ triplet_install_path.generic_string(),
+ binary_paragraph.spec);
+ System::print("\n ");
+ System::println(Strings::join("\n ", intersection));
+ System::println("");
+ exit(EXIT_FAILURE);
+ }
+
+ StatusParagraph spgh;
+ spgh.package = binary_paragraph;
+ spgh.want = want_t::install;
+ spgh.state = install_state_t::half_installed;
+ for (auto&& dep : spgh.package.depends)
+ {
+ if (status_db->find_installed(dep, spgh.package.spec.target_triplet()) == status_db->end())
+ {
+ Checks::unreachable();
+ }
+ }
+ write_update(paths, spgh);
+ status_db->insert(std::make_unique<StatusParagraph>(spgh));
+
+ install_and_write_listfile(paths, spgh.package);
+
+ spgh.state = install_state_t::installed;
+ write_update(paths, spgh);
+ status_db->insert(std::make_unique<StatusParagraph>(spgh));
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ {
+ static const std::string example = Commands::Help::create_example_string("install zlib zlib:x64-windows curl boost");
+ args.check_min_arg_count(1, example);
+ std::vector<package_spec> specs = Input::check_and_get_package_specs(args.command_arguments, default_target_triplet, example);
+ Input::check_triplets(specs, paths);
+ args.check_and_get_optional_command_arguments({});
+
+ StatusParagraphs status_db = database_load_check(paths);
+ std::vector<package_spec_with_install_plan> install_plan = Dependencies::create_install_plan(paths, specs, status_db);
+ Checks::check_exit(!install_plan.empty(), "Install plan cannot be empty");
+
+ std::string specs_string = install_plan[0].spec.toString();
+ for (size_t i = 1; i < install_plan.size(); ++i)
+ {
+ specs_string.push_back(',');
+ specs_string.append(install_plan[i].spec.toString());
+ }
+ TrackProperty("installplan", specs_string);
+
+ for (const package_spec_with_install_plan& action : install_plan)
+ {
+ try
+ {
+ if (action.plan.plan_type == install_plan_type::ALREADY_INSTALLED)
+ {
+ if (std::find(specs.begin(), specs.end(), action.spec) != specs.end())
+ {
+ System::println(System::color::success, "Package %s is already installed", action.spec);
+ }
+ }
+ else if (action.plan.plan_type == install_plan_type::BUILD_AND_INSTALL)
+ {
+ const Build::BuildResult result = Commands::Build::build_package(*action.plan.source_pgh, action.spec, paths, paths.port_dir(action.spec), status_db);
+ if (result != Build::BuildResult::SUCCEEDED)
+ {
+ System::println(System::color::error, Build::create_error_message(result, action.spec));
+ System::println(Build::create_user_troubleshooting_message(action.spec));
+ exit(EXIT_FAILURE);
+ }
+ const BinaryParagraph bpgh = Paragraphs::try_load_cached_package(paths, action.spec).get_or_throw();
+ install_package(paths, bpgh, &status_db);
+ System::println(System::color::success, "Package %s is installed", action.spec);
+ }
+ else if (action.plan.plan_type == install_plan_type::INSTALL)
+ {
+ install_package(paths, *action.plan.binary_pgh, &status_db);
+ System::println(System::color::success, "Package %s is installed", action.spec);
+ }
+ else
+ Checks::unreachable();
+ }
+ catch (const std::exception& e)
+ {
+ System::println(System::color::error, "Error: Could not install package %s: %s", action.spec, e.what());
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+}
diff --git a/toolsrc/src/commands_installation.cpp b/toolsrc/src/commands_installation.cpp
deleted file mode 100644
index 8d940bc9d..000000000
--- a/toolsrc/src/commands_installation.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-#include "vcpkg_Commands.h"
-#include "vcpkg.h"
-#include <fstream>
-#include "vcpkg_Environment.h"
-#include "metrics.h"
-#include "vcpkg_Files.h"
-#include "post_build_lint.h"
-#include "vcpkg_System.h"
-#include "vcpkg_Dependencies.h"
-#include "vcpkg_Input.h"
-#include "vcpkg_Maps.h"
-#include "vcpkg_info.h"
-
-namespace vcpkg
-{
- using Dependencies::package_spec_with_install_plan;
- using Dependencies::install_plan_type;
-
- static const std::string OPTION_CHECKS_ONLY = "--checks-only";
-
- static void create_binary_control_file(const vcpkg_paths& paths, const SourceParagraph& source_paragraph, const triplet& target_triplet)
- {
- const BinaryParagraph bpgh = BinaryParagraph(source_paragraph, target_triplet);
- const fs::path binary_control_file = paths.packages / bpgh.dir() / "CONTROL";
- std::ofstream(binary_control_file) << bpgh;
- }
-
- static void build_internal(const SourceParagraph& source_paragraph, const package_spec& spec, const vcpkg_paths& paths, const fs::path& port_dir)
- {
- Checks::check_exit(spec.name() == source_paragraph.name, "inconsistent arguments to build_internal()");
- const triplet& target_triplet = spec.target_triplet();
-
- const fs::path ports_cmake_script_path = paths.ports_cmake;
- const std::wstring command = Strings::wformat(LR"("%%VS140COMNTOOLS%%..\..\VC\vcvarsall.bat" %s && cmake -DCMD=BUILD -DPORT=%s -DTARGET_TRIPLET=%s "-DCURRENT_PORT_DIR=%s/." -P "%s")",
- Strings::utf8_to_utf16(target_triplet.architecture()),
- Strings::utf8_to_utf16(source_paragraph.name),
- Strings::utf8_to_utf16(target_triplet.canonical_name()),
- port_dir.generic_wstring(),
- ports_cmake_script_path.generic_wstring());
-
- System::Stopwatch2 timer;
- timer.start();
- int return_code = System::cmd_execute(command);
- timer.stop();
- TrackMetric("buildtimeus-" + to_string(spec), timer.microseconds());
-
- if (return_code != 0)
- {
- System::println(System::color::error, "Error: building package %s failed", to_string(spec));
- System::println("Please ensure sure you're using the latest portfiles with `vcpkg update`, then\n"
- "submit an issue at https://github.com/Microsoft/vcpkg/issues including:\n"
- " Package: %s\n"
- " Vcpkg version: %s\n"
- "\n"
- "Additionally, attach any relevant sections from the log files above."
- , to_string(spec), Info::version());
- TrackProperty("error", "build failed");
- TrackProperty("build_error", to_string(spec));
- exit(EXIT_FAILURE);
- }
-
- PostBuildLint::perform_all_checks(spec, paths);
-
- create_binary_control_file(paths, source_paragraph, target_triplet);
-
- // const fs::path port_buildtrees_dir = paths.buildtrees / spec.name;
- // delete_directory(port_buildtrees_dir);
- }
-
- static void install_and_write_listfile(const vcpkg_paths& paths, const BinaryParagraph& bpgh)
- {
- std::vector<std::string> output;
-
- const fs::path package_prefix_path = paths.package_dir(bpgh.spec);
- const size_t prefix_length = package_prefix_path.native().size();
-
- const triplet& target_triplet = bpgh.spec.target_triplet();
- const std::string& target_triplet_as_string = target_triplet.canonical_name();
- std::error_code ec;
- fs::create_directory(paths.installed / target_triplet_as_string, ec);
- output.push_back(Strings::format(R"(%s)", target_triplet_as_string));
-
- for (auto it = fs::recursive_directory_iterator(package_prefix_path); it != fs::recursive_directory_iterator(); ++it)
- {
- const std::string filename = it->path().filename().generic_string();
- if (fs::is_regular_file(it->status()) && (_stricmp(filename.c_str(), "CONTROL") == 0 || _stricmp(filename.c_str(), "BUILD_INFO") == 0))
- {
- // Do not copy the control file
- continue;
- }
-
- const std::string suffix = it->path().generic_u8string().substr(prefix_length + 1);
- const fs::path target = paths.installed / target_triplet_as_string / suffix;
-
- auto status = it->status(ec);
- if (ec)
- {
- System::println(System::color::error, "failed: %s: %s", it->path().u8string(), ec.message());
- continue;
- }
-
- if (fs::is_directory(status))
- {
- fs::create_directory(target, ec);
- if (ec)
- {
- System::println(System::color::error, "failed: %s: %s", target.u8string(), ec.message());
- }
-
- // Trailing backslash for directories
- output.push_back(Strings::format(R"(%s/%s)", target_triplet_as_string, suffix));
- continue;
- }
-
- if (fs::is_regular_file(status))
- {
- if (fs::exists(target))
- {
- System::println(System::color::warning, "File %s was already present and will be overwritten", target.u8string(), ec.message());
- }
- fs::copy_file(*it, target, fs::copy_options::overwrite_existing, ec);
- if (ec)
- {
- System::println(System::color::error, "failed: %s: %s", target.u8string(), ec.message());
- }
- output.push_back(Strings::format(R"(%s/%s)", target_triplet_as_string, suffix));
- continue;
- }
-
- if (!fs::status_known(status))
- {
- System::println(System::color::error, "failed: %s: unknown status", it->path().u8string());
- continue;
- }
-
- System::println(System::color::error, "failed: %s: cannot handle file type", it->path().u8string());
- }
-
- Files::write_all_lines(paths.listfile_path(bpgh), output);
- }
-
- static void remove_first_n_chars(std::vector<std::string>* strings, const size_t n)
- {
- for (std::string& s : *strings)
- {
- s.erase(0, n);
- }
- };
-
- static std::vector<std::string> extract_files_in_triplet(const std::vector<StatusParagraph_and_associated_files>& pgh_and_files, const triplet& triplet)
- {
- std::vector<std::string> output;
- for (const StatusParagraph_and_associated_files& t : pgh_and_files)
- {
- if (t.pgh.package.spec.target_triplet() != triplet)
- {
- continue;
- }
-
- output.insert(output.end(), t.files.cbegin(), t.files.cend());
- }
-
- std::sort(output.begin(), output.end());
- return output;
- }
-
- void install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs& status_db)
- {
- const fs::path package_dir = paths.package_dir(binary_paragraph.spec);
- const std::vector<fs::path> package_file_paths = Files::recursive_find_all_files_in_dir(package_dir);
- std::vector<std::string> package_files;
- const size_t package_remove_char_count = package_dir.generic_string().size() + 1; // +1 for the slash
- std::transform(package_file_paths.cbegin(), package_file_paths.cend(), std::back_inserter(package_files), [package_remove_char_count](const fs::path& path)
- {
- std::string as_string = path.generic_string();
- as_string.erase(0, package_remove_char_count);
- return std::move(as_string);
- });
- std::sort(package_files.begin(), package_files.end());
-
- const std::vector<StatusParagraph_and_associated_files>& pgh_and_files = get_installed_files(paths, status_db);
- const triplet& triplet = binary_paragraph.spec.target_triplet();
- std::vector<std::string> installed_files = extract_files_in_triplet(pgh_and_files, triplet);
- const size_t installed_remove_char_count = triplet.canonical_name().size() + 1; // +1 for the slash
- remove_first_n_chars(&installed_files, installed_remove_char_count);
- std::sort(installed_files.begin(), installed_files.end()); // Should already be sorted
-
- std::vector<std::string> intersection;
- std::set_intersection(package_files.cbegin(), package_files.cend(),
- installed_files.cbegin(), installed_files.cend(),
- std::back_inserter(intersection));
-
- if (!intersection.empty())
- {
- const fs::path triplet_install_path = paths.installed / triplet.canonical_name();
- System::println(System::color::error, "The following files are already installed in %s and are in conflict with %s",
- triplet_install_path.generic_string(),
- binary_paragraph.spec);
- System::println("");
- for (const std::string& s : intersection)
- {
- System::println(" %s", s);
- }
- System::println("");
- exit(EXIT_FAILURE);
- }
-
- StatusParagraph spgh;
- spgh.package = binary_paragraph;
- spgh.want = want_t::install;
- spgh.state = install_state_t::half_installed;
- for (auto&& dep : spgh.package.depends)
- {
- if (status_db.find_installed(dep, spgh.package.spec.target_triplet()) == status_db.end())
- {
- Checks::unreachable();
- }
- }
- write_update(paths, spgh);
- status_db.insert(std::make_unique<StatusParagraph>(spgh));
-
- install_and_write_listfile(paths, spgh.package);
-
- spgh.state = install_state_t::installed;
- write_update(paths, spgh);
- status_db.insert(std::make_unique<StatusParagraph>(spgh));
- }
-
- void install_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
- {
- static const std::string example = create_example_string("install zlib zlib:x64-windows curl boost");
- args.check_min_arg_count(1, example);
- StatusParagraphs status_db = database_load_check(paths);
-
- std::vector<package_spec> specs = Input::check_and_get_package_specs(args.command_arguments, default_target_triplet, example);
- Input::check_triplets(specs, paths);
- std::vector<package_spec_with_install_plan> install_plan = Dependencies::create_install_plan(paths, specs, status_db);
- Checks::check_exit(!install_plan.empty(), "Install plan cannot be empty");
-
- std::string specs_string = to_string(install_plan[0].spec);
- for (size_t i = 1; i < install_plan.size(); ++i)
- {
- specs_string.push_back(',');
- specs_string.append(to_string(install_plan[i].spec));
- }
- TrackProperty("installplan", specs_string);
- Environment::ensure_utilities_on_path(paths);
-
- for (const package_spec_with_install_plan& action : install_plan)
- {
- try
- {
- if (action.plan.type == install_plan_type::ALREADY_INSTALLED)
- {
- if (std::find(specs.begin(), specs.end(), action.spec) != specs.end())
- {
- System::println(System::color::success, "Package %s is already installed", action.spec);
- }
- }
- else if (action.plan.type == install_plan_type::BUILD_AND_INSTALL)
- {
- build_internal(*action.plan.spgh, action.spec, paths, paths.port_dir(action.spec));
- const BinaryParagraph bpgh = try_load_cached_package(paths, action.spec).get_or_throw();
- install_package(paths, bpgh, status_db);
- System::println(System::color::success, "Package %s is installed", action.spec);
- }
- else if (action.plan.type == install_plan_type::INSTALL)
- {
- install_package(paths, *action.plan.bpgh, status_db);
- System::println(System::color::success, "Package %s is installed", action.spec);
- }
- else
- Checks::unreachable();
- }
- catch (const std::exception& e)
- {
- System::println(System::color::error, "Error: Could not install package %s: %s", action.spec, e.what());
- exit(EXIT_FAILURE);
- }
- }
-
- exit(EXIT_SUCCESS);
- }
-
- void build_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
- {
- static const std::string example = create_example_string("build zlib:x64-windows");
-
- // Installing multiple packages leads to unintuitive behavior if one of them depends on another.
- // Allowing only 1 package for now.
-
- args.check_exact_arg_count(1, example);
-
- StatusParagraphs status_db = database_load_check(paths);
-
- const package_spec spec = Input::check_and_get_package_spec(args.command_arguments.at(0), default_target_triplet, example);
- Input::check_triplet(spec.target_triplet(), paths);
-
- const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({OPTION_CHECKS_ONLY});
- if (options.find(OPTION_CHECKS_ONLY) != options.end())
- {
- PostBuildLint::perform_all_checks(spec, paths);
- exit(EXIT_SUCCESS);
- }
-
- // Explicitly load and use the portfile's build dependencies when resolving the build command (instead of a cached package's dependencies).
- const expected<SourceParagraph> maybe_spgh = try_load_port(paths, spec.name());
- Checks::check_exit(!maybe_spgh.error_code(), "Could not find package named %s: %s", spec, maybe_spgh.error_code().message());
- const SourceParagraph& spgh = *maybe_spgh.get();
-
- const std::vector<std::string> first_level_deps = filter_dependencies(spgh.depends, spec.target_triplet());
-
- std::vector<package_spec> first_level_deps_specs;
- for (const std::string& dep : first_level_deps)
- {
- first_level_deps_specs.push_back(package_spec::from_name_and_triplet(dep, spec.target_triplet()).get_or_throw());
- }
-
- std::vector<package_spec_with_install_plan> unmet_dependencies = Dependencies::create_install_plan(paths, first_level_deps_specs, status_db);
- unmet_dependencies.erase(
- std::remove_if(unmet_dependencies.begin(), unmet_dependencies.end(), [](const package_spec_with_install_plan& p)
- {
- return p.plan.type == install_plan_type::ALREADY_INSTALLED;
- }),
- unmet_dependencies.end());
-
- if (!unmet_dependencies.empty())
- {
- System::println(System::color::error, "The build command requires all dependencies to be already installed.");
- System::println("The following dependencies are missing:");
- System::println("");
- for (const package_spec_with_install_plan& p : unmet_dependencies)
- {
- System::println(" %s", to_string(p.spec));
- }
- System::println("");
- exit(EXIT_FAILURE);
- }
-
- Environment::ensure_utilities_on_path(paths);
- build_internal(spgh, spec, paths, paths.port_dir(spec));
- exit(EXIT_SUCCESS);
- }
-
- void build_external_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
- {
- static const std::string example = create_example_string(R"(build_external zlib2 C:\path\to\dir\with\controlfile\)");
- args.check_exact_arg_count(2, example);
-
- expected<package_spec> maybe_current_spec = package_spec::from_string(args.command_arguments[0], default_target_triplet);
- if (auto spec = maybe_current_spec.get())
- {
- Input::check_triplet(spec->target_triplet(), paths);
- Environment::ensure_utilities_on_path(paths);
- const fs::path port_dir = args.command_arguments.at(1);
- const expected<SourceParagraph> maybe_spgh = try_load_port(port_dir);
- if (auto spgh = maybe_spgh.get())
- {
- build_internal(*spgh, *spec, paths, port_dir);
- exit(EXIT_SUCCESS);
- }
- }
-
- System::println(System::color::error, "Error: %s: %s", maybe_current_spec.error_code().message(), args.command_arguments[0]);
- print_example(Strings::format("%s zlib:x64-windows", args.command));
- exit(EXIT_FAILURE);
- }
-}
diff --git a/toolsrc/src/commands_integration.cpp b/toolsrc/src/commands_integrate.cpp
index e7e5b2d8d..f98b9f77c 100644
--- a/toolsrc/src/commands_integration.cpp
+++ b/toolsrc/src/commands_integrate.cpp
@@ -1,22 +1,17 @@
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <shellapi.h>
+#include "pch.h"
#include "vcpkg_Commands.h"
-#include <fstream>
-#include <regex>
-#include <array>
#include "vcpkg_Environment.h"
#include "vcpkg_Checks.h"
#include "vcpkg_System.h"
#include "vcpkg_Files.h"
-namespace vcpkg
+namespace vcpkg::Commands::Integrate
{
static const std::array<fs::path, 2> old_system_target_files = {
- "C:/Program Files (x86)/MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.nuget.targets",
- "C:/Program Files (x86)/MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.system.targets"
+ Environment::get_ProgramFiles_32_bit() / "MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.nuget.targets",
+ Environment::get_ProgramFiles_32_bit() / "MSBuild/14.0/Microsoft.Common.Targets/ImportBefore/vcpkg.system.targets"
};
- static const fs::path system_wide_targets_file = "C:/Program Files (x86)/MSBuild/Microsoft.Cpp/v4.0/V140/ImportBefore/Default/vcpkg.system.props";
+ static const fs::path system_wide_targets_file = Environment::get_ProgramFiles_32_bit() / "MSBuild/Microsoft.Cpp/v4.0/V140/ImportBefore/Default/vcpkg.system.props";
static std::string create_appdata_targets_shortcut(const std::string& target_path) noexcept
{
@@ -114,7 +109,7 @@ namespace vcpkg
static elevation_prompt_user_choice elevated_cmd_execute(const std::string& param)
{
- SHELLEXECUTEINFO shExInfo = {0};
+ SHELLEXECUTEINFO shExInfo = { 0 };
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExInfo.hwnd = nullptr;
@@ -141,7 +136,7 @@ namespace vcpkg
static fs::path get_appdata_targets_path()
{
- return fs::path(System::wdupenv_str(L"LOCALAPPDATA")) / "vcpkg" / "vcpkg.user.targets";
+ return fs::path(*System::get_environmental_variable(L"LOCALAPPDATA")) / "vcpkg" / "vcpkg.user.targets";
}
static void integrate_install(const vcpkg_paths& paths)
@@ -171,20 +166,17 @@ namespace vcpkg
fs::create_directory(tmp_dir);
bool should_install_system = true;
- if (fs::exists(system_wide_targets_file))
+ const expected<std::string> system_wide_file_contents = Files::read_contents(system_wide_targets_file);
+ if (auto contents_data = system_wide_file_contents.get())
{
- auto system_wide_file_contents = Files::read_contents(system_wide_targets_file);
- if (auto contents_data = system_wide_file_contents.get())
+ std::regex re(R"###(<!-- version (\d+) -->)###");
+ std::match_results<std::string::const_iterator> match;
+ auto found = std::regex_search(*contents_data, match, re);
+ if (found)
{
- std::regex re(R"###(<!-- version (\d+) -->)###");
- std::match_results<std::string::const_iterator> match;
- auto found = std::regex_search(*contents_data, match, re);
- if (found)
- {
- int ver = atoi(match[1].str().c_str());
- if (ver >= 1)
- should_install_system = false;
- }
+ int ver = atoi(match[1].str().c_str());
+ if (ver >= 1)
+ should_install_system = false;
}
}
@@ -219,37 +211,45 @@ namespace vcpkg
exit(EXIT_FAILURE);
}
System::println(System::color::success, "Applied user-wide integration for this vcpkg root.");
+ const fs::path cmake_toolchain = paths.buildsystems / "vcpkg.cmake";
System::println("\n"
- "All C++ projects can now #include any installed libraries.\n"
- "Linking will be handled automatically.\n"
- "Installing new libraries will make them instantly available.");
+ "All MSBuild C++ projects can now #include any installed libraries.\n"
+ "Linking will be handled automatically.\n"
+ "Installing new libraries will make them instantly available.\n"
+ "\n"
+ "CMake projects should use -DCMAKE_TOOLCHAIN_FILE=%s", cmake_toolchain.generic_string());
exit(EXIT_SUCCESS);
}
static void integrate_remove()
{
- auto path = get_appdata_targets_path();
- if (!fs::exists(path))
+ const fs::path path = get_appdata_targets_path();
+
+ std::error_code ec;
+ bool was_deleted = fs::remove(path, ec);
+
+ if (ec)
{
- System::println(System::color::success, "User-wide integration is not installed");
- exit(EXIT_SUCCESS);
+ System::println(System::color::error, "Error: Unable to remove user-wide integration: %d", ec.message());
+ exit(EXIT_FAILURE);
}
- const std::wstring cmd_line = Strings::wformat(LR"(DEL "%s")", get_appdata_targets_path().native());
- const int exit_code = System::cmd_execute(cmd_line);
- if (exit_code)
+ if (was_deleted)
+ {
+ System::println(System::color::success, "User-wide integration was removed");
+ }
+ else
{
- System::println(System::color::error, "Error: Unable to remove user-wide integration: %d", exit_code);
- exit(exit_code);
+ System::println(System::color::success, "User-wide integration is not installed");
}
- System::println(System::color::success, "User-wide integration was removed");
+
exit(EXIT_SUCCESS);
}
static void integrate_project(const vcpkg_paths& paths)
{
- Environment::ensure_nuget_on_path(paths);
+ const fs::path& nuget_exe = paths.get_nuget_exe();
const fs::path& buildsystems_dir = paths.buildsystems;
const fs::path tmp_dir = buildsystems_dir / "tmp";
@@ -267,17 +267,12 @@ namespace vcpkg
std::ofstream(nuspec_file_path) << create_nuspec_file(paths.root, nuget_id, nupkg_version);
// Using all forward slashes for the command line
- const std::wstring cmd_line = Strings::wformat(LR"(nuget.exe pack -OutputDirectory "%s" "%s" > nul)", buildsystems_dir.native(), nuspec_file_path.native());
+ const std::wstring cmd_line = Strings::wformat(LR"("%s" pack -OutputDirectory "%s" "%s" > nul)", nuget_exe.native(), buildsystems_dir.native(), nuspec_file_path.native());
- const int exit_code = System::cmd_execute(cmd_line);
+ const int exit_code = System::cmd_execute_clean(cmd_line);
const fs::path nuget_package = buildsystems_dir / Strings::format("%s.%s.nupkg", nuget_id, nupkg_version);
- if (exit_code != 0 || !fs::exists(nuget_package))
- {
- System::println(System::color::error, "Error: NuGet package creation failed");
- exit(EXIT_FAILURE);
- }
-
+ Checks::check_exit(exit_code == 0 && fs::exists(nuget_package), "Error: NuGet package creation failed");
System::println(System::color::success, "Created nupkg: %s", nuget_package.string());
System::println(R"(
@@ -293,11 +288,12 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
" vcpkg integrate remove Remove user-wide integration\n"
" vcpkg integrate project Generate a referencing nuget package for individual VS project use\n";
- void integrate_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
static const std::string example = Strings::format("Commands:\n"
"%s", INTEGRATE_COMMAND_HELPSTRING);
args.check_exact_arg_count(1, example);
+ args.check_and_get_optional_command_arguments({});
if (args.command_arguments[0] == "install")
{
diff --git a/toolsrc/src/commands_list.cpp b/toolsrc/src/commands_list.cpp
index cc51232e9..7bfc11f1b 100644
--- a/toolsrc/src/commands_list.cpp
+++ b/toolsrc/src/commands_list.cpp
@@ -1,9 +1,10 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
-#include "vcpkg.h"
+#include "vcpkglib.h"
#include "vcpkg_System.h"
#include "vcpkglib_helpers.h"
-namespace vcpkg
+namespace vcpkg::Commands::List
{
static void do_print(const StatusParagraph& pgh)
{
@@ -13,11 +14,12 @@ namespace vcpkg
details::shorten_description(pgh.package.description));
}
- void list_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
static const std::string example = Strings::format(
- "The argument should be a substring to search for, or no argument to display all installed libraries.\n%s", create_example_string("list png"));
+ "The argument should be a substring to search for, or no argument to display all installed libraries.\n%s", Commands::Help::create_example_string("list png"));
args.check_max_arg_count(1, example);
+ args.check_and_get_optional_command_arguments({});
const StatusParagraphs status_paragraphs = database_load_check(paths);
std::vector<StatusParagraph> installed_packages;
diff --git a/toolsrc/src/commands_other.cpp b/toolsrc/src/commands_other.cpp
deleted file mode 100644
index 6df325100..000000000
--- a/toolsrc/src/commands_other.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "vcpkg_Commands.h"
-#include "vcpkg_System.h"
-
-namespace vcpkg
-{
- void print_usage()
- {
- System::println(
- "Commands:\n"
- " vcpkg search [pat] Search for packages available to be built\n"
- " vcpkg install <pkg> Install a package\n"
- " vcpkg remove <pkg> Uninstall a package. \n"
- " vcpkg remove --purge <pkg> Uninstall and delete a package. \n"
- " vcpkg list List installed packages\n"
- " vcpkg update Display list of packages for updating\n"
- " vcpkg hash <file> [alg] Hash a file by specific algorithm, default SHA512\n"
- "\n"
- "%s" // Integration help
- "\n"
- " vcpkg edit <pkg> Open up a port for editing (uses %%EDITOR%%, default 'code')\n"
- " vcpkg import <pkg> Import a pre-built library\n"
- " vcpkg create <pkg> <url>\n"
- " [archivename] Create a new package\n"
- " vcpkg owns <pat> Search for files in installed packages\n"
- " vcpkg cache List cached compiled packages\n"
- " vcpkg version Display version information\n"
- " vcpkg contact Display contact information to send feedback\n"
- "\n"
- //"internal commands:\n"
- //" --check-build-deps <controlfile>\n"
- //" --create-binary-control <controlfile>\n"
- //"\n"
- "Options:\n"
- " --triplet <t> Specify the target architecture triplet.\n"
- " (default: %%VCPKG_DEFAULT_TRIPLET%%, see 'vcpkg help triplet')\n"
- "\n"
- " --vcpkg-root <path> Specify the vcpkg root directory\n"
- " (default: %%VCPKG_ROOT%%)\n"
- "\n"
- "For more help (including examples) see the accompanying README.md."
- , INTEGRATE_COMMAND_HELPSTRING);
- }
-
- std::string create_example_string(const std::string& command_and_arguments)
- {
- std::string cs = Strings::format("Example:\n"
- " vcpkg %s", command_and_arguments);
- return cs;
- }
-
- void print_example(const std::string& command_and_arguments)
- {
- System::println(create_example_string(command_and_arguments));
- }
-
- void internal_test_command(const vcpkg_cmd_arguments& /*args*/, const vcpkg_paths& /*paths*/)
- {
- // auto data = FormatEventData("test");
- // Track(data);
- exit(EXIT_SUCCESS);
- }
-
- const std::vector<package_name_and_function<command_type_a>>& get_available_commands_type_a()
- {
- static std::vector<package_name_and_function<command_type_a>> t = {
- {"install", install_command},
- {"remove", remove_command},
- {"build", build_command},
- {"build_external", build_external_command}
- };
- return t;
- }
-
- const std::vector<package_name_and_function<command_type_b>>& get_available_commands_type_b()
- {
- static std::vector<package_name_and_function<command_type_b>> t = {
- {"/?", help_command},
- {"help", help_command},
- {"search", search_command},
- {"list", list_command},
- {"integrate", integrate_command},
- {"owns", owns_command},
- {"update", update_command},
- {"edit", edit_command},
- {"create", create_command},
- {"import", import_command},
- {"cache", cache_command},
- {"internal_test", internal_test_command},
- {"portsdiff", portsdiff_command}
- };
- return t;
- }
-
- const std::vector<package_name_and_function<command_type_c>>& get_available_commands_type_c()
- {
- static std::vector<package_name_and_function<command_type_c>> t = {
- {"version", &version_command},
- {"contact", &contact_command},
- {"hash", &hash_command},
- };
- return t;
- }
-}
diff --git a/toolsrc/src/commands_owns.cpp b/toolsrc/src/commands_owns.cpp
index 62dac57eb..16bb986e2 100644
--- a/toolsrc/src/commands_owns.cpp
+++ b/toolsrc/src/commands_owns.cpp
@@ -1,8 +1,9 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
-#include "vcpkg.h"
+#include "vcpkglib.h"
-namespace vcpkg
+namespace vcpkg::Commands::Owns
{
static void search_file(const vcpkg_paths& paths, const std::string& file_substr, const StatusParagraphs& status_db)
{
@@ -21,10 +22,11 @@ namespace vcpkg
}
}
- void owns_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = Strings::format("The argument should be a pattern to search for. %s", create_example_string("owns zlib.dll"));
+ static const std::string example = Strings::format("The argument should be a pattern to search for. %s", Commands::Help::create_example_string("owns zlib.dll"));
args.check_exact_arg_count(1, example);
+ args.check_and_get_optional_command_arguments({});
StatusParagraphs status_db = database_load_check(paths);
search_file(paths, args.command_arguments[0], status_db);
diff --git a/toolsrc/src/commands_portsdiff.cpp b/toolsrc/src/commands_portsdiff.cpp
index 46c6c90c7..4d5a589f6 100644
--- a/toolsrc/src/commands_portsdiff.cpp
+++ b/toolsrc/src/commands_portsdiff.cpp
@@ -1,26 +1,19 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
-#include <map>
-#include <iterator>
#include "vcpkg_Maps.h"
-#include <iostream>
-#include <iomanip>
-#include <set>
-#include "Paragraphs.h"
#include "SourceParagraph.h"
#include "vcpkg_Environment.h"
+#include "Paragraphs.h"
-namespace vcpkg
+namespace vcpkg::Commands::PortsDiff
{
static void do_print_name_and_version(const std::vector<std::string>& ports_to_print, const std::map<std::string, std::string>& names_and_versions)
{
for (const std::string& name : ports_to_print)
{
const std::string& version = names_and_versions.at(name);
- std::cout << std::left
- << std::setw(20) << name << ' '
- << std::setw(16) << version << ' '
- << '\n';
+ System::println("%-20s %-16s", name, version);
}
}
@@ -30,85 +23,59 @@ namespace vcpkg
{
for (const std::string& name : ports_to_print)
{
- if (name == "")
- {
- continue;
- }
-
const std::string& previous_version = previous_names_and_versions.at(name);
const std::string& current_version = current_names_and_versions.at(name);
- std::cout << std::left
- << std::setw(20) << name << ' '
- << std::setw(16) << previous_version << " -> " << current_version
- << '\n';
- }
- }
-
- static std::map<std::string, std::string> read_all_ports(const fs::path& ports_folder_path)
- {
- std::map<std::string, std::string> names_and_versions;
-
- for (auto it = fs::directory_iterator(ports_folder_path); it != fs::directory_iterator(); ++it)
- {
- const fs::path& path = it->path();
-
- try
- {
- auto pghs = Paragraphs::get_paragraphs(path / "CONTROL");
- if (pghs.empty())
- continue;
- auto srcpgh = SourceParagraph(pghs[0]);
- names_and_versions.emplace(srcpgh.name, srcpgh.version);
- }
- catch (std::runtime_error const&)
- {
- }
+ System::println("%-20s %-16s -> %s", name, previous_version, current_version);
}
-
- return names_and_versions;
}
static std::map<std::string, std::string> read_ports_from_commit(const vcpkg_paths& paths, const std::wstring& git_commit_id)
{
+ const fs::path& git_exe = paths.get_git_exe();
const fs::path dot_git_dir = paths.root / ".git";
const std::wstring ports_dir_name_as_string = paths.ports.filename().native();
const fs::path temp_checkout_path = paths.root / Strings::wformat(L"%s-%s", ports_dir_name_as_string, git_commit_id);
fs::create_directory(temp_checkout_path);
const std::wstring checkout_this_dir = Strings::wformat(LR"(.\%s)", ports_dir_name_as_string); // Must be relative to the root of the repository
- const std::wstring cmd = Strings::wformat(LR"(git --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s & git reset >NUL)",
+ const std::wstring cmd = Strings::wformat(LR"("%s" --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s & "%s" reset >NUL)",
+ git_exe.native(),
dot_git_dir.native(),
temp_checkout_path.native(),
git_commit_id,
checkout_this_dir,
- L".vcpkg-root");
- System::cmd_execute(cmd);
- std::map<std::string, std::string> names_and_versions = read_all_ports(temp_checkout_path / ports_dir_name_as_string);
+ L".vcpkg-root",
+ git_exe.native());
+ System::cmd_execute_clean(cmd);
+ const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(temp_checkout_path / ports_dir_name_as_string);
+ const std::map<std::string, std::string> names_and_versions = Paragraphs::extract_port_names_and_versions(source_paragraphs);
fs::remove_all(temp_checkout_path);
return names_and_versions;
}
- static void check_commit_exists(const std::wstring& git_commit_id)
+ static void check_commit_exists(const fs::path& git_exe, const std::wstring& git_commit_id)
{
static const std::string VALID_COMMIT_OUTPUT = "commit\n";
- const std::wstring cmd = Strings::wformat(LR"(git cat-file -t %s 2>NUL)", git_commit_id);
+ const std::wstring cmd = Strings::wformat(LR"("%s" cat-file -t %s 2>NUL)", git_exe.native(), git_commit_id);
const System::exit_code_and_output output = System::cmd_execute_and_capture_output(cmd);
Checks::check_exit(output.output == VALID_COMMIT_OUTPUT, "Invalid commit id %s", Strings::utf16_to_utf8(git_commit_id));
}
- void portsdiff_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = Strings::format("The argument should be a branch/tag/hash to checkout.\n%s", create_example_string("portsdiff mybranchname"));
+ static const std::string example = Strings::format("The argument should be a branch/tag/hash to checkout.\n%s", Commands::Help::create_example_string("portsdiff mybranchname"));
args.check_min_arg_count(1, example);
args.check_max_arg_count(2, example);
+ args.check_and_get_optional_command_arguments({});
+
+ const fs::path& git_exe = paths.get_git_exe();
- Environment::ensure_git_on_path(paths);
const std::wstring git_commit_id_for_previous_snapshot = Strings::utf8_to_utf16(args.command_arguments.at(0));
const std::wstring git_commit_id_for_current_snapshot = args.command_arguments.size() < 2 ? L"HEAD" : Strings::utf8_to_utf16(args.command_arguments.at(1));
- check_commit_exists(git_commit_id_for_current_snapshot);
- check_commit_exists(git_commit_id_for_previous_snapshot);
+ check_commit_exists(git_exe, git_commit_id_for_current_snapshot);
+ check_commit_exists(git_exe, git_commit_id_for_previous_snapshot);
const std::map<std::string, std::string> current_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_current_snapshot);
const std::map<std::string, std::string> previous_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_previous_snapshot);
diff --git a/toolsrc/src/commands_remove.cpp b/toolsrc/src/commands_remove.cpp
index 445213fc2..1b7b7923a 100644
--- a/toolsrc/src/commands_remove.cpp
+++ b/toolsrc/src/commands_remove.cpp
@@ -1,12 +1,18 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
-#include "vcpkg.h"
+#include "vcpkglib.h"
#include "vcpkg_System.h"
#include "vcpkg_Input.h"
-#include <fstream>
+#include "vcpkg_Dependencies.h"
-namespace vcpkg
+namespace vcpkg::Commands::Remove
{
+ using Dependencies::package_spec_with_remove_plan;
+ using Dependencies::remove_plan_type;
+ using Dependencies::request_type;
+
static const std::string OPTION_PURGE = "--purge";
+ static const std::string OPTION_RECURSE = "--recurse";
static void delete_directory(const fs::path& directory)
{
@@ -22,78 +28,9 @@ namespace vcpkg
}
}
- enum class deinstall_plan
- {
- not_installed,
- dependencies_not_satisfied,
- should_deinstall
- };
-
- static deinstall_plan deinstall_package_plan(
- const StatusParagraphs::iterator package_it,
- const StatusParagraphs& status_db,
- std::vector<const StatusParagraph*>& dependencies_out)
- {
- dependencies_out.clear();
-
- if (package_it == status_db.end() || (*package_it)->state == install_state_t::not_installed)
- {
- return deinstall_plan::not_installed;
- }
-
- auto& pkg = (*package_it)->package;
-
- for (auto&& inst_pkg : status_db)
- {
- if (inst_pkg->want != want_t::install)
- continue;
- if (inst_pkg->package.spec.target_triplet() != pkg.spec.target_triplet())
- continue;
-
- const auto& deps = inst_pkg->package.depends;
-
- if (std::find(deps.begin(), deps.end(), pkg.spec.name()) != deps.end())
- {
- dependencies_out.push_back(inst_pkg.get());
- }
- }
-
- if (!dependencies_out.empty())
- return deinstall_plan::dependencies_not_satisfied;
-
- return deinstall_plan::should_deinstall;
- }
-
- static void deinstall_package(const vcpkg_paths& paths, const package_spec& spec, StatusParagraphs& status_db)
+ static void remove_package(const vcpkg_paths& paths, const package_spec& spec, StatusParagraphs* status_db)
{
- auto package_it = status_db.find(spec.name(), spec.target_triplet());
- if (package_it == status_db.end())
- {
- System::println(System::color::success, "Package %s is not installed", spec);
- return;
- }
-
- auto& pkg = **package_it;
-
- std::vector<const StatusParagraph*> deps;
- auto plan = deinstall_package_plan(package_it, status_db, deps);
- switch (plan)
- {
- case deinstall_plan::not_installed:
- System::println(System::color::success, "Package %s is not installed", spec);
- return;
- case deinstall_plan::dependencies_not_satisfied:
- System::println(System::color::error, "Error: Cannot remove package %s:", spec);
- for (auto&& dep : deps)
- {
- System::println(" %s depends on %s", dep->package.displayname(), pkg.package.displayname());
- }
- exit(EXIT_FAILURE);
- case deinstall_plan::should_deinstall:
- break;
- default:
- Checks::unreachable();
- }
+ StatusParagraph& pkg = **status_db->find(spec.name(), spec.target_triplet());
pkg.want = want_t::purge;
pkg.state = install_state_t::half_installed;
@@ -163,31 +100,125 @@ namespace vcpkg
pkg.state = install_state_t::not_installed;
write_update(paths, pkg);
- System::println(System::color::success, "Package %s was successfully removed", pkg.package.displayname());
}
- void remove_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ static void sort_packages_by_name(std::vector<const package_spec_with_remove_plan*>* packages)
{
- static const std::string example = create_example_string("remove zlib zlib:x64-windows curl boost");
- args.check_min_arg_count(1, example);
+ std::sort(packages->begin(), packages->end(), [](const package_spec_with_remove_plan* left, const package_spec_with_remove_plan* right) -> bool
+ {
+ return left->spec.name() < right->spec.name();
+ });
+ }
- const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({OPTION_PURGE});
- auto status_db = database_load_check(paths);
+ static void print_plan(const std::vector<package_spec_with_remove_plan>& plan)
+ {
+ std::vector<const package_spec_with_remove_plan*> not_installed;
+ std::vector<const package_spec_with_remove_plan*> remove;
+ for (const package_spec_with_remove_plan& i : plan)
+ {
+ if (i.plan.plan_type == remove_plan_type::NOT_INSTALLED)
+ {
+ not_installed.push_back(&i);
+ continue;
+ }
+
+ if (i.plan.plan_type == remove_plan_type::REMOVE)
+ {
+ remove.push_back(&i);
+ continue;
+ }
+
+ Checks::unreachable();
+ }
+
+ if (!not_installed.empty())
+ {
+ sort_packages_by_name(&not_installed);
+ System::println("The following packages are not installed, so not removed:\n%s",
+ Strings::join("\n ", not_installed, [](const package_spec_with_remove_plan* p)
+ {
+ return " " + p->spec.toString();
+ }));
+ }
+
+ if (!remove.empty())
+ {
+ sort_packages_by_name(&remove);
+ System::println("The following packages will be removed:\n%s",
+ Strings::join("\n", remove, [](const package_spec_with_remove_plan* p)
+ {
+ if (p->plan.request_type == Dependencies::request_type::AUTO_SELECTED)
+ {
+ return " * " + p->spec.toString();
+ }
+
+ if (p->plan.request_type == Dependencies::request_type::USER_REQUESTED)
+ {
+ return " " + p->spec.toString();
+ }
+
+ Checks::unreachable();
+ }));
+ }
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet)
+ {
+ static const std::string example = Commands::Help::create_example_string("remove zlib zlib:x64-windows curl boost");
+ args.check_min_arg_count(1, example);
std::vector<package_spec> specs = Input::check_and_get_package_specs(args.command_arguments, default_target_triplet, example);
Input::check_triplets(specs, paths);
- bool alsoRemoveFolderFromPackages = options.find(OPTION_PURGE) != options.end();
+ const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({ OPTION_PURGE, OPTION_RECURSE });
+ const bool alsoRemoveFolderFromPackages = options.find(OPTION_PURGE) != options.end();
+ const bool isRecursive = options.find(OPTION_RECURSE) != options.end();
+
+ auto status_db = database_load_check(paths);
+ const std::vector<package_spec_with_remove_plan> remove_plan = Dependencies::create_remove_plan(specs, status_db);
+ Checks::check_exit(!remove_plan.empty(), "Remove plan cannot be empty");
+
+ print_plan(remove_plan);
+
+ const bool has_non_user_requested_packages = std::find_if(remove_plan.cbegin(), remove_plan.cend(), [](const package_spec_with_remove_plan& package)-> bool
+ {
+ return package.plan.request_type != request_type::USER_REQUESTED;
+ }) != remove_plan.cend();
- for (const package_spec& spec : specs)
+ if (has_non_user_requested_packages && !isRecursive)
{
- deinstall_package(paths, spec, status_db);
+ System::println(System::color::warning,
+ "Additional packages (*) need to be removed to complete this operation.\n"
+ "If you are sure you want to remove them, run the command with the --recurse option");
+ exit(EXIT_FAILURE);
+ }
+
+ for (const package_spec_with_remove_plan& action : remove_plan)
+ {
+ const std::string display_name = action.spec.display_name();
+
+ switch (action.plan.plan_type)
+ {
+ case remove_plan_type::NOT_INSTALLED:
+ System::println(System::color::success, "Package %s is not installed", display_name);
+ break;
+ case remove_plan_type::REMOVE:
+ System::println("Removing package %s... ", display_name);
+ remove_package(paths, action.spec, &status_db);
+ System::println(System::color::success, "Removing package %s... done", display_name);
+ break;
+ case remove_plan_type::UNKNOWN:
+ default:
+ Checks::unreachable();
+ }
if (alsoRemoveFolderFromPackages)
{
- const fs::path spec_package_dir = paths.packages / spec.dir();
- delete_directory(spec_package_dir);
+ System::println("Purging package %s... ", display_name);
+ delete_directory(paths.packages / action.spec.dir());
+ System::println(System::color::success, "Purging package %s... done", display_name);
}
}
+
exit(EXIT_SUCCESS);
}
}
diff --git a/toolsrc/src/commands_search.cpp b/toolsrc/src/commands_search.cpp
index a4714477e..8bac858f1 100644
--- a/toolsrc/src/commands_search.cpp
+++ b/toolsrc/src/commands_search.cpp
@@ -1,35 +1,47 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
#include "vcpkg_System.h"
#include "Paragraphs.h"
#include "vcpkglib_helpers.h"
#include "SourceParagraph.h"
-namespace vcpkg
+namespace vcpkg::Commands::Search
{
- static std::vector<SourceParagraph> read_all_source_paragraphs(const vcpkg_paths& paths)
+ static const std::string OPTION_GRAPH = "--graph"; //TODO: This should find a better home, eventually
+
+ static std::string replace_dashes_with_underscore(const std::string& input)
{
- std::vector<SourceParagraph> output;
- for (auto it = fs::directory_iterator(paths.ports); it != fs::directory_iterator(); ++it)
- {
- const fs::path& path = it->path();
+ std::string output = input;
+ std::replace(output.begin(), output.end(), '-', '_');
+ return output;
+ }
- try
- {
- auto pghs = Paragraphs::get_paragraphs(path / "CONTROL");
- if (pghs.empty())
- {
- continue;
- }
+ static std::string create_graph_as_string(const std::vector<SourceParagraph>& source_paragraphs)
+ {
+ int empty_node_count = 0;
+
+ std::string s;
+ s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;");
- auto srcpgh = SourceParagraph(pghs[0]);
- output.push_back(srcpgh);
+ for (const SourceParagraph& source_paragraph : source_paragraphs)
+ {
+ if (source_paragraph.depends.empty())
+ {
+ empty_node_count++;
+ continue;
}
- catch (std::runtime_error const&)
+
+ const std::string name = replace_dashes_with_underscore(source_paragraph.name);
+ s.append(Strings::format("%s;", name));
+ for (const dependency& d : source_paragraph.depends)
{
+ const std::string dependency_name = replace_dashes_with_underscore(d.name);
+ s.append(Strings::format("%s -> %s;", name, dependency_name));
}
}
- return output;
+ s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count));
+ return s;
}
static void do_print(const SourceParagraph& source_paragraph)
@@ -40,14 +52,22 @@ namespace vcpkg
details::shorten_description(source_paragraph.description));
}
- void search_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
- static const std::string example = Strings::format("The argument should be a substring to search for, or no argument to display all libraries.\n%s", create_example_string("search png"));
+ static const std::string example = Strings::format("The argument should be a substring to search for, or no argument to display all libraries.\n%s",
+ Commands::Help::create_example_string("search png"));
args.check_max_arg_count(1, example);
+ const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({ OPTION_GRAPH });
- const std::vector<SourceParagraph> source_paragraphs = read_all_source_paragraphs(paths);
+ const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.ports);
+ if (options.find(OPTION_GRAPH) != options.cend())
+ {
+ const std::string graph_as_string = create_graph_as_string(source_paragraphs);
+ System::println(graph_as_string);
+ exit(EXIT_SUCCESS);
+ }
- if (args.command_arguments.size() == 0)
+ if (args.command_arguments.empty())
{
for (const SourceParagraph& source_paragraph : source_paragraphs)
{
diff --git a/toolsrc/src/commands_update.cpp b/toolsrc/src/commands_update.cpp
index a4ab7c6e7..8131d9a73 100644
--- a/toolsrc/src/commands_update.cpp
+++ b/toolsrc/src/commands_update.cpp
@@ -1,38 +1,22 @@
+#include "pch.h"
#include "vcpkg_Commands.h"
-#include "vcpkg.h"
+#include "vcpkglib.h"
#include "vcpkg_System.h"
#include "vcpkg_Files.h"
#include "Paragraphs.h"
-#include "vcpkg_info.h"
-namespace vcpkg
+namespace vcpkg::Commands::Update
{
- void update_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
+ void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths)
{
args.check_exact_arg_count(0);
+ args.check_and_get_optional_command_arguments({});
System::println("Using local portfile versions. To update the local portfiles, use `git pull`.");
auto status_db = database_load_check(paths);
- std::unordered_map<std::string, std::string> src_names_to_versions;
-
- auto begin_it = fs::directory_iterator(paths.ports);
- auto end_it = fs::directory_iterator();
- for (; begin_it != end_it; ++begin_it)
- {
- const auto& path = begin_it->path();
- try
- {
- auto pghs = Paragraphs::get_paragraphs(path / "CONTROL");
- if (pghs.empty())
- continue;
- auto srcpgh = SourceParagraph(pghs[0]);
- src_names_to_versions.emplace(srcpgh.name, srcpgh.version);
- }
- catch (std::runtime_error const&)
- {
- }
- }
+ const std::vector<SourceParagraph> source_paragraphs = Paragraphs::load_all_ports(paths.ports);
+ const std::map<std::string, std::string> src_names_to_versions = Paragraphs::extract_port_names_and_versions(source_paragraphs);
std::string packages_list;
@@ -78,13 +62,13 @@ namespace vcpkg
auto num1 = sscanf_s(version_contents->c_str(), "\"%d.%d.%d\"", &maj1, &min1, &rev1);
int maj2, min2, rev2;
- auto num2 = sscanf_s(Info::version().c_str(), "%d.%d.%d-", &maj2, &min2, &rev2);
+ auto num2 = sscanf_s(Version::version().c_str(), "%d.%d.%d-", &maj2, &min2, &rev2);
if (num1 == 3 && num2 == 3)
{
if (maj1 != maj2 || min1 != min2 || rev1 != rev2)
{
- System::println("Different source is available for vcpkg (%d.%d.%d -> %d.%d.%d). Use scripts\\bootstrap.ps1 to update.",
+ System::println("Different source is available for vcpkg (%d.%d.%d -> %d.%d.%d). Use powershell -exec bypass scripts/bootstrap.ps1 to update.",
maj2, min2, rev2,
maj1, min1, rev1);
}
diff --git a/toolsrc/src/commands_version.cpp b/toolsrc/src/commands_version.cpp
new file mode 100644
index 000000000..4789e2409
--- /dev/null
+++ b/toolsrc/src/commands_version.cpp
@@ -0,0 +1,37 @@
+#include "pch.h"
+#include "vcpkg_Commands.h"
+#include "vcpkg_System.h"
+#include "metrics.h"
+
+#define STRINGIFY(...) #__VA_ARGS__
+#define MACRO_TO_STRING(X) STRINGIFY(X)
+
+#define VCPKG_VERSION_AS_STRING MACRO_TO_STRING(VCPKG_VERSION)
+
+namespace vcpkg::Commands::Version
+{
+ const std::string& version()
+ {
+ static const std::string s_version =
+#include "../VERSION.txt"
+
+ + std::string(VCPKG_VERSION_AS_STRING)
+#ifndef NDEBUG
+ + std::string("-debug")
+#endif
+ + std::string(GetCompiledMetricsEnabled() ? "" : "-external");
+ return s_version;
+ }
+
+ void perform_and_exit(const vcpkg_cmd_arguments& args)
+ {
+ args.check_exact_arg_count(0);
+ args.check_and_get_optional_command_arguments({});
+
+ System::println("Vcpkg package management program version %s\n"
+ "\n"
+ "See LICENSE.txt for license information.", version()
+ );
+ exit(EXIT_SUCCESS);
+ }
+}
diff --git a/toolsrc/src/main.cpp b/toolsrc/src/main.cpp
deleted file mode 100644
index 7703c541f..000000000
--- a/toolsrc/src/main.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
-
-#include <iostream>
-#include <fstream>
-#include <memory>
-#include <cassert>
-#include "vcpkg_Commands.h"
-#include "metrics.h"
-#include <Shlobj.h>
-#include "vcpkg_Files.h"
-#include "vcpkg_System.h"
-#include "vcpkg_Input.h"
-#include "Paragraphs.h"
-#include "vcpkg_info.h"
-
-using namespace vcpkg;
-
-bool g_debugging = false;
-
-void invalid_command(const std::string& cmd)
-{
- System::println(System::color::error, "invalid command: %s", cmd);
- print_usage();
- exit(EXIT_FAILURE);
-}
-
-static void inner(const vcpkg_cmd_arguments& args)
-{
- TrackProperty("command", args.command);
- if (args.command.empty())
- {
- print_usage();
- exit(EXIT_FAILURE);
- }
-
- if (auto command_function = find_command(args.command, get_available_commands_type_c()))
- {
- return command_function(args);
- }
-
- fs::path vcpkg_root_dir;
- if (args.vcpkg_root_dir != nullptr)
- {
- vcpkg_root_dir = fs::absolute(Strings::utf8_to_utf16(*args.vcpkg_root_dir));
- }
- else
- {
- auto vcpkg_root_dir_env = System::wdupenv_str(L"VCPKG_ROOT");
-
- if (!vcpkg_root_dir_env.empty())
- {
- vcpkg_root_dir = fs::absolute(vcpkg_root_dir_env);
- }
- else
- {
- vcpkg_root_dir = Files::find_file_recursively_up(fs::absolute(System::get_exe_path_of_current_process()), ".vcpkg-root");
- }
- }
-
- Checks::check_exit(!vcpkg_root_dir.empty(), "Error: Could not detect vcpkg-root.");
-
- const expected<vcpkg_paths> expected_paths = vcpkg_paths::create(vcpkg_root_dir);
- Checks::check_exit(!expected_paths.error_code(), "Error: Invalid vcpkg root directory %s: %s", vcpkg_root_dir.string(), expected_paths.error_code().message());
- const vcpkg_paths paths = expected_paths.get_or_throw();
- int exit_code = _wchdir(paths.root.c_str());
- Checks::check_exit(exit_code == 0, "Changing the working dir failed");
-
- if (auto command_function = find_command(args.command, get_available_commands_type_b()))
- {
- return command_function(args, paths);
- }
-
- triplet default_target_triplet;
- if (args.target_triplet != nullptr)
- {
- default_target_triplet = triplet::from_canonical_name(*args.target_triplet);
- }
- else
- {
- const auto vcpkg_default_triplet_env = System::wdupenv_str(L"VCPKG_DEFAULT_TRIPLET");
- if (!vcpkg_default_triplet_env.empty())
- {
- default_target_triplet = triplet::from_canonical_name(Strings::utf16_to_utf8(vcpkg_default_triplet_env));
- }
- else
- {
- default_target_triplet = triplet::X86_WINDOWS;
- }
- }
-
- Input::check_triplet(default_target_triplet, paths);
-
- if (auto command_function = find_command(args.command, get_available_commands_type_a()))
- {
- return command_function(args, paths, default_target_triplet);
- }
-
- return invalid_command(args.command);
-}
-
-static void loadConfig()
-{
- fs::path localappdata;
- {
- // Config path in AppDataLocal
- wchar_t* localappdatapath = nullptr;
- if (S_OK != SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localappdatapath))
- __fastfail(1);
- localappdata = localappdatapath;
- CoTaskMemFree(localappdatapath);
- }
-
- try
- {
- std::string config_contents = Files::read_contents(localappdata / "vcpkg" / "config").get_or_throw();
-
- std::unordered_map<std::string, std::string> keys;
- auto pghs = Paragraphs::parse_paragraphs(config_contents);
- if (pghs.size() > 0)
- keys = pghs[0];
-
- for (size_t x = 1; x < pghs.size(); ++x)
- {
- for (auto&& p : pghs[x])
- keys.insert(p);
- }
-
- auto user_id = keys["User-Id"];
- auto user_time = keys["User-Since"];
- Checks::check_throw(!user_id.empty() && !user_time.empty(), ""); // Use as goto to the catch statement
-
- SetUserInformation(user_id, user_time);
- return;
- }
- catch (...)
- {
- }
-
- // config file not found, could not be read, or invalid
- std::string user_id, user_time;
- InitUserInformation(user_id, user_time);
- SetUserInformation(user_id, user_time);
- try
- {
- std::error_code ec;
- fs::create_directory(localappdata / "vcpkg", ec);
- std::ofstream(localappdata / "vcpkg" / "config", std::ios_base::out | std::ios_base::trunc)
- << "User-Id: " << user_id << "\n"
- << "User-Since: " << user_time << "\n";
- }
- catch (...)
- {
- }
-}
-
-static System::Stopwatch2 g_timer;
-
-static std::string trim_path_from_command_line(const std::string& full_command_line)
-{
- Checks::check_exit(full_command_line.size() > 0, "Internal failure - cannot have empty command line");
-
- if (full_command_line[0] == '"')
- {
- auto it = std::find(full_command_line.cbegin() + 1, full_command_line.cend(), '"');
- if (it != full_command_line.cend()) // Skip over the quote
- ++it;
- while (it != full_command_line.cend() && *it == ' ') // Skip over a space
- ++it;
- return std::string(it, full_command_line.cend());
- }
-
- auto it = std::find(full_command_line.cbegin(), full_command_line.cend(), ' ');
- while (it != full_command_line.cend() && *it == ' ')
- ++it;
- return std::string(it, full_command_line.cend());
-}
-
-int wmain(const int argc, const wchar_t* const* const argv)
-{
- if (argc == 0)
- std::abort();
-
- std::cout.sync_with_stdio(false);
- std::cout.imbue(std::locale::classic());
-
- g_timer.start();
- atexit([]()
- {
- g_timer.stop();
- TrackMetric("elapsed_us", g_timer.microseconds());
- Flush();
- });
-
- TrackProperty("version", Info::version());
-
- const std::string trimmed_command_line = trim_path_from_command_line(Strings::utf16_to_utf8(GetCommandLineW()));
- TrackProperty("cmdline", trimmed_command_line);
- loadConfig();
- TrackProperty("sqmuser", GetSQMUser());
-
- const vcpkg_cmd_arguments args = vcpkg_cmd_arguments::create_from_command_line(argc, argv);
-
- if (args.printmetrics != opt_bool::unspecified)
- SetPrintMetrics(args.printmetrics == opt_bool::enabled);
- if (args.sendmetrics != opt_bool::unspecified)
- SetSendMetrics(args.sendmetrics == opt_bool::enabled);
-
- if (args.debug != opt_bool::unspecified)
- {
- g_debugging = (args.debug == opt_bool::enabled);
- }
-
- if (g_debugging)
- {
- inner(args);
- exit(EXIT_FAILURE);
- }
-
- std::string exc_msg;
- try
- {
- inner(args);
- exit(EXIT_FAILURE);
- }
- catch (std::exception& e)
- {
- exc_msg = e.what();
- }
- catch (...)
- {
- exc_msg = "unknown error(...)";
- }
- TrackProperty("error", exc_msg);
- std::cerr
- << "vcpkg.exe has crashed.\n"
- << "Please send an email to:\n"
- << " " << Info::email() << "\n"
- << "containing a brief summary of what you were trying to do and the following data blob:\n"
- << "\n"
- << "Version=" << Info::version() << "\n"
- << "EXCEPTION='" << exc_msg << "'\n"
- << "CMD=\n";
- for (int x = 0; x < argc; ++x)
- std::cerr << argv[x] << "|\n";
- std::cerr
- << "\n";
-}
diff --git a/toolsrc/src/metrics.cpp b/toolsrc/src/metrics.cpp
index 51c7179c8..d0e20fe2d 100644
--- a/toolsrc/src/metrics.cpp
+++ b/toolsrc/src/metrics.cpp
@@ -1,15 +1,5 @@
+#include "pch.h"
#include "metrics.h"
-#include <utility>
-#include <array>
-#include <string>
-#include <iostream>
-#include <vector>
-#include <sys/timeb.h>
-#include <time.h>
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
-#include <winhttp.h>
-#include <fstream>
#include "filesystem_fs.h"
#include "vcpkg_Strings.h"
#include "vcpkg_System.h"
@@ -42,7 +32,7 @@ namespace vcpkg
static std::string GenerateRandomUUID()
{
- int partSizes[] = {8, 4, 4, 4, 12};
+ int partSizes[] = { 8, 4, 4, 4, 12 };
char uuid[37];
memset(uuid, 0, sizeof(uuid));
int num;
@@ -111,7 +101,7 @@ namespace vcpkg
// Note: this treats incoming Strings as Latin-1
static constexpr const char hex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
encoded.append("\\u00");
encoded.push_back(hex[ch / 16]);
encoded.push_back(hex[ch % 16]);
@@ -237,36 +227,12 @@ true
std::wstring GetSQMUser()
{
- LONG err = NULL;
+ auto hkcu_sqmclient = System::get_registry_string(HKEY_CURRENT_USER, LR"(Software\Microsoft\SQMClient)", L"UserId");
- struct RAII_HKEY {
- HKEY hkey = NULL;
- ~RAII_HKEY()
- {
- if (hkey != NULL)
- RegCloseKey(hkey);
- }
- } HKCU_SQMClient;
-
- err = RegOpenKeyExW(HKEY_CURRENT_USER, LR"(Software\Microsoft\SQMClient)", NULL, KEY_READ, &HKCU_SQMClient.hkey);
- if (err != ERROR_SUCCESS)
- {
+ if (hkcu_sqmclient)
+ return std::move(*hkcu_sqmclient);
+ else
return L"{}";
- }
-
- std::array<wchar_t,128> buffer;
- DWORD lType = 0;
- DWORD dwBufferSize = static_cast<DWORD>(buffer.size() * sizeof(wchar_t));
- err = RegQueryValueExW(HKCU_SQMClient.hkey, L"UserId", NULL, &lType, reinterpret_cast<LPBYTE>(buffer.data()), &dwBufferSize);
- if (err == ERROR_SUCCESS && lType == REG_SZ && dwBufferSize >= sizeof(wchar_t))
- {
- size_t sz = dwBufferSize / sizeof(wchar_t);
- if (buffer[sz - 1] == '\0')
- --sz;
- return std::wstring(buffer.begin(), buffer.begin() + sz);
- }
-
- return L"{}";
}
void SetUserInformation(const std::string& user_id, const std::string& first_use_time)
@@ -366,8 +332,7 @@ true
if (bResults)
{
DWORD availableData = 0, readData = 0, totalData = 0;
-
- while ((bResults = WinHttpQueryDataAvailable(hRequest, &availableData)) && availableData > 0)
+ while ((bResults = WinHttpQueryDataAvailable(hRequest, &availableData)) == TRUE && availableData > 0)
{
responseBuffer.resize(responseBuffer.size() + availableData);
@@ -452,6 +417,6 @@ true
std::ofstream(vcpkg_metrics_txt_path) << payload;
const std::wstring cmdLine = Strings::wformat(L"start %s %s", temp_folder_path_exe.native(), vcpkg_metrics_txt_path.native());
- System::cmd_execute(cmdLine);
+ System::cmd_execute_clean(cmdLine);
}
}
diff --git a/toolsrc/src/opt_bool.cpp b/toolsrc/src/opt_bool.cpp
new file mode 100644
index 000000000..324936fb4
--- /dev/null
+++ b/toolsrc/src/opt_bool.cpp
@@ -0,0 +1,29 @@
+#include "pch.h"
+#include "opt_bool.h"
+#include "vcpkg_Checks.h"
+
+namespace vcpkg::opt_bool
+{
+ static const std::string UNSPECIFIED_NAME = "unspecified";
+ static const std::string ENABLED_NAME = "enabled";
+ static const std::string DISABLED_NAME = "disabled";
+ type parse(const std::string& s)
+ {
+ if (s == UNSPECIFIED_NAME)
+ {
+ return opt_bool_t::UNSPECIFIED;
+ }
+
+ if (s == ENABLED_NAME)
+ {
+ return opt_bool_t::ENABLED;
+ }
+
+ if (s == DISABLED_NAME)
+ {
+ return opt_bool_t::DISABLED;
+ }
+
+ Checks::exit_with_message("Could not convert string [%s] to opt_bool", s);
+ }
+}
diff --git a/toolsrc/src/package_spec.cpp b/toolsrc/src/package_spec.cpp
index 86d4393bd..2713e219f 100644
--- a/toolsrc/src/package_spec.cpp
+++ b/toolsrc/src/package_spec.cpp
@@ -1,5 +1,5 @@
+#include "pch.h"
#include "package_spec.h"
-#include <algorithm>
namespace vcpkg
{
@@ -50,19 +50,24 @@ namespace vcpkg
return this->m_target_triplet;
}
+ std::string package_spec::display_name() const
+ {
+ return Strings::format("%s:%s", this->name(), this->target_triplet());
+ }
+
std::string package_spec::dir() const
{
return Strings::format("%s_%s", this->m_name, this->m_target_triplet);
}
- std::string to_string(const package_spec& spec)
+ std::string package_spec::toString() const
{
- return Strings::format("%s:%s", spec.name(), spec.target_triplet());
+ return this->display_name();
}
std::string to_printf_arg(const package_spec& spec)
{
- return to_string(spec);
+ return spec.toString();
}
bool operator==(const package_spec& left, const package_spec& right)
@@ -72,6 +77,6 @@ namespace vcpkg
std::ostream& operator<<(std::ostream& os, const package_spec& spec)
{
- return os << to_string(spec);
+ return os << spec.toString();
}
}
diff --git a/toolsrc/src/package_spec_parse_result.cpp b/toolsrc/src/package_spec_parse_result.cpp
index dc377f656..892232c2e 100644
--- a/toolsrc/src/package_spec_parse_result.cpp
+++ b/toolsrc/src/package_spec_parse_result.cpp
@@ -1,5 +1,5 @@
-#include <package_spec.h>
-#include <system_error>
+#include "pch.h"
+#include "package_spec.h"
#include "package_spec_parse_result.h"
namespace vcpkg
diff --git a/toolsrc/src/pch.cpp b/toolsrc/src/pch.cpp
new file mode 100644
index 000000000..17305716a
--- /dev/null
+++ b/toolsrc/src/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h" \ No newline at end of file
diff --git a/toolsrc/src/tests_paragraph.cpp b/toolsrc/src/tests_paragraph.cpp
index 6d9e46fcf..fb20eee82 100644
--- a/toolsrc/src/tests_paragraph.cpp
+++ b/toolsrc/src/tests_paragraph.cpp
@@ -7,14 +7,14 @@
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
-namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework
+namespace Microsoft::VisualStudio::CppUnitTestFramework
{
template <>
inline std::wstring ToString<vcpkg::package_spec_parse_result>(const vcpkg::package_spec_parse_result& t)
{
return ToString(static_cast<uint32_t>(t));
}
-}}}
+}
namespace UnitTest1
{
diff --git a/toolsrc/src/triplet.cpp b/toolsrc/src/triplet.cpp
index a6816b445..d91e0e68f 100644
--- a/toolsrc/src/triplet.cpp
+++ b/toolsrc/src/triplet.cpp
@@ -1,6 +1,7 @@
+#include "pch.h"
#include "triplet.h"
#include "vcpkg_Checks.h"
-#include <algorithm>
+#include "vcpkg_Strings.h"
namespace vcpkg
{
@@ -37,9 +38,7 @@ namespace vcpkg
triplet triplet::from_canonical_name(const std::string& triplet_as_string)
{
- std::string s(triplet_as_string);
- std::transform(s.begin(), s.end(), s.begin(), ::tolower);
-
+ const std::string s(Strings::ascii_to_lowercase(triplet_as_string));
auto it = std::find(s.cbegin(), s.cend(), '-');
Checks::check_exit(it != s.cend(), "Invalid triplet: %s", triplet_as_string);
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp
index 4748aeb54..e94d2538b 100644
--- a/toolsrc/src/vcpkg.cpp
+++ b/toolsrc/src/vcpkg.cpp
@@ -1,248 +1,250 @@
-#include "vcpkg.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
#include <iostream>
-#include <iomanip>
#include <fstream>
-#include <functional>
-#include <string>
-#include <unordered_map>
#include <memory>
-#include <vector>
+#include <cassert>
+#include "vcpkg_Commands.h"
+#include "metrics.h"
+#include <Shlobj.h>
#include "vcpkg_Files.h"
+#include "vcpkg_System.h"
+#include "vcpkg_Input.h"
#include "Paragraphs.h"
-#include <regex>
-#include "metrics.h"
+#include "vcpkg_Strings.h"
+#include "vcpkg_Chrono.h"
using namespace vcpkg;
-static StatusParagraphs load_current_database(const fs::path& vcpkg_dir_status_file, const fs::path& vcpkg_dir_status_file_old)
+bool g_debugging = false;
+
+void invalid_command(const std::string& cmd)
{
- if (!fs::exists(vcpkg_dir_status_file))
- {
- if (!fs::exists(vcpkg_dir_status_file_old))
- {
- // no status file, use empty db
- return StatusParagraphs();
- }
+ System::println(System::color::error, "invalid command: %s", cmd);
+ Commands::Help::print_usage();
+ exit(EXIT_FAILURE);
+}
- fs::rename(vcpkg_dir_status_file_old, vcpkg_dir_status_file);
+static void inner(const vcpkg_cmd_arguments& args)
+{
+ TrackProperty("command", args.command);
+ if (args.command.empty())
+ {
+ Commands::Help::print_usage();
+ exit(EXIT_FAILURE);
}
- auto text = Files::read_contents(vcpkg_dir_status_file).get_or_throw();
- auto pghs = Paragraphs::parse_paragraphs(text);
-
- std::vector<std::unique_ptr<StatusParagraph>> status_pghs;
- for (auto&& p : pghs)
+ if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_c()))
{
- status_pghs.push_back(std::make_unique<StatusParagraph>(p));
+ return command_function(args);
}
- return StatusParagraphs(std::move(status_pghs));
-}
-
-StatusParagraphs vcpkg::database_load_check(const vcpkg_paths& paths)
-{
- auto updates_dir = paths.vcpkg_dir_updates;
-
- std::error_code ec;
- fs::create_directory(paths.installed, ec);
- fs::create_directory(paths.vcpkg_dir, ec);
- fs::create_directory(paths.vcpkg_dir_info, ec);
- fs::create_directory(updates_dir, ec);
+ fs::path vcpkg_root_dir;
+ if (args.vcpkg_root_dir != nullptr)
+ {
+ vcpkg_root_dir = fs::absolute(Strings::utf8_to_utf16(*args.vcpkg_root_dir));
+ }
+ else
+ {
+ const optional<std::wstring> vcpkg_root_dir_env = System::get_environmental_variable(L"VCPKG_ROOT");
+ if (vcpkg_root_dir_env)
+ {
+ vcpkg_root_dir = fs::absolute(*vcpkg_root_dir_env);
+ }
+ else
+ {
+ vcpkg_root_dir = Files::find_file_recursively_up(fs::absolute(System::get_exe_path_of_current_process()), ".vcpkg-root");
+ }
+ }
- const fs::path& status_file = paths.vcpkg_dir_status_file;
- const fs::path status_file_old = status_file.parent_path() / "status-old";
- const fs::path status_file_new = status_file.parent_path() / "status-new";
+ Checks::check_exit(!vcpkg_root_dir.empty(), "Error: Could not detect vcpkg-root.");
- StatusParagraphs current_status_db = load_current_database(status_file, status_file_old);
+ const expected<vcpkg_paths> expected_paths = vcpkg_paths::create(vcpkg_root_dir);
+ Checks::check_exit(!expected_paths.error_code(), "Error: Invalid vcpkg root directory %s: %s", vcpkg_root_dir.string(), expected_paths.error_code().message());
+ const vcpkg_paths paths = expected_paths.get_or_throw();
+ int exit_code = _wchdir(paths.root.c_str());
+ Checks::check_exit(exit_code == 0, "Changing the working dir failed");
- auto b = fs::directory_iterator(updates_dir);
- auto e = fs::directory_iterator();
- if (b == e)
+ if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_b()))
{
- // updates directory is empty, control file is up-to-date.
- return current_status_db;
+ return command_function(args, paths);
}
- for (; b != e; ++b)
+ triplet default_target_triplet;
+ if (args.target_triplet != nullptr)
{
- if (!fs::is_regular_file(b->status()))
- continue;
- if (b->path().filename() == "incomplete")
- continue;
-
- auto text = Files::read_contents(b->path()).get_or_throw();
- auto pghs = Paragraphs::parse_paragraphs(text);
- for (auto&& p : pghs)
+ default_target_triplet = triplet::from_canonical_name(*args.target_triplet);
+ }
+ else
+ {
+ const optional<std::wstring> vcpkg_default_triplet_env = System::get_environmental_variable(L"VCPKG_DEFAULT_TRIPLET");
+ if (vcpkg_default_triplet_env)
{
- current_status_db.insert(std::make_unique<StatusParagraph>(p));
+ default_target_triplet = triplet::from_canonical_name(Strings::utf16_to_utf8(*vcpkg_default_triplet_env));
+ }
+ else
+ {
+ default_target_triplet = triplet::X86_WINDOWS;
}
}
- std::fstream(status_file_new, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc) << current_status_db;
-
- if (fs::exists(status_file_old))
- fs::remove(status_file_old);
- if (fs::exists(status_file))
- fs::rename(status_file, status_file_old);
- fs::rename(status_file_new, status_file);
- fs::remove(status_file_old);
+ Input::check_triplet(default_target_triplet, paths);
- b = fs::directory_iterator(updates_dir);
- for (; b != e; ++b)
+ if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_a()))
{
- if (!fs::is_regular_file(b->status()))
- continue;
- fs::remove(b->path());
+ return command_function(args, paths, default_target_triplet);
}
- return current_status_db;
-}
-
-void vcpkg::write_update(const vcpkg_paths& paths, const StatusParagraph& p)
-{
- static int update_id = 0;
- auto my_update_id = update_id++;
- auto tmp_update_filename = paths.vcpkg_dir_updates / "incomplete";
- auto update_filename = paths.vcpkg_dir_updates / std::to_string(my_update_id);
- std::fstream fs(tmp_update_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
- fs << p;
- fs.close();
- fs::rename(tmp_update_filename, update_filename);
+ return invalid_command(args.command);
}
-static void upgrade_to_slash_terminated_sorted_format(std::vector<std::string>* lines, const fs::path& listfile_path)
+static void loadConfig()
{
- static bool was_tracked = false;
+ fs::path localappdata;
+ {
+ // Config path in AppDataLocal
+ wchar_t* localappdatapath = nullptr;
+ if (S_OK != SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localappdatapath))
+ __fastfail(1);
+ localappdata = localappdatapath;
+ CoTaskMemFree(localappdatapath);
+ }
- if (lines->empty())
+ try
{
+ std::string config_contents = Files::read_contents(localappdata / "vcpkg" / "config").get_or_throw();
+
+ std::unordered_map<std::string, std::string> keys;
+ auto pghs = Paragraphs::parse_paragraphs(config_contents);
+ if (pghs.size() > 0)
+ keys = pghs[0];
+
+ for (size_t x = 1; x < pghs.size(); ++x)
+ {
+ for (auto&& p : pghs[x])
+ keys.insert(p);
+ }
+
+ auto user_id = keys["User-Id"];
+ auto user_time = keys["User-Since"];
+ Checks::check_throw(!user_id.empty() && !user_time.empty(), ""); // Use as goto to the catch statement
+
+ SetUserInformation(user_id, user_time);
return;
}
-
- if (lines->at(0).back() == '/')
+ catch (...)
{
- return; // File already in the new format
}
- if (!was_tracked)
+ // config file not found, could not be read, or invalid
+ std::string user_id, user_time;
+ InitUserInformation(user_id, user_time);
+ SetUserInformation(user_id, user_time);
+ try
{
- was_tracked = true;
- TrackProperty("listfile", "update to new format");
+ std::error_code ec;
+ fs::create_directory(localappdata / "vcpkg", ec);
+ std::ofstream(localappdata / "vcpkg" / "config", std::ios_base::out | std::ios_base::trunc)
+ << "User-Id: " << user_id << "\n"
+ << "User-Since: " << user_time << "\n";
}
-
- // The files are sorted such that directories are placed just before the files they contain
- // (They are not necessarily sorted alphabetically, e.g. libflac)
- // Therefore we can detect the entries that represent directories by comparing every element with the next one
- // and checking if the next has a slash immediately after the current one's length
- for (size_t i = 0; i < lines->size() - 1; i++)
+ catch (...)
{
- std::string& current_string = lines->at(i);
- const std::string& next_string = lines->at(i + 1);
+ }
+}
- const size_t potential_slash_char_index = current_string.length();
- // Make sure the index exists first
- if (next_string.size() > potential_slash_char_index && next_string.at(potential_slash_char_index) == '/')
- {
- current_string += '/'; // Mark as a directory
- }
+static std::string trim_path_from_command_line(const std::string& full_command_line)
+{
+ Checks::check_exit(full_command_line.size() > 0, "Internal failure - cannot have empty command line");
+
+ if (full_command_line[0] == '"')
+ {
+ auto it = std::find(full_command_line.cbegin() + 1, full_command_line.cend(), '"');
+ if (it != full_command_line.cend()) // Skip over the quote
+ ++it;
+ while (it != full_command_line.cend() && *it == ' ') // Skip over a space
+ ++it;
+ return std::string(it, full_command_line.cend());
}
- // After suffixing the directories with a slash, we can now sort.
- // We cannot sort before adding the suffixes because the following (actual example):
- /*
- x86-windows/include/FLAC <<<<<< This would be separated from its group due to sorting
- x86-windows/include/FLAC/all.h
- x86-windows/include/FLAC/assert.h
- x86-windows/include/FLAC/callback.h
- x86-windows/include/FLAC++
- x86-windows/include/FLAC++/all.h
- x86-windows/include/FLAC++/decoder.h
- x86-windows/include/FLAC++/encoder.h
- *
- x86-windows/include/FLAC/ <<<<<< This will now be kept with its group when sorting
- x86-windows/include/FLAC/all.h
- x86-windows/include/FLAC/assert.h
- x86-windows/include/FLAC/callback.h
- x86-windows/include/FLAC++/
- x86-windows/include/FLAC++/all.h
- x86-windows/include/FLAC++/decoder.h
- x86-windows/include/FLAC++/encoder.h
- */
- // Note that after sorting, the FLAC++/ group will be placed before the FLAC/ group
- // The new format is lexicographically sorted
- std::sort(lines->begin(), lines->end());
-
-#if 0
- // Replace the listfile on disk
- const fs::path updated_listfile_path = listfile_path.generic_string() + "_updated";
- Files::write_all_lines(updated_listfile_path, *lines);
- fs::rename(updated_listfile_path, listfile_path);
-#endif
+ auto it = std::find(full_command_line.cbegin(), full_command_line.cend(), ' ');
+ while (it != full_command_line.cend() && *it == ' ')
+ ++it;
+ return std::string(it, full_command_line.cend());
}
-std::vector<StatusParagraph_and_associated_files> vcpkg::get_installed_files(const vcpkg_paths& paths, const StatusParagraphs& status_db)
+static ElapsedTime g_timer;
+
+int wmain(const int argc, const wchar_t* const* const argv)
{
- std::vector<StatusParagraph_and_associated_files> installed_files;
+ if (argc == 0)
+ std::abort();
- for (const std::unique_ptr<StatusParagraph>& pgh : status_db)
- {
- if (pgh->state != install_state_t::installed)
+ g_timer = ElapsedTime::createStarted();
+ atexit([]()
{
- continue;
- }
+ auto elapsed_us = g_timer.microseconds();
+ TrackMetric("elapsed_us", elapsed_us);
+ Flush();
+ });
+
+ TrackProperty("version", Commands::Version::version());
+
+ const std::string trimmed_command_line = trim_path_from_command_line(Strings::utf16_to_utf8(GetCommandLineW()));
+ TrackProperty("cmdline", trimmed_command_line);
+ loadConfig();
+ TrackProperty("sqmuser", GetSQMUser());
- const fs::path listfile_path = paths.listfile_path(pgh->package);
- std::vector<std::string> installed_files_of_current_pgh = Files::read_all_lines(listfile_path).get_or_throw();
- Strings::trim_all_and_remove_whitespace_strings(&installed_files_of_current_pgh);
- upgrade_to_slash_terminated_sorted_format(&installed_files_of_current_pgh, listfile_path);
+ const vcpkg_cmd_arguments args = vcpkg_cmd_arguments::create_from_command_line(argc, argv);
- // Remove the directories
- installed_files_of_current_pgh.erase(
- std::remove_if(installed_files_of_current_pgh.begin(), installed_files_of_current_pgh.end(), [](const std::string& file) -> bool
- {
- return file.back() == '/';
- }
- ), installed_files_of_current_pgh.end());
+ if (args.printmetrics != opt_bool_t::UNSPECIFIED)
+ SetPrintMetrics(args.printmetrics == opt_bool_t::ENABLED);
+ if (args.sendmetrics != opt_bool_t::UNSPECIFIED)
+ SetSendMetrics(args.sendmetrics == opt_bool_t::ENABLED);
- StatusParagraph_and_associated_files pgh_and_files = {*pgh, std::move(installed_files_of_current_pgh)};
- installed_files.push_back(std::move(pgh_and_files));
+ if (args.debug != opt_bool_t::UNSPECIFIED)
+ {
+ g_debugging = (args.debug == opt_bool_t::ENABLED);
}
- return installed_files;
-}
+ if (g_debugging)
+ {
+ inner(args);
+ exit(EXIT_FAILURE);
+ }
-expected<SourceParagraph> vcpkg::try_load_port(const fs::path& path)
-{
+ std::string exc_msg;
try
{
- auto pghs = Paragraphs::get_paragraphs(path / "CONTROL");
- Checks::check_exit(pghs.size() == 1, "Invalid control file at %s\\CONTROL", path.string());
- return SourceParagraph(pghs[0]);
+ inner(args);
+ exit(EXIT_FAILURE);
}
- catch (std::runtime_error const&)
+ catch (std::exception& e)
{
+ exc_msg = e.what();
}
-
- return std::errc::no_such_file_or_directory;
-}
-
-expected<BinaryParagraph> vcpkg::try_load_cached_package(const vcpkg_paths& paths, const package_spec& spec)
-{
- const fs::path path = paths.package_dir(spec) / "CONTROL";
-
- auto control_contents_maybe = Files::read_contents(path);
- if (auto control_contents = control_contents_maybe.get())
+ catch (...)
{
- std::vector<std::unordered_map<std::string, std::string>> pghs;
- try
- {
- pghs = Paragraphs::parse_paragraphs(*control_contents);
- }
- catch (std::runtime_error)
- {
- }
- Checks::check_exit(pghs.size() == 1, "Invalid control file at %s", path.string());
- return BinaryParagraph(pghs[0]);
+ exc_msg = "unknown error(...)";
}
- return control_contents_maybe.error_code();
+ TrackProperty("error", exc_msg);
+
+ fflush(stdout);
+ System::print(
+ "vcpkg.exe has crashed.\n"
+ "Please send an email to:\n"
+ " %s\n"
+ "containing a brief summary of what you were trying to do and the following data blob:\n"
+ "\n"
+ "Version=%s\n"
+ "EXCEPTION='%s'\n"
+ "CMD=\n",
+ Commands::Contact::email(),
+ Commands::Version::version(),
+ exc_msg);
+ fflush(stdout);
+ for (int x = 0; x < argc; ++x)
+ System::println("%s|", Strings::utf16_to_utf8(argv[x]));
+ fflush(stdout);
}
diff --git a/toolsrc/src/vcpkg_Checks.cpp b/toolsrc/src/vcpkg_Checks.cpp
index 817ac9e96..02d3480a2 100644
--- a/toolsrc/src/vcpkg_Checks.cpp
+++ b/toolsrc/src/vcpkg_Checks.cpp
@@ -1,11 +1,10 @@
+#include "pch.h"
#include "vcpkg_Checks.h"
-
-#include <stdexcept>
#include "vcpkg_System.h"
-namespace vcpkg {namespace Checks
+namespace vcpkg::Checks
{
- void unreachable()
+ __declspec(noreturn) void unreachable()
{
System::println(System::color::error, "Error: Unreachable code was reached");
#ifndef NDEBUG
@@ -15,13 +14,13 @@ namespace vcpkg {namespace Checks
#endif
}
- void exit_with_message(const char* errorMessage)
+ __declspec(noreturn) void exit_with_message(const char* errorMessage)
{
System::println(System::color::error, errorMessage);
exit(EXIT_FAILURE);
}
- void throw_with_message(const char* errorMessage)
+ __declspec(noreturn) void throw_with_message(const char* errorMessage)
{
throw std::runtime_error(errorMessage);
}
@@ -34,6 +33,14 @@ namespace vcpkg {namespace Checks
}
}
+ void check_exit(bool expression)
+ {
+ if (!expression)
+ {
+ exit(EXIT_FAILURE);
+ }
+ }
+
void check_exit(bool expression, const char* errorMessage)
{
if (!expression)
@@ -41,4 +48,4 @@ namespace vcpkg {namespace Checks
exit_with_message(errorMessage);
}
}
-}}
+}
diff --git a/toolsrc/src/Stopwatch.cpp b/toolsrc/src/vcpkg_Chrono.cpp
index 550f1ebd8..e39842df9 100644
--- a/toolsrc/src/Stopwatch.cpp
+++ b/toolsrc/src/vcpkg_Chrono.cpp
@@ -1,48 +1,10 @@
-#include "Stopwatch.h"
+#include "pch.h"
+#include "vcpkg_Chrono.h"
#include "vcpkg_Checks.h"
namespace vcpkg
{
- Stopwatch Stopwatch::createUnstarted()
- {
- return Stopwatch();
- }
-
- Stopwatch Stopwatch::createStarted()
- {
- return Stopwatch().start();
- }
-
- bool Stopwatch::isRunning() const
- {
- return this->m_isRunning;
- }
-
- const Stopwatch& Stopwatch::start()
- {
- Checks::check_exit(!this->m_isRunning, "This stopwatch is already running.");
- this->m_isRunning = true;
- this->m_startTick = std::chrono::high_resolution_clock::now();
- return *this;
- }
-
- const Stopwatch& Stopwatch::stop()
- {
- auto tick = std::chrono::high_resolution_clock::now();
- Checks::check_exit(this->m_isRunning, "This stopwatch is already stopped.");
- this->m_isRunning = false;
- this->m_elapsedNanos += tick - this->m_startTick;
- return *this;
- }
-
- Stopwatch& Stopwatch::reset()
- {
- this->m_elapsedNanos = std::chrono::nanoseconds();
- this->m_isRunning = false;
- return *this;
- }
-
- std::string Stopwatch::toString() const
+ static std::string format_time_userfriendly(const std::chrono::nanoseconds& nanos)
{
using std::chrono::hours;
using std::chrono::minutes;
@@ -52,8 +14,7 @@ namespace vcpkg
using std::chrono::nanoseconds;
using std::chrono::duration_cast;
- auto nanos = elapsedNanos();
- auto nanos_as_double = static_cast<double>(nanos.count());
+ const double nanos_as_double = static_cast<double>(nanos.count());
if (duration_cast<hours>(nanos) > hours())
{
@@ -88,17 +49,15 @@ namespace vcpkg
return Strings::format("%.4g ns", nanos_as_double);
}
- Stopwatch::Stopwatch() : m_isRunning(false), m_elapsedNanos(), m_startTick()
+ ElapsedTime ElapsedTime::createStarted()
{
+ ElapsedTime t;
+ t.m_startTick = std::chrono::high_resolution_clock::now();
+ return t;
}
- std::chrono::nanoseconds Stopwatch::elapsedNanos() const
+ std::string ElapsedTime::toString() const
{
- if (this->m_isRunning)
- {
- return std::chrono::high_resolution_clock::now() - this->m_startTick + this->m_elapsedNanos;
- }
-
- return this->m_elapsedNanos;
+ return format_time_userfriendly(elapsed<std::chrono::nanoseconds>());
}
}
diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp
index ae7f697fa..e8bf10617 100644
--- a/toolsrc/src/vcpkg_Dependencies.cpp
+++ b/toolsrc/src/vcpkg_Dependencies.cpp
@@ -1,16 +1,40 @@
+#include "pch.h"
#include "vcpkg_Dependencies.h"
-#include <vector>
#include "vcpkg_Graphs.h"
#include "vcpkg_paths.h"
#include "package_spec.h"
#include "StatusParagraphs.h"
-#include <unordered_set>
-#include "vcpkg_Maps.h"
#include "vcpkg_Files.h"
-#include "vcpkg.h"
+#include "Paragraphs.h"
-namespace vcpkg { namespace Dependencies
+namespace vcpkg::Dependencies
{
+ install_plan_action::install_plan_action() : plan_type(install_plan_type::UNKNOWN), binary_pgh(nullptr), source_pgh(nullptr)
+ {
+ }
+
+ install_plan_action::install_plan_action(const install_plan_type& plan_type, optional<BinaryParagraph> binary_pgh, optional<SourceParagraph> source_pgh)
+ : plan_type(std::move(plan_type)), binary_pgh(std::move(binary_pgh)), source_pgh(std::move(source_pgh))
+ {
+ }
+
+ package_spec_with_install_plan::package_spec_with_install_plan(const package_spec& spec, install_plan_action&& plan) : spec(spec), plan(std::move(plan))
+ {
+ }
+
+ remove_plan_action::remove_plan_action() : plan_type(remove_plan_type::UNKNOWN), request_type(request_type::UNKNOWN)
+ {
+ }
+
+ remove_plan_action::remove_plan_action(const remove_plan_type& plan_type, const Dependencies::request_type& request_type) : plan_type(plan_type), request_type(request_type)
+ {
+ }
+
+ package_spec_with_remove_plan::package_spec_with_remove_plan(const package_spec& spec, remove_plan_action&& plan)
+ : spec(spec), plan(std::move(plan))
+ {
+ }
+
std::vector<package_spec_with_install_plan> create_install_plan(const vcpkg_paths& paths, const std::vector<package_spec>& specs, const StatusParagraphs& status_db)
{
std::unordered_map<package_spec, install_plan_action> was_examined; // Examine = we have checked its immediate (non-recursive) dependencies
@@ -48,7 +72,7 @@ namespace vcpkg { namespace Dependencies
continue;
}
- expected<BinaryParagraph> maybe_bpgh = try_load_cached_package(paths, spec);
+ expected<BinaryParagraph> maybe_bpgh = Paragraphs::try_load_cached_package(paths, spec);
if (BinaryParagraph* bpgh = maybe_bpgh.get())
{
process_dependencies(bpgh->depends);
@@ -56,7 +80,7 @@ namespace vcpkg { namespace Dependencies
continue;
}
- expected<SourceParagraph> maybe_spgh = try_load_port(paths, spec.name());
+ expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.port_dir(spec));
SourceParagraph* spgh = maybe_spgh.get();
Checks::check_exit(spgh != nullptr, "Cannot find package %s", spec.name());
process_dependencies(filter_dependencies(spgh->depends, spec.target_triplet()));
@@ -68,8 +92,65 @@ namespace vcpkg { namespace Dependencies
const std::vector<package_spec> pkgs = graph.find_topological_sort();
for (const package_spec& pkg : pkgs)
{
- ret.push_back({ pkg, std::move(was_examined[pkg]) });
+ ret.push_back(package_spec_with_install_plan(pkg, std::move(was_examined[pkg])));
+ }
+ return ret;
+ }
+
+ std::vector<package_spec_with_remove_plan> create_remove_plan(const std::vector<package_spec>& specs, const StatusParagraphs& status_db)
+ {
+ std::unordered_set<package_spec> specs_as_set(specs.cbegin(), specs.cend());
+
+ std::unordered_map<package_spec, remove_plan_action> was_examined; // Examine = we have checked its immediate (non-recursive) dependencies
+ Graphs::Graph<package_spec> graph;
+ graph.add_vertices(specs);
+
+ std::vector<package_spec> examine_stack(specs);
+ while (!examine_stack.empty())
+ {
+ const package_spec spec = examine_stack.back();
+ examine_stack.pop_back();
+
+ if (was_examined.find(spec) != was_examined.end())
+ {
+ continue;
+ }
+
+ const StatusParagraphs::const_iterator it = status_db.find(spec);
+ if (it == status_db.end() || (*it)->state == install_state_t::not_installed)
+ {
+ was_examined.emplace(spec, remove_plan_action(remove_plan_type::NOT_INSTALLED, request_type::USER_REQUESTED));
+ continue;
+ }
+
+ for (const std::unique_ptr<StatusParagraph>& an_installed_package : status_db)
+ {
+ if (an_installed_package->want != want_t::install)
+ continue;
+ if (an_installed_package->package.spec.target_triplet() != spec.target_triplet())
+ continue;
+
+ const std::vector<std::string>& deps = an_installed_package->package.depends;
+ if (std::find(deps.begin(), deps.end(), spec.name()) == deps.end())
+ {
+ continue;
+ }
+
+ graph.add_edge(spec, an_installed_package.get()->package.spec);
+ examine_stack.push_back(an_installed_package.get()->package.spec);
+ }
+
+ const request_type request_type = specs_as_set.find(spec) != specs_as_set.end() ? request_type::USER_REQUESTED : request_type::AUTO_SELECTED;
+ was_examined.emplace(spec, remove_plan_action(remove_plan_type::REMOVE, request_type));
+ }
+
+ std::vector<package_spec_with_remove_plan> ret;
+
+ const std::vector<package_spec> pkgs = graph.find_topological_sort();
+ for (const package_spec& pkg : pkgs)
+ {
+ ret.push_back(package_spec_with_remove_plan(pkg, std::move(was_examined[pkg])));
}
return ret;
}
-}}
+}
diff --git a/toolsrc/src/vcpkg_Enums.cpp b/toolsrc/src/vcpkg_Enums.cpp
new file mode 100644
index 000000000..5e698659d
--- /dev/null
+++ b/toolsrc/src/vcpkg_Enums.cpp
@@ -0,0 +1,21 @@
+#include "pch.h"
+#include "vcpkg_Enums.h"
+#include "vcpkg_Checks.h"
+
+namespace vcpkg::Enums
+{
+ std::string nullvalue_toString(const std::string& enum_name)
+ {
+ return Strings::format("%s_NULLVALUE", enum_name);
+ }
+
+ void nullvalue_used(const std::string& enum_name)
+ {
+ Checks::exit_with_message("NULLVALUE of enum %s was used", enum_name);
+ }
+
+ void unreachable(const std::string& enum_name)
+ {
+ Checks::exit_with_message("Unreachable code for enum, %s", enum_name);
+ }
+}
diff --git a/toolsrc/src/vcpkg_Environment.cpp b/toolsrc/src/vcpkg_Environment.cpp
index ed70e6881..8aaaba8a8 100644
--- a/toolsrc/src/vcpkg_Environment.cpp
+++ b/toolsrc/src/vcpkg_Environment.cpp
@@ -1,86 +1,187 @@
-#include <regex>
-#include <array>
+#include "pch.h"
#include "vcpkg_Environment.h"
#include "vcpkg_Commands.h"
-#include "metrics.h"
#include "vcpkg_System.h"
+#include "vcpkg_Strings.h"
+#include "vcpkg_Files.h"
-namespace vcpkg {namespace Environment
+namespace vcpkg::Environment
{
- static const fs::path default_cmake_installation_dir = "C:/Program Files/CMake/bin";
- static const fs::path default_cmake_installation_dir_x86 = "C:/Program Files (x86)/CMake/bin";
- static const fs::path default_git_installation_dir = "C:/Program Files/git/cmd";
- static const fs::path default_git_installation_dir_x86 = "C:/Program Files (x86)/git/cmd";
+ static std::vector<std::string> get_VS2017_installation_instances(const vcpkg_paths& paths)
+ {
+ const fs::path script = paths.scripts / "findVisualStudioInstallationInstances.ps1";
+ const std::wstring cmd = System::create_powershell_script_cmd(script);
+ System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(cmd);
+ Checks::check_exit(ec_data.exit_code == 0, "Could not run script to detect VS 2017 instances");
+ return Strings::split(ec_data.output, "\n");
+ }
+
+ static optional<fs::path> find_vs2015_installation_instance()
+ {
+ const optional<std::wstring> vs2015_cmntools_optional = System::get_environmental_variable(L"VS140COMNTOOLS");
+ if (!vs2015_cmntools_optional)
+ {
+ return nullptr;
+ }
+
+ static const fs::path vs2015_cmntools = fs::path(*vs2015_cmntools_optional).parent_path(); // The call to parent_path() is needed because the env variable has a trailing backslash
+ static const fs::path vs2015_path = vs2015_cmntools.parent_path().parent_path();
+ return std::make_unique<fs::path>(vs2015_path);
+ }
+
+ static const optional<fs::path>& get_VS2015_installation_instance()
+ {
+ static const optional<fs::path> vs2015_path = find_vs2015_installation_instance();
+ return vs2015_path;
+ }
- static void ensure_on_path(const std::array<int, 3>& version, const wchar_t* version_check_cmd, const wchar_t* install_cmd)
+ static fs::path find_dumpbin_exe(const vcpkg_paths& paths)
{
- System::exit_code_and_output ec_data = System::cmd_execute_and_capture_output(version_check_cmd);
- if (ec_data.exit_code == 0)
+ const std::vector<std::string> vs2017_installation_instances = get_VS2017_installation_instances(paths);
+ std::vector<fs::path> paths_examined;
+
+ // VS2017
+ for (const std::string& instance : vs2017_installation_instances)
{
- // version check
- std::regex re(R"###((\d+)\.(\d+)\.(\d+))###");
- std::match_results<std::string::const_iterator> match;
- auto found = std::regex_search(ec_data.output, match, re);
- if (found)
+ const fs::path msvc_path = Strings::format(R"(%s\VC\Tools\MSVC)", instance);
+ std::vector<fs::path> msvc_subdirectories;
+ Files::non_recursive_find_matching_paths_in_dir(msvc_path, [&](const fs::path& current)
+ {
+ return fs::is_directory(current);
+ }, &msvc_subdirectories);
+
+ // Sort them so that latest comes first
+ std::sort(msvc_subdirectories.begin(), msvc_subdirectories.end(), [&](const fs::path& left, const fs::path& right)
+ {
+ return left.filename() > right.filename();
+ });
+
+ for (const fs::path& subdir : msvc_subdirectories)
{
- int d1 = atoi(match[1].str().c_str());
- int d2 = atoi(match[2].str().c_str());
- int d3 = atoi(match[3].str().c_str());
- if (d1 > version[0] || (d1 == version[0] && d2 > version[1]) || (d1 == version[0] && d2 == version[1] && d3 >= version[2]))
+ const fs::path dumpbin_path = subdir / "bin" / "HostX86" / "x86" / "dumpbin.exe";
+ paths_examined.push_back(dumpbin_path);
+ if (fs::exists(dumpbin_path))
{
- // satisfactory version found
- return;
+ return dumpbin_path;
}
}
}
- auto rc = System::cmd_execute(install_cmd);
- if (rc)
+ // VS2015
+ const optional<fs::path>& vs_2015_installation_instance = get_VS2015_installation_instance();
+ if (vs_2015_installation_instance)
+ {
+ const fs::path vs2015_dumpbin_exe = *vs_2015_installation_instance / "VC" / "bin" / "dumpbin.exe";
+ paths_examined.push_back(vs2015_dumpbin_exe);
+ if (fs::exists(vs2015_dumpbin_exe))
+ {
+ return vs2015_dumpbin_exe;
+ }
+ }
+
+ System::println(System::color::error, "Could not detect dumpbin.exe.");
+ System::println("The following paths were examined:");
+ for (const fs::path& path : paths_examined)
+ {
+ System::println(" %s", path.generic_string());
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ const fs::path& get_dumpbin_exe(const vcpkg_paths& paths)
+ {
+ static const fs::path dumpbin_exe = find_dumpbin_exe(paths);
+ return dumpbin_exe;
+ }
+
+ static vcvarsall_and_platform_toolset find_vcvarsall_bat(const vcpkg_paths& paths)
+ {
+ const std::vector<std::string> vs2017_installation_instances = get_VS2017_installation_instances(paths);
+ std::vector<fs::path> paths_examined;
+
+ // VS2017
+ for (const fs::path& instance : vs2017_installation_instances)
+ {
+ const fs::path vcvarsall_bat = instance / "VC" / "Auxiliary" / "Build" / "vcvarsall.bat";
+ paths_examined.push_back(vcvarsall_bat);
+ if (fs::exists(vcvarsall_bat))
+ {
+ return { vcvarsall_bat , L"v141" };
+ }
+ }
+
+ // VS2015
+ const optional<fs::path>& vs_2015_installation_instance = get_VS2015_installation_instance();
+ if (vs_2015_installation_instance)
+ {
+ const fs::path vs2015_vcvarsall_bat = *vs_2015_installation_instance / "VC" / "vcvarsall.bat";
+
+ paths_examined.push_back(vs2015_vcvarsall_bat);
+ if (fs::exists(vs2015_vcvarsall_bat))
+ {
+ return { vs2015_vcvarsall_bat, L"v140" };
+ }
+ }
+
+ System::println(System::color::error, "Could not detect vcvarsall.bat.");
+ System::println("The following paths were examined:");
+ for (const fs::path& path : paths_examined)
{
- System::println(System::color::error, "Launching powershell failed or was denied");
- TrackProperty("error", "powershell install failed");
- TrackProperty("installcmd", install_cmd);
- exit(rc);
+ System::println(" %s", path.generic_string());
}
+ exit(EXIT_FAILURE);
+ }
+
+ const vcvarsall_and_platform_toolset& get_vcvarsall_bat(const vcpkg_paths& paths)
+ {
+ static const vcvarsall_and_platform_toolset vcvarsall_bat = find_vcvarsall_bat(paths);
+ return vcvarsall_bat;
}
- void ensure_git_on_path(const vcpkg_paths& paths)
+ static fs::path find_ProgramFiles()
{
- const fs::path downloaded_git = paths.downloads / "PortableGit" / "cmd";
- const std::wstring path_buf = Strings::wformat(L"%s;%s;%s;%s",
- downloaded_git.native(),
- System::wdupenv_str(L"PATH"),
- default_git_installation_dir.native(),
- default_git_installation_dir_x86.native());
- _wputenv_s(L"PATH", path_buf.c_str());
-
- static constexpr std::array<int, 3> git_version = {2,0,0};
- // TODO: switch out ExecutionPolicy Bypass with "Remove Mark Of The Web" code and restore RemoteSigned
- ensure_on_path(git_version, L"git --version 2>&1", L"powershell -ExecutionPolicy Bypass scripts\\fetchDependency.ps1 -Dependency git");
+ const optional<std::wstring> program_files = System::get_environmental_variable(L"PROGRAMFILES");
+ Checks::check_exit(program_files.get() != nullptr, "Could not detect the PROGRAMFILES environmental variable");
+ return *program_files;
}
- void ensure_cmake_on_path(const vcpkg_paths& paths)
+ static const fs::path& get_ProgramFiles()
{
- const fs::path downloaded_cmake = paths.downloads / "cmake-3.5.2-win32-x86" / "bin";
- const std::wstring path_buf = Strings::wformat(L"%s;%s;%s;%s",
- downloaded_cmake.native(),
- System::wdupenv_str(L"PATH"),
- default_cmake_installation_dir.native(),
- default_cmake_installation_dir_x86.native());
- _wputenv_s(L"PATH", path_buf.c_str());
-
- static constexpr std::array<int, 3> cmake_version = {3,5,0};
- // TODO: switch out ExecutionPolicy Bypass with "Remove Mark Of The Web" code and restore RemoteSigned
- ensure_on_path(cmake_version, L"cmake --version 2>&1", L"powershell -ExecutionPolicy Bypass scripts\\fetchDependency.ps1 -Dependency cmake");
+ static const fs::path p = find_ProgramFiles();
+ return p;
}
- void ensure_nuget_on_path(const vcpkg_paths& paths)
+ static fs::path find_ProgramFiles_32_bit()
{
- const std::wstring path_buf = Strings::wformat(L"%s;%s", paths.downloads.native(), System::wdupenv_str(L"PATH"));
- _wputenv_s(L"PATH", path_buf.c_str());
+ const optional<std::wstring> program_files_X86 = System::get_environmental_variable(L"ProgramFiles(x86)");
+ if (program_files_X86)
+ {
+ return *program_files_X86;
+ }
+
+ return get_ProgramFiles();
+ }
+
+ const fs::path& get_ProgramFiles_32_bit()
+ {
+ static const fs::path p = find_ProgramFiles_32_bit();
+ return p;
+ }
- static constexpr std::array<int, 3> nuget_version = {1,0,0};
- // TODO: switch out ExecutionPolicy Bypass with "Remove Mark Of The Web" code and restore RemoteSigned
- ensure_on_path(nuget_version, L"nuget 2>&1", L"powershell -ExecutionPolicy Bypass scripts\\fetchDependency.ps1 -Dependency nuget");
+ static fs::path find_ProgramFiles_platform_bitness()
+ {
+ const optional<std::wstring> program_files_W6432 = System::get_environmental_variable(L"ProgramW6432");
+ if (program_files_W6432)
+ {
+ return *program_files_W6432;
+ }
+
+ return get_ProgramFiles();
+ }
+
+ const fs::path& get_ProgramFiles_platform_bitness()
+ {
+ static const fs::path p = find_ProgramFiles_platform_bitness();
+ return p;
}
-}}
+}
diff --git a/toolsrc/src/vcpkg_Files.cpp b/toolsrc/src/vcpkg_Files.cpp
index 48283e43f..57d4c665c 100644
--- a/toolsrc/src/vcpkg_Files.cpp
+++ b/toolsrc/src/vcpkg_Files.cpp
@@ -1,9 +1,8 @@
+#include "pch.h"
#include "vcpkg_Files.h"
-#include <fstream>
-#include <regex>
#include "vcpkg_System.h"
-namespace vcpkg {namespace Files
+namespace vcpkg::Files
{
static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])");
@@ -103,7 +102,7 @@ namespace vcpkg {namespace Files
void recursive_find_all_files_in_dir(const fs::path& dir, std::vector<fs::path>* output)
{
- recursive_find_matching_paths_in_dir(dir, [&](const fs::path& current)
+ recursive_find_matching_paths_in_dir(dir, [](const fs::path& current)
{
return !fs::is_directory(current);
}, output);
@@ -118,7 +117,7 @@ namespace vcpkg {namespace Files
void non_recursive_find_all_files_in_dir(const fs::path& dir, std::vector<fs::path>* output)
{
- non_recursive_find_matching_paths_in_dir(dir, [&](const fs::path& current)
+ non_recursive_find_matching_paths_in_dir(dir, [](const fs::path& current)
{
return !fs::is_directory(current);
}, output);
@@ -140,4 +139,4 @@ namespace vcpkg {namespace Files
}
System::println("");
}
-}}
+}
diff --git a/toolsrc/src/vcpkg_Input.cpp b/toolsrc/src/vcpkg_Input.cpp
index 29d487fdb..5720cadc0 100644
--- a/toolsrc/src/vcpkg_Input.cpp
+++ b/toolsrc/src/vcpkg_Input.cpp
@@ -1,9 +1,10 @@
+#include "pch.h"
#include "vcpkg_Input.h"
#include "vcpkg_System.h"
#include "metrics.h"
#include "vcpkg_Commands.h"
-namespace vcpkg {namespace Input
+namespace vcpkg::Input
{
package_spec check_and_get_package_spec(const std::string& package_spec_as_string, const triplet& default_target_triplet, const std::string& example_text)
{
@@ -37,16 +38,16 @@ namespace vcpkg {namespace Input
{
System::println(System::color::error, "Error: invalid triplet: %s", t.canonical_name());
TrackProperty("error", "invalid triplet: " + t.canonical_name());
- help_topic_valid_triplet(paths);
+ Commands::Help::help_topic_valid_triplet(paths);
exit(EXIT_FAILURE);
}
}
- void check_triplets(std::vector<package_spec> triplets, const vcpkg_paths& paths)
+ void check_triplets(const std::vector<package_spec>& triplets, const vcpkg_paths& paths)
{
for (const package_spec& spec : triplets)
{
check_triplet(spec.target_triplet(), paths);
}
}
-}}
+}
diff --git a/toolsrc/src/vcpkg_Strings.cpp b/toolsrc/src/vcpkg_Strings.cpp
index 46a4b1855..044fd3c05 100644
--- a/toolsrc/src/vcpkg_Strings.cpp
+++ b/toolsrc/src/vcpkg_Strings.cpp
@@ -1,13 +1,7 @@
+#include "pch.h"
#include "vcpkg_Strings.h"
-#include <cstdarg>
-#include <algorithm>
-#include <codecvt>
-#include <iterator>
-#include <functional>
-#include <cctype>
-
-namespace vcpkg {namespace Strings {namespace details
+namespace vcpkg::Strings::details
{
// To disambiguate between two overloads
static const auto isspace = [](const char c)
@@ -15,14 +9,26 @@ namespace vcpkg {namespace Strings {namespace details
return std::isspace(c);
};
+ // Avoids C4244 warnings because of char<->int conversion that occur when using std::tolower()
+ static char tolower_char(const char c)
+ {
+ return static_cast<char>(std::tolower(c));
+ }
+
+ static _locale_t& c_locale()
+ {
+ static _locale_t c_locale_impl = _create_locale(LC_ALL, "C");
+ return c_locale_impl;
+ }
+
std::string format_internal(const char* fmtstr, ...)
{
va_list lst;
va_start(lst, fmtstr);
- auto sz = _vscprintf(fmtstr, lst);
+ const int sz = _vscprintf_l(fmtstr, c_locale(), lst);
std::string output(sz, '\0');
- _vsnprintf_s(&output[0], output.size() + 1, output.size() + 1, fmtstr, lst);
+ _vsnprintf_s_l(&output[0], output.size() + 1, output.size() + 1, fmtstr, c_locale(), lst);
va_end(lst);
return output;
@@ -33,16 +39,16 @@ namespace vcpkg {namespace Strings {namespace details
va_list lst;
va_start(lst, fmtstr);
- auto sz = _vscwprintf(fmtstr, lst);
+ const int sz = _vscwprintf_l(fmtstr, c_locale(), lst);
std::wstring output(sz, '\0');
- _vsnwprintf_s(&output[0], output.size() + 1, output.size() + 1, fmtstr, lst);
+ _vsnwprintf_s_l(&output[0], output.size() + 1, output.size() + 1, fmtstr, c_locale(), lst);
va_end(lst);
return output;
}
-}}}
+}
-namespace vcpkg {namespace Strings
+namespace vcpkg::Strings
{
std::wstring utf8_to_utf16(const std::string& s)
{
@@ -58,40 +64,28 @@ namespace vcpkg {namespace Strings
std::string::const_iterator case_insensitive_ascii_find(const std::string& s, const std::string& pattern)
{
- std::string pattern_as_lower_case;
- std::transform(pattern.begin(), pattern.end(), back_inserter(pattern_as_lower_case), tolower);
+ const std::string pattern_as_lower_case(ascii_to_lowercase(pattern));
return search(s.begin(), s.end(), pattern_as_lower_case.begin(), pattern_as_lower_case.end(), [](const char a, const char b)
{
- return tolower(a) == b;
+ return details::tolower_char(a) == b;
});
}
std::string ascii_to_lowercase(const std::string& input)
{
- std::string output = input;
- std::transform(output.begin(), output.end(), output.begin(), ::tolower);
+ std::string output(input);
+ std::transform(output.begin(), output.end(), output.begin(), &details::tolower_char);
return output;
}
- std::string join(const std::vector<std::string>& v, const std::string& delimiter)
+ std::string join(const std::string& delimiter, const std::vector<std::string>& v)
{
- if (v.empty())
- {
- return std::string();
- }
-
- std::string output;
- size_t size = v.size();
-
- output.append(v.at(0));
-
- for (size_t i = 1; i < size; ++i)
- {
- output.append(delimiter);
- output.append(v.at(i));
- }
+ return join(delimiter, v, [](const std::string& p) -> const std::string& { return p; });
+ }
- return output;
+ std::wstring wjoin(const std::wstring& delimiter, const std::vector<std::wstring>& v)
+ {
+ return wjoin(delimiter, v, [](const std::wstring& p) -> const std::wstring&{ return p; });
}
void trim(std::string* s)
@@ -119,4 +113,24 @@ namespace vcpkg {namespace Strings
return s == "";
}), strings->end());
}
-}}
+
+ std::vector<std::string> split(const std::string& s, const std::string& delimiter)
+ {
+ std::vector<std::string> output;
+
+ size_t i = 0;
+ for (size_t pos = s.find(delimiter); pos != std::string::npos; pos = s.find(delimiter, pos))
+ {
+ output.push_back(s.substr(i, pos - i));
+ i = ++pos;
+ }
+
+ // Add the rest of the string after the last delimiter, unless there is nothing after it
+ if (i != s.length())
+ {
+ output.push_back(s.substr(i, s.length()));
+ }
+
+ return output;
+ }
+}
diff --git a/toolsrc/src/vcpkg_System.cpp b/toolsrc/src/vcpkg_System.cpp
index 43eae3412..472f8450f 100644
--- a/toolsrc/src/vcpkg_System.cpp
+++ b/toolsrc/src/vcpkg_System.cpp
@@ -1,21 +1,97 @@
+#include "pch.h"
#include "vcpkg_System.h"
-#include <iostream>
-#include <Windows.h>
-#include <regex>
+#include "vcpkg_Checks.h"
-namespace vcpkg {namespace System
+namespace vcpkg::System
{
fs::path get_exe_path_of_current_process()
{
- wchar_t buf[_MAX_PATH ];
+ wchar_t buf[_MAX_PATH];
int bytes = GetModuleFileNameW(nullptr, buf, _MAX_PATH);
if (bytes == 0)
std::abort();
return fs::path(buf, buf + bytes);
}
+ int cmd_execute_clean(const wchar_t* cmd_line)
+ {
+ static const std::wstring system_root = *get_environmental_variable(L"SystemRoot");
+ static const std::wstring system_32 = system_root + LR"(\system32)";
+ static const std::wstring new_PATH = Strings::wformat(LR"(Path=%s;%s;%s\WindowsPowerShell\v1.0\)", system_32, system_root, system_32);
+
+ std::vector<std::wstring> env_wstrings =
+ {
+ 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",
+ 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",
+ };
+
+ // Flush stdout before launching external process
+ _flushall();
+
+ std::vector<const wchar_t*> env_cstr;
+ env_cstr.reserve(env_wstrings.size() + 2);
+
+ for (auto&& env_wstring : env_wstrings)
+ {
+ auto v = System::get_environmental_variable(env_wstring.c_str());
+ if (v == nullptr || v->empty())
+ continue;
+
+ env_wstring.push_back(L'=');
+ env_wstring.append(*v);
+ env_cstr.push_back(env_wstring.c_str());
+ }
+
+ env_cstr.push_back(new_PATH.c_str());
+ env_cstr.push_back(nullptr);
+
+ // Basically we are wrapping it in quotes
+ const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s")###", cmd_line);
+ auto exit_code = _wspawnlpe(_P_WAIT, L"cmd.exe", L"cmd.exe", L"/c", actual_cmd_line.c_str(), nullptr, env_cstr.data());
+ return static_cast<int>(exit_code);
+ }
+
int cmd_execute(const wchar_t* cmd_line)
{
+ // Flush stdout before launching external process
+ _flushall();
+
// Basically we are wrapping it in quotes
const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s")###", cmd_line);
int exit_code = _wsystem(actual_cmd_line.c_str());
@@ -24,6 +100,9 @@ namespace vcpkg {namespace System
exit_code_and_output cmd_execute_and_capture_output(const wchar_t* cmd_line)
{
+ // Flush stdout before launching external process
+ fflush(stdout);
+
const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s")###", cmd_line);
std::string output;
@@ -31,7 +110,7 @@ namespace vcpkg {namespace System
auto pipe = _wpopen(actual_cmd_line.c_str(), L"r");
if (pipe == nullptr)
{
- return {1, output};
+ return { 1, output };
}
while (fgets(buf, 1024, pipe))
{
@@ -39,21 +118,32 @@ namespace vcpkg {namespace System
}
if (!feof(pipe))
{
- return {1, output};
+ return { 1, output };
}
auto ec = _pclose(pipe);
- return {ec, output};
+ return { ec, output };
+ }
+
+ std::wstring create_powershell_script_cmd(const fs::path& script_path)
+ {
+ return create_powershell_script_cmd(script_path, L"");
+ }
+
+ std::wstring create_powershell_script_cmd(const fs::path& script_path, const std::wstring& args)
+ {
+ // TODO: switch out ExecutionPolicy Bypass with "Remove Mark Of The Web" code and restore RemoteSigned
+ return Strings::wformat(LR"(powershell -ExecutionPolicy Bypass -Command "& {& '%s' %s}")", script_path.native(), args);
}
void print(const char* message)
{
- std::cout << message;
+ fputs(message, stdout);
}
void println(const char* message)
{
print(message);
- std::cout << "\n";
+ putchar('\n');
}
void print(const color c, const char* message)
@@ -64,46 +154,61 @@ namespace vcpkg {namespace System
GetConsoleScreenBufferInfo(hConsole, &consoleScreenBufferInfo);
auto original_color = consoleScreenBufferInfo.wAttributes;
- SetConsoleTextAttribute(hConsole, static_cast<int>(c) | (original_color & 0xF0));
- std::cout << message;
+ SetConsoleTextAttribute(hConsole, static_cast<WORD>(c) | (original_color & 0xF0));
+ print(message);
SetConsoleTextAttribute(hConsole, original_color);
}
void println(const color c, const char* message)
{
print(c, message);
- std::cout << "\n";
+ putchar('\n');
}
- std::wstring wdupenv_str(const wchar_t* varname) noexcept
+ optional<std::wstring> get_environmental_variable(const wchar_t* varname) noexcept
{
- std::wstring ret;
- wchar_t* buffer;
- _wdupenv_s(&buffer, nullptr, varname);
- if (buffer != nullptr)
- {
- ret = buffer;
- free(buffer);
- }
+ auto sz = GetEnvironmentVariableW(varname, nullptr, 0);
+ if (sz == 0)
+ return nullptr;
+
+ auto ret = std::make_unique<std::wstring>(sz, L'\0');
+ Checks::check_exit(MAXDWORD >= ret->size());
+ auto sz2 = GetEnvironmentVariableW(varname, ret->data(), static_cast<DWORD>(ret->size()));
+ Checks::check_exit(sz2 + 1 == sz);
+ ret->pop_back();
return ret;
}
- void Stopwatch2::start()
+ void set_environmental_variable(const wchar_t* varname, const wchar_t* varvalue) noexcept
{
- static_assert(sizeof(start_time) == sizeof(LARGE_INTEGER), "");
-
- QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&start_time));
+ _wputenv_s(varname, varvalue);
}
- void Stopwatch2::stop()
+ static bool is_string_keytype(DWORD hkey_type)
{
- QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_time));
- QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq));
+ return hkey_type == REG_SZ || hkey_type == REG_MULTI_SZ || hkey_type == REG_EXPAND_SZ;
}
- double Stopwatch2::microseconds() const
+ optional<std::wstring> get_registry_string(HKEY base, const wchar_t* subKey, const wchar_t* valuename)
{
- return (reinterpret_cast<const LARGE_INTEGER*>(&end_time)->QuadPart -
- reinterpret_cast<const LARGE_INTEGER*>(&start_time)->QuadPart) * 1000000.0 / reinterpret_cast<const LARGE_INTEGER*>(&freq)->QuadPart;
+ HKEY k = nullptr;
+ LSTATUS ec = RegOpenKeyExW(base, subKey, NULL, KEY_READ, &k);
+ if (ec != ERROR_SUCCESS)
+ return nullptr;
+
+ DWORD dwBufferSize = 0;
+ DWORD dwType = 0;
+ auto rc = RegQueryValueExW(k, valuename, nullptr, &dwType, nullptr, &dwBufferSize);
+ if (rc != ERROR_SUCCESS || !is_string_keytype(dwType) || dwBufferSize == 0 || dwBufferSize % sizeof(wchar_t) != 0)
+ return nullptr;
+ 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())
+ return nullptr;
+
+ ret.pop_back(); // remove extra trailing null byte
+ return std::make_unique<std::wstring>(std::move(ret));
}
-}}
+}
diff --git a/toolsrc/src/vcpkg_cmd_arguments.cpp b/toolsrc/src/vcpkg_cmd_arguments.cpp
index a3648668f..fdeb6e877 100644
--- a/toolsrc/src/vcpkg_cmd_arguments.cpp
+++ b/toolsrc/src/vcpkg_cmd_arguments.cpp
@@ -1,8 +1,6 @@
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include "pch.h"
#include "vcpkg_cmd_arguments.h"
#include "vcpkg_Commands.h"
-#include <unordered_set>
#include "metrics.h"
#include "vcpkg_System.h"
@@ -18,7 +16,7 @@ namespace vcpkg
{
System::println(System::color::error, "Error: expected value after %s", option_name);
TrackProperty("error", "error option name");
- print_usage();
+ Commands::Help::print_usage();
exit(EXIT_FAILURE);
}
@@ -26,7 +24,7 @@ namespace vcpkg
{
System::println(System::color::error, "Error: %s specified multiple times", option_name);
TrackProperty("error", "error option specified multiple times");
- print_usage();
+ Commands::Help::print_usage();
exit(EXIT_FAILURE);
}
@@ -34,15 +32,15 @@ namespace vcpkg
}
static void parse_switch(
- opt_bool new_setting,
+ opt_bool_t new_setting,
const std::string& option_name,
- opt_bool& option_field)
+ opt_bool_t& option_field)
{
- if (option_field != opt_bool::unspecified && option_field != new_setting)
+ if (option_field != opt_bool_t::UNSPECIFIED && option_field != new_setting)
{
System::println(System::color::error, "Error: conflicting values specified for --%s", option_name);
TrackProperty("error", "error conflicting switches");
- print_usage();
+ Commands::Help::print_usage();
exit(EXIT_FAILURE);
}
option_field = new_setting;
@@ -96,27 +94,27 @@ namespace vcpkg
}
if (arg == "--debug")
{
- parse_switch(opt_bool::enabled, "debug", args.debug);
+ parse_switch(opt_bool_t::ENABLED, "debug", args.debug);
continue;
}
if (arg == "--sendmetrics")
{
- parse_switch(opt_bool::enabled, "sendmetrics", args.sendmetrics);
+ parse_switch(opt_bool_t::ENABLED, "sendmetrics", args.sendmetrics);
continue;
}
if (arg == "--printmetrics")
{
- parse_switch(opt_bool::enabled, "printmetrics", args.printmetrics);
+ parse_switch(opt_bool_t::ENABLED, "printmetrics", args.printmetrics);
continue;
}
if (arg == "--no-sendmetrics")
{
- parse_switch(opt_bool::disabled, "sendmetrics", args.sendmetrics);
+ parse_switch(opt_bool_t::DISABLED, "sendmetrics", args.sendmetrics);
continue;
}
if (arg == "--no-printmetrics")
{
- parse_switch(opt_bool::disabled, "printmetrics", args.printmetrics);
+ parse_switch(opt_bool_t::DISABLED, "printmetrics", args.printmetrics);
continue;
}
diff --git a/toolsrc/src/vcpkg_info.cpp b/toolsrc/src/vcpkg_info.cpp
deleted file mode 100644
index 25c09d6da..000000000
--- a/toolsrc/src/vcpkg_info.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "vcpkg_info.h"
-#include "metrics.h"
-
-#define STRINGIFY(X) #X
-#define MACRO_TO_STRING(X) STRINGIFY(X)
-
-#define VCPKG_VERSION_AS_STRING MACRO_TO_STRING(VCPKG_VERSION)"" // Double quotes needed at the end to prevent blank token
-
-namespace vcpkg { namespace Info
-{
- const std::string& version()
- {
- static const std::string s_version =
-#include "../VERSION.txt"
-
-
-#pragma warning( push )
-#pragma warning( disable : 4003)
- // VCPKG_VERSION can be defined but have no value, which yields C4003.
- + std::string(VCPKG_VERSION_AS_STRING)
-#pragma warning( pop )
-#ifndef NDEBUG
- + std::string("-debug")
-#endif
- + std::string(GetCompiledMetricsEnabled() ? "" : "-external");
- return s_version;
- }
-
- const std::string& email()
- {
- static const std::string s_email = R"(vcpkg@microsoft.com)";
- return s_email;
- }
-}}
diff --git a/toolsrc/src/vcpkg_metrics_uploader.cpp b/toolsrc/src/vcpkg_metrics_uploader.cpp
index 14fc9ae48..82dcd4b03 100644
--- a/toolsrc/src/vcpkg_metrics_uploader.cpp
+++ b/toolsrc/src/vcpkg_metrics_uploader.cpp
@@ -5,13 +5,7 @@
using namespace vcpkg;
-int WINAPI
-WinMain(
- _In_ HINSTANCE hInstance,
- _In_opt_ HINSTANCE hPrevInstance,
- _In_ LPSTR lpCmdLine,
- _In_ int nShowCmd
-)
+int WINAPI WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ int)
{
LPWSTR* szArgList;
int argCount;
diff --git a/toolsrc/src/vcpkg_paths.cpp b/toolsrc/src/vcpkg_paths.cpp
index b7e716307..fa6fca370 100644
--- a/toolsrc/src/vcpkg_paths.cpp
+++ b/toolsrc/src/vcpkg_paths.cpp
@@ -1,11 +1,156 @@
+#include "pch.h"
#include "expected.h"
#include "vcpkg_paths.h"
#include "metrics.h"
#include "vcpkg_System.h"
#include "package_spec.h"
+#include "vcpkg_Environment.h"
namespace vcpkg
{
+ static bool exists_and_has_equal_or_greater_version(const std::wstring& version_cmd, const std::array<int, 3>& expected_version)
+ {
+ static const std::regex re(R"###((\d+)\.(\d+)\.(\d+))###");
+
+ auto rc = System::cmd_execute_and_capture_output(Strings::wformat(LR"(%s 2>&1)", version_cmd));
+ if (rc.exit_code != 0)
+ {
+ return false;
+ }
+
+ std::match_results<std::string::const_iterator> match;
+ auto found = std::regex_search(rc.output, match, re);
+ if (!found)
+ {
+ return false;
+ }
+
+ int d1 = atoi(match[1].str().c_str());
+ int d2 = atoi(match[2].str().c_str());
+ int d3 = atoi(match[3].str().c_str());
+ if (d1 > expected_version[0] || (d1 == expected_version[0] && d2 > expected_version[1]) || (d1 == expected_version[0] && d2 == expected_version[1] && d3 >= expected_version[2]))
+ {
+ // satisfactory version found
+ return true;
+ }
+
+ return false;
+ }
+
+ static optional<fs::path> find_if_has_equal_or_greater_version(const std::vector<fs::path>& candidate_paths, const std::wstring& version_check_arguments, const std::array<int, 3>& expected_version)
+ {
+ auto it = std::find_if(candidate_paths.cbegin(), candidate_paths.cend(), [&](const fs::path& p)
+ {
+ const std::wstring cmd = Strings::wformat(LR"("%s" %s)", p.native(), version_check_arguments);
+ return exists_and_has_equal_or_greater_version(cmd, expected_version);
+ });
+
+ if (it != candidate_paths.cend())
+ {
+ return std::make_unique<fs::path>(std::move(*it));
+ }
+
+ return nullptr;
+ }
+
+ static std::vector<fs::path> find_from_PATH(const std::wstring& name)
+ {
+ const std::wstring cmd = Strings::wformat(L"where.exe %s", name);
+ auto out = System::cmd_execute_and_capture_output(cmd);
+ if (out.exit_code != 0)
+ {
+ return {};
+ }
+
+ const std::vector<std::string> paths_to_add = Strings::split(out.output, "\n");
+ std::vector<fs::path> v;
+ v.insert(v.end(), paths_to_add.cbegin(), paths_to_add.cend());
+ return v;
+ }
+
+ static fs::path fetch_dependency(const fs::path scripts_folder, const std::wstring& tool_name, const fs::path& expected_downloaded_path)
+ {
+ const fs::path script = scripts_folder / "fetchDependency.ps1";
+ auto install_cmd = System::create_powershell_script_cmd(script, Strings::wformat(L"-Dependency %s", tool_name));
+ System::exit_code_and_output rc = System::cmd_execute_and_capture_output(install_cmd);
+ if (rc.exit_code)
+ {
+ System::println(System::color::error, "Launching powershell failed or was denied");
+ TrackProperty("error", "powershell install failed");
+ TrackProperty("installcmd", install_cmd);
+ exit(rc.exit_code);
+ }
+
+ const fs::path actual_downloaded_path = rc.output;
+ Checks::check_exit(expected_downloaded_path == actual_downloaded_path, "Expected dependency downloaded path to be %s, but was %s",
+ expected_downloaded_path.generic_string(), actual_downloaded_path.generic_string());
+ return actual_downloaded_path;
+ }
+
+ static fs::path get_cmake_path(const fs::path& downloads_folder, const fs::path scripts_folder)
+ {
+ static constexpr std::array<int, 3> expected_version = { 3,8,0 };
+ static const std::wstring version_check_arguments = L"--version";
+
+ const fs::path downloaded_copy = downloads_folder / "cmake-3.8.0-rc1-win32-x86" / "bin" / "cmake.exe";
+ const std::vector<fs::path> from_path = find_from_PATH(L"cmake");
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(downloaded_copy);
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+ candidate_paths.push_back(Environment::get_ProgramFiles_platform_bitness() / "CMake" / "bin" / "cmake.exe");
+ candidate_paths.push_back(Environment::get_ProgramFiles_32_bit() / "CMake" / "bin");
+
+ if (auto ret = find_if_has_equal_or_greater_version(candidate_paths, version_check_arguments, expected_version))
+ {
+ return *ret;
+ }
+
+ return fetch_dependency(scripts_folder, L"cmake", downloaded_copy);
+ }
+
+ fs::path get_nuget_path(const fs::path& downloads_folder, const fs::path scripts_folder)
+ {
+ static constexpr std::array<int, 3> expected_version = { 3,3,0 };
+ static const std::wstring version_check_arguments = L"";
+
+ const fs::path downloaded_copy = downloads_folder / "nuget-3.5.0" / "nuget.exe";
+ const std::vector<fs::path> from_path = find_from_PATH(L"nuget");
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(downloaded_copy);
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+
+ if (auto ret = find_if_has_equal_or_greater_version(candidate_paths, version_check_arguments, expected_version))
+ {
+ return *ret;
+ }
+
+ return fetch_dependency(scripts_folder, L"nuget", downloaded_copy);
+ }
+
+ fs::path get_git_path(const fs::path& downloads_folder, const fs::path scripts_folder)
+ {
+ static constexpr std::array<int, 3> expected_version = { 2,0,0 };
+ static const std::wstring version_check_arguments = L"--version";
+
+ const fs::path downloaded_copy = downloads_folder / "MinGit-2.11.1-32-bit" / "cmd" / "git.exe";
+ const std::vector<fs::path> from_path = find_from_PATH(L"git");
+
+ std::vector<fs::path> candidate_paths;
+ candidate_paths.push_back(downloaded_copy);
+ candidate_paths.insert(candidate_paths.end(), from_path.cbegin(), from_path.cend());
+ candidate_paths.push_back(Environment::get_ProgramFiles_platform_bitness() / "git" / "cmd" / "git.exe");
+ candidate_paths.push_back(Environment::get_ProgramFiles_32_bit() / "git" / "cmd" / "git.exe");
+
+ if (auto ret = find_if_has_equal_or_greater_version(candidate_paths, version_check_arguments, expected_version))
+ {
+ return *ret;
+ }
+
+ return fetch_dependency(scripts_folder, L"git", downloaded_copy);
+ }
+
expected<vcpkg_paths> vcpkg_paths::create(const fs::path& vcpkg_root_dir)
{
std::error_code ec;
@@ -31,8 +176,9 @@ namespace vcpkg
paths.ports = paths.root / "ports";
paths.installed = paths.root / "installed";
paths.triplets = paths.root / "triplets";
+ paths.scripts = paths.root / "scripts";
- paths.buildsystems = paths.root / "scripts" / "buildsystems";
+ paths.buildsystems = paths.scripts / "buildsystems";
paths.buildsystems_msbuild_targets = paths.buildsystems / "msbuild" / "vcpkg.targets";
paths.vcpkg_dir = paths.installed / "vcpkg";
@@ -40,7 +186,8 @@ namespace vcpkg
paths.vcpkg_dir_info = paths.vcpkg_dir / "info";
paths.vcpkg_dir_updates = paths.vcpkg_dir / "updates";
- paths.ports_cmake = paths.root / "scripts" / "ports.cmake";
+ paths.ports_cmake = paths.scripts / "ports.cmake";
+
return paths;
}
@@ -78,4 +225,19 @@ namespace vcpkg
}
return false;
}
+
+ const fs::path& vcpkg_paths::get_cmake_exe() const
+ {
+ return this->cmake_exe.get_lazy([this]() { return get_cmake_path(this->downloads, this->scripts); });
+ }
+
+ const fs::path& vcpkg_paths::get_git_exe() const
+ {
+ return this->git_exe.get_lazy([this]() { return get_git_path(this->downloads, this->scripts); });
+ }
+
+ const fs::path& vcpkg_paths::get_nuget_exe() const
+ {
+ return this->nuget_exe.get_lazy([this]() { return get_nuget_path(this->downloads, this->scripts); });
+ }
}
diff --git a/toolsrc/src/vcpkglib.cpp b/toolsrc/src/vcpkglib.cpp
new file mode 100644
index 000000000..7ea33da0a
--- /dev/null
+++ b/toolsrc/src/vcpkglib.cpp
@@ -0,0 +1,215 @@
+#include "pch.h"
+#include "vcpkglib.h"
+#include "vcpkg_Files.h"
+#include "Paragraphs.h"
+#include "metrics.h"
+#include "vcpkg_Strings.h"
+
+namespace vcpkg
+{
+ static StatusParagraphs load_current_database(const fs::path& vcpkg_dir_status_file, const fs::path& vcpkg_dir_status_file_old)
+ {
+ if (!fs::exists(vcpkg_dir_status_file))
+ {
+ if (!fs::exists(vcpkg_dir_status_file_old))
+ {
+ // no status file, use empty db
+ return StatusParagraphs();
+ }
+
+ fs::rename(vcpkg_dir_status_file_old, vcpkg_dir_status_file);
+ }
+
+ auto text = Files::read_contents(vcpkg_dir_status_file).get_or_throw();
+ auto pghs = Paragraphs::parse_paragraphs(text);
+
+ std::vector<std::unique_ptr<StatusParagraph>> status_pghs;
+ for (auto&& p : pghs)
+ {
+ status_pghs.push_back(std::make_unique<StatusParagraph>(p));
+ }
+
+ return StatusParagraphs(std::move(status_pghs));
+ }
+
+ StatusParagraphs database_load_check(const vcpkg_paths& paths)
+ {
+ auto updates_dir = paths.vcpkg_dir_updates;
+
+ std::error_code ec;
+ fs::create_directory(paths.installed, ec);
+ fs::create_directory(paths.vcpkg_dir, ec);
+ fs::create_directory(paths.vcpkg_dir_info, ec);
+ fs::create_directory(updates_dir, ec);
+
+ const fs::path& status_file = paths.vcpkg_dir_status_file;
+ const fs::path status_file_old = status_file.parent_path() / "status-old";
+ const fs::path status_file_new = status_file.parent_path() / "status-new";
+
+ StatusParagraphs current_status_db = load_current_database(status_file, status_file_old);
+
+ auto b = fs::directory_iterator(updates_dir);
+ auto e = fs::directory_iterator();
+ if (b == e)
+ {
+ // updates directory is empty, control file is up-to-date.
+ return current_status_db;
+ }
+
+ for (; b != e; ++b)
+ {
+ if (!fs::is_regular_file(b->status()))
+ continue;
+ if (b->path().filename() == "incomplete")
+ continue;
+
+ auto text = Files::read_contents(b->path()).get_or_throw();
+ auto pghs = Paragraphs::parse_paragraphs(text);
+ for (auto&& p : pghs)
+ {
+ current_status_db.insert(std::make_unique<StatusParagraph>(p));
+ }
+ }
+
+ std::fstream(status_file_new, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc) << current_status_db;
+
+ if (fs::exists(status_file_old))
+ fs::remove(status_file_old);
+ if (fs::exists(status_file))
+ fs::rename(status_file, status_file_old);
+ fs::rename(status_file_new, status_file);
+ fs::remove(status_file_old);
+
+ b = fs::directory_iterator(updates_dir);
+ for (; b != e; ++b)
+ {
+ if (!fs::is_regular_file(b->status()))
+ continue;
+ fs::remove(b->path());
+ }
+
+ return current_status_db;
+ }
+
+ void write_update(const vcpkg_paths& paths, const StatusParagraph& p)
+ {
+ static int update_id = 0;
+ auto my_update_id = update_id++;
+ auto tmp_update_filename = paths.vcpkg_dir_updates / "incomplete";
+ auto update_filename = paths.vcpkg_dir_updates / std::to_string(my_update_id);
+ std::fstream fs(tmp_update_filename, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
+ fs << p;
+ fs.close();
+ fs::rename(tmp_update_filename, update_filename);
+ }
+
+ static void upgrade_to_slash_terminated_sorted_format(std::vector<std::string>* lines, const fs::path& listfile_path)
+ {
+ static bool was_tracked = false;
+
+ if (lines->empty())
+ {
+ return;
+ }
+
+ if (lines->at(0).back() == '/')
+ {
+ return; // File already in the new format
+ }
+
+ if (!was_tracked)
+ {
+ was_tracked = true;
+ TrackProperty("listfile", "update to new format");
+ }
+
+ // The files are sorted such that directories are placed just before the files they contain
+ // (They are not necessarily sorted alphabetically, e.g. libflac)
+ // Therefore we can detect the entries that represent directories by comparing every element with the next one
+ // and checking if the next has a slash immediately after the current one's length
+ for (size_t i = 0; i < lines->size() - 1; i++)
+ {
+ std::string& current_string = lines->at(i);
+ const std::string& next_string = lines->at(i + 1);
+
+ const size_t potential_slash_char_index = current_string.length();
+ // Make sure the index exists first
+ if (next_string.size() > potential_slash_char_index && next_string.at(potential_slash_char_index) == '/')
+ {
+ current_string += '/'; // Mark as a directory
+ }
+ }
+
+ // After suffixing the directories with a slash, we can now sort.
+ // We cannot sort before adding the suffixes because the following (actual example):
+ /*
+ x86-windows/include/FLAC <<<<<< This would be separated from its group due to sorting
+ x86-windows/include/FLAC/all.h
+ x86-windows/include/FLAC/assert.h
+ x86-windows/include/FLAC/callback.h
+ x86-windows/include/FLAC++
+ x86-windows/include/FLAC++/all.h
+ x86-windows/include/FLAC++/decoder.h
+ x86-windows/include/FLAC++/encoder.h
+ *
+ x86-windows/include/FLAC/ <<<<<< This will now be kept with its group when sorting
+ x86-windows/include/FLAC/all.h
+ x86-windows/include/FLAC/assert.h
+ x86-windows/include/FLAC/callback.h
+ x86-windows/include/FLAC++/
+ x86-windows/include/FLAC++/all.h
+ x86-windows/include/FLAC++/decoder.h
+ x86-windows/include/FLAC++/encoder.h
+ */
+ // Note that after sorting, the FLAC++/ group will be placed before the FLAC/ group
+ // The new format is lexicographically sorted
+ std::sort(lines->begin(), lines->end());
+
+ // Replace the listfile on disk
+ const fs::path updated_listfile_path = listfile_path.generic_string() + "_updated";
+ Files::write_all_lines(updated_listfile_path, *lines);
+ fs::rename(updated_listfile_path, listfile_path);
+ }
+
+ std::vector<StatusParagraph_and_associated_files> get_installed_files(const vcpkg_paths& paths, const StatusParagraphs& status_db)
+ {
+ std::vector<StatusParagraph_and_associated_files> installed_files;
+
+ for (const std::unique_ptr<StatusParagraph>& pgh : status_db)
+ {
+ if (pgh->state != install_state_t::installed)
+ {
+ continue;
+ }
+
+ const fs::path listfile_path = paths.listfile_path(pgh->package);
+ std::vector<std::string> installed_files_of_current_pgh = Files::read_all_lines(listfile_path).get_or_throw();
+ Strings::trim_all_and_remove_whitespace_strings(&installed_files_of_current_pgh);
+ upgrade_to_slash_terminated_sorted_format(&installed_files_of_current_pgh, listfile_path);
+
+ // Remove the directories
+ installed_files_of_current_pgh.erase(
+ std::remove_if(installed_files_of_current_pgh.begin(), installed_files_of_current_pgh.end(), [](const std::string& file) -> bool
+ {
+ return file.back() == '/';
+ }
+ ), installed_files_of_current_pgh.end());
+
+ StatusParagraph_and_associated_files pgh_and_files = { *pgh, ImmutableSortedVector<std::string>::create(std::move(installed_files_of_current_pgh)) };
+ installed_files.push_back(std::move(pgh_and_files));
+ }
+
+ return installed_files;
+ }
+
+ CMakeVariable::CMakeVariable(const std::wstring& varname, const wchar_t* varvalue) : s(Strings::wformat(LR"("-D%s=%s")", varname, varvalue)) { }
+ CMakeVariable::CMakeVariable(const std::wstring& varname, const std::string& varvalue) : CMakeVariable(varname, Strings::utf8_to_utf16(varvalue).c_str()) { }
+ CMakeVariable::CMakeVariable(const std::wstring& varname, const std::wstring& varvalue) : CMakeVariable(varname, varvalue.c_str()) {}
+ CMakeVariable::CMakeVariable(const std::wstring& varname, const fs::path& path) : CMakeVariable(varname, path.generic_wstring()) {}
+
+ std::wstring make_cmake_cmd(const fs::path& cmake_exe, const fs::path& cmake_script, const std::vector<CMakeVariable>& pass_variables)
+ {
+ std::wstring cmd_cmake_pass_variables = Strings::wjoin(L" ", pass_variables, [](auto&& v) { return v.s; });
+ return Strings::wformat(LR"("%s" %s -P "%s")", cmake_exe.native(), cmd_cmake_pass_variables, cmake_script.generic_wstring());
+ }
+}
diff --git a/toolsrc/src/vcpkglib_helpers.cpp b/toolsrc/src/vcpkglib_helpers.cpp
index d104bb19d..6b96c25cb 100644
--- a/toolsrc/src/vcpkglib_helpers.cpp
+++ b/toolsrc/src/vcpkglib_helpers.cpp
@@ -1,9 +1,8 @@
+#include "pch.h"
#include "vcpkg_Checks.h"
#include "vcpkglib_helpers.h"
-#include <unordered_map>
-#include <regex>
-namespace vcpkg {namespace details
+namespace vcpkg::details
{
std::string optional_field(const std::unordered_map<std::string, std::string>& fields, const std::string& fieldname)
{
@@ -53,4 +52,4 @@ namespace vcpkg {namespace details
simple_desc.append("...");
return simple_desc;
}
-}}
+}