diff options
| author | Jan Hrubý <jhruby.web@gmail.com> | 2017-03-13 08:56:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-03-13 08:56:05 +0100 |
| commit | 665f4118f603c5858217ed7a2f2f824b18ff4fc5 (patch) | |
| tree | f0167041edf71e90f2331b5025f603392a8de67a /toolsrc | |
| parent | 1bec0fcb73073b5b1719f454c368a63f1bff625e (diff) | |
| parent | 1c9873a0daf625f67474aaf3e163c592c27ecb65 (diff) | |
| download | vcpkg-665f4118f603c5858217ed7a2f2f824b18ff4fc5.tar.gz vcpkg-665f4118f603c5858217ed7a2f2f824b18ff4fc5.zip | |
Merge pull request #1 from Microsoft/master
pull
Diffstat (limited to 'toolsrc')
119 files changed, 6409 insertions, 2964 deletions
diff --git a/toolsrc/VERSION.txt b/toolsrc/VERSION.txt index f723d10e0..efe1fb7ee 100644 --- a/toolsrc/VERSION.txt +++ b/toolsrc/VERSION.txt @@ -1 +1 @@ -"0.0.30"
\ No newline at end of file +"0.0.76"
\ No newline at end of file diff --git a/toolsrc/dirs.proj b/toolsrc/dirs.proj new file mode 100644 index 000000000..17d9fa1b0 --- /dev/null +++ b/toolsrc/dirs.proj @@ -0,0 +1,20 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir> + </PropertyGroup> + <ItemGroup> + <ProjectFile Include="vcpkg\vcpkg.vcxproj"/> + <ProjectFile Include="vcpkglib\vcpkglib.vcxproj"/> + <ProjectFile Include="vcpkgmetricsuploader\vcpkgmetricsuploader.vcxproj"/> + </ItemGroup> + + <Target Name="Rebuild" DependsOnTargets="Clean;Build" /> + + <Target Name="Build"> + <MSBuild Projects="@(ProjectFile)" Properties="SolutionDir=$(SolutionDir)" Targets="Build"/> + </Target> + + <Target Name="Clean"> + <MSBuild Projects="@(ProjectFile)" Properties="SolutionDir=$(SolutionDir)" Targets="Clean"/> + </Target> +</Project>
\ No newline at end of file diff --git a/toolsrc/include/BinaryParagraph.h b/toolsrc/include/BinaryParagraph.h index 88d6e84b1..3d9cfb9fb 100644 --- a/toolsrc/include/BinaryParagraph.h +++ b/toolsrc/include/BinaryParagraph.h @@ -2,14 +2,14 @@ #include <unordered_map> #include "SourceParagraph.h" -#include "triplet.h" +#include "package_spec.h" namespace vcpkg { struct BinaryParagraph { BinaryParagraph(); - explicit BinaryParagraph(const std::unordered_map<std::string, std::string>& fields); + explicit BinaryParagraph(std::unordered_map<std::string, std::string> fields); BinaryParagraph(const SourceParagraph& spgh, const triplet& target_triplet); std::string displayname() const; @@ -18,11 +18,10 @@ namespace vcpkg std::string dir() const; - std::string name; + package_spec spec; std::string version; std::string description; std::string maintainer; - triplet target_triplet; std::vector<std::string> depends; }; diff --git a/toolsrc/include/ImmutableSortedVector.h b/toolsrc/include/ImmutableSortedVector.h new file mode 100644 index 000000000..681f9fd4d --- /dev/null +++ b/toolsrc/include/ImmutableSortedVector.h @@ -0,0 +1,48 @@ +#pragma once + +#include <vector> +#include <algorithm> + +// Add more forwarding functions to the delegate std::vector as needed. +namespace vcpkg +{ + template <class T> + class ImmutableSortedVector + { + public: + static ImmutableSortedVector<T> create(std::vector<T> vector) + { + ImmutableSortedVector out; + out.delegate = std::move(vector); + if (!std::is_sorted(out.delegate.cbegin(), out.delegate.cend())) + { + std::sort(out.delegate.begin(), out.delegate.end()); + } + + return out; + } + + typename std::vector<T>::const_iterator begin() const + { + return this->delegate.cbegin(); + } + + typename std::vector<T>::const_iterator end() const + { + return this->delegate.cend(); + } + + typename std::vector<T>::const_iterator cbegin() const + { + return this->delegate.cbegin(); + } + + typename std::vector<T>::const_iterator cend() const + { + return this->delegate.cend(); + } + + private: + std::vector<T> delegate; + }; +} diff --git a/toolsrc/include/MachineType.h b/toolsrc/include/MachineType.h new file mode 100644 index 000000000..86efb85c5 --- /dev/null +++ b/toolsrc/include/MachineType.h @@ -0,0 +1,36 @@ +#pragma once +#include <cstdint> + +namespace vcpkg +{ + enum class MachineType : uint16_t + { + UNKNOWN = 0x0, // The contents of this field are assumed to be applicable to any machine type + AM33=0x1d3,//Matsushita AM33 + AMD64=0x8664,//x64 + ARM=0x1c0,//ARM little endian + ARM64=0xaa64,//ARM64 little endian + ARMNT=0x1c4,//ARM Thumb-2 little endian + EBC=0xebc,//EFI byte code + I386=0x14c,//Intel 386 or later processors and compatible processors + IA64=0x200,//Intel Itanium processor family + M32R=0x9041,//Mitsubishi M32R little endian + MIPS16=0x266,//MIPS16 + MIPSFPU=0x366,//MIPS with FPU + MIPSFPU16=0x466,//MIPS16 with FPU + POWERPC=0x1f0,//Power PC little endian + POWERPCFP=0x1f1,//Power PC with floating point support + R4000=0x166,//MIPS little endian + RISCV32=0x5032,//RISC-V 32-bit address space + RISCV64=0x5064,//RISC-V 64-bit address space + RISCV128=0x5128,//RISC-V 128-bit address space + SH3=0x1a2,//Hitachi SH3 + SH3DSP=0x1a3,//Hitachi SH3 DSP + SH4=0x1a6,//Hitachi SH4 + SH5=0x1a8,//Hitachi SH5 + THUMB=0x1c2,//Thumb + WCEMIPSV2=0x169,//MIPS little-endian WCE v2 + }; + + MachineType getMachineType(const uint16_t value); +} diff --git a/toolsrc/include/Paragraphs.h b/toolsrc/include/Paragraphs.h new file mode 100644 index 000000000..79b66a67f --- /dev/null +++ b/toolsrc/include/Paragraphs.h @@ -0,0 +1,21 @@ +#pragma once + +#include "filesystem_fs.h" +#include <map> +#include "expected.h" +#include "BinaryParagraph.h" +#include "vcpkg_paths.h" + +namespace vcpkg::Paragraphs +{ + std::vector<std::unordered_map<std::string, std::string>> get_paragraphs(const fs::path& control_path); + std::vector<std::unordered_map<std::string, std::string>> parse_paragraphs(const std::string& str); + + expected<SourceParagraph> try_load_port(const fs::path& control_path); + + expected<BinaryParagraph> try_load_cached_package(const vcpkg_paths& paths, const package_spec& spec); + + std::vector<SourceParagraph> load_all_ports(const fs::path& ports_dir); + + std::map<std::string, std::string> extract_port_names_and_versions(const std::vector<SourceParagraph>& source_paragraphs); +} diff --git a/toolsrc/include/PostBuildLint.h b/toolsrc/include/PostBuildLint.h new file mode 100644 index 000000000..73c8ec54b --- /dev/null +++ b/toolsrc/include/PostBuildLint.h @@ -0,0 +1,8 @@ +#pragma once +#include "package_spec.h" +#include "vcpkg_paths.h" + +namespace vcpkg::PostBuildLint +{ + size_t perform_all_checks(const package_spec& spec, const vcpkg_paths& paths); +} diff --git a/toolsrc/include/PostBuildLint_BuildInfo.h b/toolsrc/include/PostBuildLint_BuildInfo.h new file mode 100644 index 000000000..bac024e01 --- /dev/null +++ b/toolsrc/include/PostBuildLint_BuildInfo.h @@ -0,0 +1,21 @@ +#pragma once + +#include "filesystem_fs.h" +#include "PostBuildLint_BuildPolicies.h" +#include "opt_bool.h" +#include "PostBuildLint_LinkageType.h" + +namespace vcpkg::PostBuildLint +{ + struct BuildInfo + { + static BuildInfo create(std::unordered_map<std::string, std::string> pgh); + + LinkageType::type crt_linkage; + LinkageType::type library_linkage; + + std::map<BuildPolicies::type, opt_bool_t> policies; + }; + + BuildInfo read_build_info(const fs::path& filepath); +} diff --git a/toolsrc/include/PostBuildLint_BuildPolicies.h b/toolsrc/include/PostBuildLint_BuildPolicies.h new file mode 100644 index 000000000..d815c6d27 --- /dev/null +++ b/toolsrc/include/PostBuildLint_BuildPolicies.h @@ -0,0 +1,38 @@ +#pragma once +#include <string> +#include <array> + +namespace vcpkg::PostBuildLint::BuildPolicies +{ + enum class backing_enum_t + { + NULLVALUE = 0, + EMPTY_PACKAGE, + DLLS_WITHOUT_LIBS, + ONLY_RELEASE_CRT + }; + + struct type + { + constexpr type() : backing_enum(backing_enum_t::NULLVALUE) {} + constexpr explicit type(backing_enum_t backing_enum) : backing_enum(backing_enum) { } + constexpr operator backing_enum_t() const { return backing_enum; } + + const std::string& toString() const; + const std::string& cmake_variable() const; + + private: + backing_enum_t backing_enum; + }; + + static const std::string ENUM_NAME = "vcpkg::PostBuildLint::BuildPolicies"; + + static constexpr type NULLVALUE(backing_enum_t::NULLVALUE); + static constexpr type EMPTY_PACKAGE(backing_enum_t::EMPTY_PACKAGE); + static constexpr type DLLS_WITHOUT_LIBS(backing_enum_t::DLLS_WITHOUT_LIBS); + static constexpr type ONLY_RELEASE_CRT(backing_enum_t::ONLY_RELEASE_CRT); + + static constexpr std::array<type, 3> values = { EMPTY_PACKAGE, DLLS_WITHOUT_LIBS, ONLY_RELEASE_CRT }; + + type parse(const std::string& s); +} diff --git a/toolsrc/include/PostBuildLint_BuildType.h b/toolsrc/include/PostBuildLint_BuildType.h new file mode 100644 index 000000000..31fbb11c9 --- /dev/null +++ b/toolsrc/include/PostBuildLint_BuildType.h @@ -0,0 +1,47 @@ +#pragma once +#include "PostBuildLint_ConfigurationType.h" +#include "PostBuildLint_LinkageType.h" +#include <array> +#include <regex> + +namespace vcpkg::PostBuildLint::BuildType +{ + enum class backing_enum_t + { + DEBUG_STATIC = 1, + DEBUG_DYNAMIC, + RELEASE_STATIC, + RELEASE_DYNAMIC + }; + + struct type + { + type() = delete; + + constexpr explicit type(const backing_enum_t backing_enum, const ConfigurationType::type config, const LinkageType::type linkage) : + backing_enum(backing_enum), m_config(config), m_linkage(linkage) { } + + constexpr operator backing_enum_t() const { return backing_enum; } + + const ConfigurationType::type& config() const; + const LinkageType::type& linkage() const; + const std::regex& crt_regex() const; + const std::string& toString() const; + + private: + backing_enum_t backing_enum; + ConfigurationType::type m_config; + LinkageType::type m_linkage; + }; + + static const std::string ENUM_NAME = "vcpkg::PostBuildLint::BuildType"; + + static constexpr type DEBUG_STATIC = type(backing_enum_t::DEBUG_STATIC, ConfigurationType::DEBUG, LinkageType::STATIC); + static constexpr type DEBUG_DYNAMIC = type(backing_enum_t::DEBUG_DYNAMIC, ConfigurationType::DEBUG, LinkageType::DYNAMIC); + static constexpr type RELEASE_STATIC = type(backing_enum_t::RELEASE_STATIC, ConfigurationType::RELEASE, LinkageType::STATIC); + static constexpr type RELEASE_DYNAMIC = type(backing_enum_t::RELEASE_DYNAMIC, ConfigurationType::RELEASE, LinkageType::DYNAMIC); + + static constexpr std::array<type, 4> values = { DEBUG_STATIC, DEBUG_DYNAMIC, RELEASE_STATIC, RELEASE_DYNAMIC }; + + type value_of(const ConfigurationType::type& config, const LinkageType::type& linkage); +} diff --git a/toolsrc/include/PostBuildLint_ConfigurationType.h b/toolsrc/include/PostBuildLint_ConfigurationType.h new file mode 100644 index 000000000..7245d2932 --- /dev/null +++ b/toolsrc/include/PostBuildLint_ConfigurationType.h @@ -0,0 +1,33 @@ +#pragma once +#pragma once +#include <string> + +namespace vcpkg::PostBuildLint::ConfigurationType +{ + enum class backing_enum_t + { + NULLVALUE = 0, + DEBUG = 1, + RELEASE = 2 + }; + + struct type + { + constexpr type() : backing_enum(backing_enum_t::NULLVALUE) {} + constexpr explicit type(backing_enum_t backing_enum) : backing_enum(backing_enum) { } + constexpr operator backing_enum_t() const { return backing_enum; } + + const std::string& toString() const; + + private: + backing_enum_t backing_enum; + }; + + static const std::string ENUM_NAME = "vcpkg::PostBuildLint::ConfigurationType"; + + static constexpr type NULLVALUE(backing_enum_t::NULLVALUE); + static constexpr type DEBUG(backing_enum_t::DEBUG); + static constexpr type RELEASE(backing_enum_t::RELEASE); + + static constexpr std::array<type, 2> values = { DEBUG, RELEASE }; +} diff --git a/toolsrc/include/PostBuildLint_LinkageType.h b/toolsrc/include/PostBuildLint_LinkageType.h new file mode 100644 index 000000000..0cecc8c9f --- /dev/null +++ b/toolsrc/include/PostBuildLint_LinkageType.h @@ -0,0 +1,34 @@ +#pragma once +#include <string> + +namespace vcpkg::PostBuildLint::LinkageType +{ + enum class backing_enum_t + { + NULLVALUE = 0, + DYNAMIC, + STATIC + }; + + struct type + { + constexpr type() : backing_enum(backing_enum_t::NULLVALUE) {} + constexpr explicit type(backing_enum_t backing_enum) : backing_enum(backing_enum) { } + constexpr operator backing_enum_t() const { return backing_enum; } + + const std::string& toString() const; + + private: + backing_enum_t backing_enum; + }; + + static const std::string ENUM_NAME = "vcpkg::PostBuildLint::LinkageType"; + + static constexpr type NULLVALUE(backing_enum_t::NULLVALUE); + static constexpr type DYNAMIC(backing_enum_t::DYNAMIC); + static constexpr type STATIC(backing_enum_t::STATIC); + + static constexpr std::array<type, 2> values = { DYNAMIC, STATIC }; + + type value_of(const std::string& as_string); +} diff --git a/toolsrc/include/SourceParagraph.h b/toolsrc/include/SourceParagraph.h index 72dca8324..5ae9b38b8 100644 --- a/toolsrc/include/SourceParagraph.h +++ b/toolsrc/include/SourceParagraph.h @@ -5,16 +5,31 @@ namespace vcpkg { + struct triplet; + + struct dependency + { + std::string name; + std::string qualifier; + }; + + std::ostream& operator<<(std::ostream& os, const dependency& p); + struct SourceParagraph { SourceParagraph(); - explicit SourceParagraph(const std::unordered_map<std::string, std::string>& fields); + explicit SourceParagraph(std::unordered_map<std::string, std::string> fields); std::string name; std::string version; std::string description; std::string maintainer; - std::vector<std::string> depends; + std::vector<dependency> depends; }; + + std::vector<std::string> filter_dependencies(const std::vector<vcpkg::dependency>& deps, const triplet& t); + + std::vector<vcpkg::dependency> expand_qualified_dependencies(const std::vector<std::string>& depends); + std::vector<std::string> parse_depends(const std::string& depends_string); } diff --git a/toolsrc/include/StatusParagraphs.h b/toolsrc/include/StatusParagraphs.h index 9446d432c..3c5d35183 100644 --- a/toolsrc/include/StatusParagraphs.h +++ b/toolsrc/include/StatusParagraphs.h @@ -1,6 +1,7 @@ #pragma once #include "StatusParagraph.h" #include <memory> +#include <iterator> namespace vcpkg { @@ -13,30 +14,34 @@ namespace vcpkg using iterator = container::reverse_iterator; using const_iterator = container::const_reverse_iterator; + const_iterator find(const package_spec& spec) const + { + return find(spec.name(), spec.target_triplet()); + } const_iterator find(const std::string& name, const triplet& target_triplet) const; iterator find(const std::string& name, const triplet& target_triplet); - iterator find_installed(const std::string& name, const triplet& target_triplet); + const_iterator find_installed(const std::string& name, const triplet& target_triplet) const; iterator insert(std::unique_ptr<StatusParagraph>); friend std::ostream& operator<<(std::ostream&, const StatusParagraphs&); - auto end() + iterator end() { return paragraphs.rend(); } - auto end() const + const_iterator end() const { return paragraphs.rend(); } - auto begin() + iterator begin() { return paragraphs.rbegin(); } - auto begin() const + const_iterator begin() const { return paragraphs.rbegin(); } diff --git a/toolsrc/include/coff_file_reader.h b/toolsrc/include/coff_file_reader.h new file mode 100644 index 000000000..24fbf4576 --- /dev/null +++ b/toolsrc/include/coff_file_reader.h @@ -0,0 +1,21 @@ +#pragma once +#include <vector> +#include "MachineType.h" +#include "filesystem_fs.h" + +namespace vcpkg::COFFFileReader +{ + struct dll_info + { + MachineType machine_type; + }; + + struct lib_info + { + std::vector<MachineType> machine_types; + }; + + dll_info read_dll(const fs::path& path); + + lib_info read_lib(const fs::path& path); +} diff --git a/toolsrc/include/expected.h b/toolsrc/include/expected.h index affabcc02..cbb513b22 100644 --- a/toolsrc/include/expected.h +++ b/toolsrc/include/expected.h @@ -1,5 +1,6 @@ #pragma once +#include <system_error> #include "vcpkg_Checks.h" namespace vcpkg diff --git a/toolsrc/include/filesystem_fs.h b/toolsrc/include/filesystem_fs.h new file mode 100644 index 000000000..ece485c23 --- /dev/null +++ b/toolsrc/include/filesystem_fs.h @@ -0,0 +1,5 @@ +#pragma once + +#include <filesystem> + +namespace fs = std::tr2::sys;
\ No newline at end of file diff --git a/toolsrc/include/lazy.h b/toolsrc/include/lazy.h new file mode 100644 index 000000000..f9dbd8dc7 --- /dev/null +++ b/toolsrc/include/lazy.h @@ -0,0 +1,26 @@ +#pragma once + +namespace vcpkg +{ + template <typename T> + class lazy + { + public: + lazy() : value(T()), initialized(false) {} + + template <class F> + T const& get_lazy(F& f) const + { + if (!initialized) + { + value = f(); + initialized = true; + } + return value; + } + + private: + mutable T value; + mutable bool initialized; + }; +} diff --git a/toolsrc/include/metrics.h b/toolsrc/include/metrics.h index 52662cd97..a0f4fc61d 100644 --- a/toolsrc/include/metrics.h +++ b/toolsrc/include/metrics.h @@ -13,6 +13,7 @@ namespace vcpkg void TrackProperty(const std::string& name, const std::string& value); void TrackProperty(const std::string& name, const std::wstring& value); bool GetCompiledMetricsEnabled(); + std::wstring GetSQMUser(); void Upload(const std::string& payload); void Flush(); diff --git a/toolsrc/include/opt_bool.h b/toolsrc/include/opt_bool.h index 3856366c8..06642a399 100644 --- a/toolsrc/include/opt_bool.h +++ b/toolsrc/include/opt_bool.h @@ -1,11 +1,33 @@ #pragma once -namespace vcpkg +#include <string> +#include <map> + +namespace vcpkg::opt_bool { - enum class opt_bool + enum class type { - unspecified, - enabled, - disabled + UNSPECIFIED = 0, + ENABLED, + DISABLED }; + + type parse(const std::string& s); + + template <class T> + type from_map(const std::map<T, std::string>& map, const T& key) + { + auto it = map.find(key); + if (it == map.cend()) + { + return type::UNSPECIFIED; + } + + return parse(*it); + } } + +namespace vcpkg +{ + using opt_bool_t = opt_bool::type; +}
\ No newline at end of file diff --git a/toolsrc/include/package_spec.h b/toolsrc/include/package_spec.h index 942b34adc..1bc493756 100644 --- a/toolsrc/include/package_spec.h +++ b/toolsrc/include/package_spec.h @@ -1,5 +1,4 @@ #pragma once -#include <string> #include "package_spec_parse_result.h" #include "triplet.h" #include "expected.h" @@ -8,15 +7,24 @@ namespace vcpkg { struct package_spec { - static expected<package_spec> from_string(const std::string& spec, const triplet& default_target_triplet); + static expected<package_spec> from_string(const std::string& spec_as_string, const triplet& default_target_triplet); - std::string name; - triplet target_triplet; + static expected<package_spec> from_name_and_triplet(const std::string& name, const triplet& target_triplet); + + const std::string& name() const; + + const triplet& target_triplet() const; + + std::string display_name() const; std::string dir() const; - }; - std::string to_string(const package_spec& spec); + std::string toString() const; + + private: + std::string m_name; + triplet m_target_triplet; + }; std::string to_printf_arg(const package_spec& spec); @@ -33,8 +41,8 @@ namespace std size_t operator()(const vcpkg::package_spec& value) const { size_t hash = 17; - hash = hash * 31 + std::hash<std::string>()(value.name); - hash = hash * 31 + std::hash<vcpkg::triplet>()(value.target_triplet); + hash = hash * 31 + std::hash<std::string>()(value.name()); + hash = hash * 31 + std::hash<vcpkg::triplet>()(value.target_triplet()); return hash; } }; diff --git a/toolsrc/include/package_spec_parse_result.h b/toolsrc/include/package_spec_parse_result.h index e59622951..5735c4f4c 100644 --- a/toolsrc/include/package_spec_parse_result.h +++ b/toolsrc/include/package_spec_parse_result.h @@ -5,8 +5,9 @@ namespace vcpkg { enum class package_spec_parse_result { - success = 0, - too_many_colons + SUCCESS = 0, + TOO_MANY_COLONS, + INVALID_CHARACTERS }; struct package_spec_parse_result_category_impl final : std::error_category @@ -30,5 +31,6 @@ namespace std { template <> struct is_error_code_enum<vcpkg::package_spec_parse_result> : ::std::true_type - {}; + { + }; } diff --git a/toolsrc/include/pch.h b/toolsrc/include/pch.h new file mode 100644 index 000000000..e78f17237 --- /dev/null +++ b/toolsrc/include/pch.h @@ -0,0 +1,43 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <Windows.h> +#include <shellapi.h> +#include <Shlobj.h> +#include <winhttp.h> +#include <process.h> + +#include <cassert> +#include <stdexcept> +#include <system_error> + +#include <array> +#include <vector> +#include <set> +#include <map> +#include <unordered_set> +#include <unordered_map> + +#include <string> +#include <regex> + +#include <filesystem> +#include <iostream> +#include <fstream> +#include <memory> +#include <iomanip> + +#include <algorithm> +#include <functional> +#include <iterator> +#include <utility> + +#include <cstdarg> +#include <codecvt> +#include <cctype> +#include <cstdint> + +#include <sys/timeb.h> +#include <time.h> +#include <chrono> diff --git a/toolsrc/include/post_build_lint.h b/toolsrc/include/post_build_lint.h deleted file mode 100644 index bc916a7af..000000000 --- a/toolsrc/include/post_build_lint.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "package_spec.h" -#include "vcpkg_paths.h" - -namespace vcpkg -{ - void perform_all_checks(const package_spec& spec, const vcpkg_paths& paths); -} diff --git a/toolsrc/include/triplet.h b/toolsrc/include/triplet.h index 0c42f2ec7..32ea2e711 100644 --- a/toolsrc/include/triplet.h +++ b/toolsrc/include/triplet.h @@ -4,23 +4,24 @@ namespace vcpkg { - struct vcpkg_paths; - struct triplet { + static triplet from_canonical_name(const std::string& triplet_as_string); + static const triplet X86_WINDOWS; static const triplet X64_WINDOWS; static const triplet X86_UWP; static const triplet X64_UWP; static const triplet ARM_UWP; - std::string value; + const std::string& canonical_name() const; std::string architecture() const; std::string system() const; - bool validate(const vcpkg_paths& paths); + private: + std::string m_canonical_name; }; bool operator==(const triplet& left, const triplet& right); @@ -43,7 +44,7 @@ namespace std { std::hash<std::string> hasher; size_t hash = 17; - hash = hash * 31 + hasher(t.value); + hash = hash * 31 + hasher(t.canonical_name()); return hash; } }; diff --git a/toolsrc/include/vcpkg.h b/toolsrc/include/vcpkg.h deleted file mode 100644 index a4a0682cf..000000000 --- a/toolsrc/include/vcpkg.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <filesystem> -#include <vector> -#include <unordered_map> -#include "package_spec.h" -#include "BinaryParagraph.h" -#include "StatusParagraphs.h" -#include "vcpkg_paths.h" - -namespace vcpkg -{ - namespace fs = std::tr2::sys; - - extern bool g_do_dry_run; - - std::vector<std::unordered_map<std::string, std::string>> get_paragraphs(const fs::path& control_path); - std::vector<std::unordered_map<std::string, std::string>> parse_paragraphs(const std::string& str); - std::string shorten_description(const std::string& desc); - - StatusParagraphs database_load_check(const vcpkg_paths& paths); - - std::vector<std::string> get_unmet_package_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db); - - void install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs& status_db); - void deinstall_package(const vcpkg_paths& paths, const package_spec& spec, StatusParagraphs& status_db); - - void search_file(const vcpkg_paths& paths, const std::string& file_substr, const StatusParagraphs& status_db); - - void binary_import(const vcpkg_paths& paths, const fs::path& include_directory, const fs::path& project_directory, const BinaryParagraph& control_file_data); - - const std::string& version(); -} // namespace vcpkg diff --git a/toolsrc/include/vcpkg_Checks.h b/toolsrc/include/vcpkg_Checks.h index 05bd0e729..23869f35f 100644 --- a/toolsrc/include/vcpkg_Checks.h +++ b/toolsrc/include/vcpkg_Checks.h @@ -2,7 +2,7 @@ #include "vcpkg_Strings.h" -namespace vcpkg {namespace Checks +namespace vcpkg::Checks { __declspec(noreturn) void unreachable(); @@ -20,7 +20,7 @@ namespace vcpkg {namespace Checks template <class...Args> _declspec(noreturn) void throw_with_message(const char* errorMessageTemplate, const Args&... errorMessageArgs) { - throw_with_message(Strings::format(errorMessageTemplate, errorMessageArgs...)); + throw_with_message(Strings::format(errorMessageTemplate, errorMessageArgs...).c_str()); } void check_throw(bool expression, const char* errorMessage); @@ -35,6 +35,8 @@ namespace vcpkg {namespace Checks } } + void check_exit(bool expression); + void check_exit(bool expression, const char* errorMessage); template <class...Args> @@ -46,4 +48,4 @@ namespace vcpkg {namespace Checks exit_with_message(Strings::format(errorMessageTemplate, errorMessageArgs...).c_str()); } } -}} +} diff --git a/toolsrc/include/vcpkg_Chrono.h b/toolsrc/include/vcpkg_Chrono.h new file mode 100644 index 000000000..a9d1bbbed --- /dev/null +++ b/toolsrc/include/vcpkg_Chrono.h @@ -0,0 +1,31 @@ +#pragma once + +#include <chrono> +#include <string> + +namespace vcpkg +{ + class ElapsedTime + { + public: + static ElapsedTime createStarted(); + + constexpr ElapsedTime() : m_startTick() {} + + template <class TimeUnit> + TimeUnit elapsed() const + { + return std::chrono::duration_cast<TimeUnit>(std::chrono::high_resolution_clock::now() - this->m_startTick); + } + + double microseconds() const + { + return elapsed<std::chrono::duration<double, std::micro>>().count(); + } + + std::string toString() const; + + private: + std::chrono::high_resolution_clock::time_point m_startTick; + }; +} diff --git a/toolsrc/include/vcpkg_Commands.h b/toolsrc/include/vcpkg_Commands.h index c706c131c..544dffe72 100644 --- a/toolsrc/include/vcpkg_Commands.h +++ b/toolsrc/include/vcpkg_Commands.h @@ -2,42 +2,139 @@ #include "vcpkg_cmd_arguments.h" #include "vcpkg_paths.h" +#include "StatusParagraphs.h" +#include <array> -namespace vcpkg +namespace vcpkg::Commands { - extern const char*const INTEGRATE_COMMAND_HELPSTRING; + using command_type_a = void(*)(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + using command_type_b = void(*)(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + using command_type_c = void(*)(const vcpkg_cmd_arguments& args); - void print_usage(); - void print_example(const char* command_and_arguments); - void update_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + namespace Build + { + enum class BuildResult + { + NULLVALUE = 0, + SUCCEEDED, + BUILD_FAILED, + POST_BUILD_CHECKS_FAILED, + CASCADED_DUE_TO_MISSING_DEPENDENCIES + }; - void build_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); - void build_external_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); - void install_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); - void remove_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + static constexpr std::array<BuildResult, 4> BuildResult_values = { BuildResult::SUCCEEDED, BuildResult::BUILD_FAILED, BuildResult::POST_BUILD_CHECKS_FAILED, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES }; - void edit_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); - void create_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + const std::string& to_string(const BuildResult build_result); + std::string create_error_message(const BuildResult build_result, const package_spec& spec); + std::string create_user_troubleshooting_message(const package_spec& spec); - void search_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - void list_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - void import_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - void owns_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - void internal_test_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + BuildResult build_package(const SourceParagraph& source_paragraph, const package_spec& spec, const vcpkg_paths& paths, const fs::path& port_dir, const StatusParagraphs& status_db); + void perform_and_exit(const package_spec& spec, const fs::path& port_dir, const std::unordered_set<std::string>& options, const vcpkg_paths& paths); + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + } - void cache_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + namespace BuildExternal + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + } - void integrate_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + namespace Install + { + void install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs* status_db); + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + } - void help_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - void help_topic_valid_triplet(const vcpkg_paths& paths); + namespace CI + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + } - void version_command(const vcpkg_cmd_arguments& args); - void contact_command(const vcpkg_cmd_arguments& args); + namespace Remove + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); + } - using command_type_a = void(*)(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet); - using command_type_b = void(*)(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); - using command_type_c = void(*)(const vcpkg_cmd_arguments& args); + namespace Update + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Create + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Edit + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Search + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace List + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Owns + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Cache + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Import + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Integrate + { + extern const char*const INTEGRATE_COMMAND_HELPSTRING; + + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace PortsDiff + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + } + + namespace Help + { + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths); + + void help_topic_valid_triplet(const vcpkg_paths& paths); + + void print_usage(); + + void print_example(const std::string& command_and_arguments); + + std::string create_example_string(const std::string& command_and_arguments); + } + + namespace Version + { + const std::string& version(); + void perform_and_exit(const vcpkg_cmd_arguments& args); + } + + namespace Contact + { + const std::string& email(); + void perform_and_exit(const vcpkg_cmd_arguments& args); + } + + namespace Hash + { + void perform_and_exit(const vcpkg_cmd_arguments& args); + } template <class T> struct package_name_and_function @@ -51,7 +148,7 @@ namespace vcpkg const std::vector<package_name_and_function<command_type_c>>& get_available_commands_type_c(); template <typename T> - T find_command(const std::string& command_name, const std::vector<package_name_and_function<T>> available_commands) + T find(const std::string& command_name, const std::vector<package_name_and_function<T>> available_commands) { for (const package_name_and_function<T>& cmd : available_commands) { diff --git a/toolsrc/include/vcpkg_Dependencies.h b/toolsrc/include/vcpkg_Dependencies.h index 9dc32fc41..dca824ee9 100644 --- a/toolsrc/include/vcpkg_Dependencies.h +++ b/toolsrc/include/vcpkg_Dependencies.h @@ -2,12 +2,78 @@ #include <vector> #include "package_spec.h" #include "StatusParagraphs.h" -#include <unordered_set> #include "vcpkg_paths.h" +#include "vcpkg_optional.h" -namespace vcpkg {namespace Dependencies +namespace vcpkg::Dependencies { - std::vector<package_spec> create_dependency_ordered_install_plan(const vcpkg_paths& paths, const std::vector<package_spec>& specs, const StatusParagraphs& status_db); + enum class request_type + { + UNKNOWN, + USER_REQUESTED, + AUTO_SELECTED + }; - std::unordered_set<package_spec> find_unmet_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db); -}} + enum class install_plan_type + { + UNKNOWN, + BUILD_AND_INSTALL, + INSTALL, + ALREADY_INSTALLED + }; + + struct install_plan_action + { + install_plan_action(); + install_plan_action(const install_plan_type& plan_type, optional<BinaryParagraph> binary_pgh, optional<SourceParagraph> source_pgh); + install_plan_action(const install_plan_action&) = delete; + install_plan_action(install_plan_action&&) = default; + install_plan_action& operator=(const install_plan_action&) = delete; + install_plan_action& operator=(install_plan_action&&) = default; + + install_plan_type plan_type; + optional<BinaryParagraph> binary_pgh; + optional<SourceParagraph> source_pgh; + }; + + struct package_spec_with_install_plan + { + package_spec_with_install_plan(const package_spec& spec, install_plan_action&& plan); + + package_spec spec; + install_plan_action plan; + }; + + enum class remove_plan_type + { + UNKNOWN, + NOT_INSTALLED, + REMOVE + }; + + struct remove_plan_action + { + remove_plan_action(); + remove_plan_action(const remove_plan_type& plan_type, const request_type& request_type); + remove_plan_action(const remove_plan_action&) = delete; + remove_plan_action(remove_plan_action&&) = default; + remove_plan_action& operator=(const remove_plan_action&) = delete; + remove_plan_action& operator=(remove_plan_action&&) = default; + + + remove_plan_type plan_type; + request_type request_type; + }; + + struct package_spec_with_remove_plan + { + package_spec_with_remove_plan(const package_spec& spec, remove_plan_action&& plan); + + package_spec spec; + remove_plan_action 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::vector<package_spec_with_remove_plan> create_remove_plan(const std::vector<package_spec>& specs, const StatusParagraphs& status_db); +} diff --git a/toolsrc/include/vcpkg_Enums.h b/toolsrc/include/vcpkg_Enums.h new file mode 100644 index 000000000..5c4dc8b06 --- /dev/null +++ b/toolsrc/include/vcpkg_Enums.h @@ -0,0 +1,11 @@ +#pragma once +#include <string> + +namespace vcpkg::Enums +{ + std::string nullvalue_toString(const std::string& enum_name); + + __declspec(noreturn) void nullvalue_used(const std::string& enum_name); + + __declspec(noreturn) void unreachable(const std::string& enum_name); +} diff --git a/toolsrc/include/vcpkg_Environment.h b/toolsrc/include/vcpkg_Environment.h index 877ac7deb..5d12c8f6c 100644 --- a/toolsrc/include/vcpkg_Environment.h +++ b/toolsrc/include/vcpkg_Environment.h @@ -1,17 +1,19 @@ #pragma once #include "vcpkg_paths.h" -namespace vcpkg {namespace Environment +namespace vcpkg::Environment { - void ensure_nuget_on_path(const vcpkg_paths& paths); + const fs::path& get_dumpbin_exe(const vcpkg_paths& paths); - void ensure_git_on_path(const vcpkg_paths& paths); + struct vcvarsall_and_platform_toolset + { + fs::path path; + std::wstring platform_toolset; + }; - void ensure_cmake_on_path(const vcpkg_paths& paths); + const vcvarsall_and_platform_toolset& get_vcvarsall_bat(const vcpkg_paths& paths); - inline void ensure_utilities_on_path(const vcpkg_paths& paths) - { - ensure_cmake_on_path(paths); - ensure_git_on_path(paths); - } -}} + const fs::path& get_ProgramFiles_32_bit(); + + const fs::path& get_ProgramFiles_platform_bitness(); +} diff --git a/toolsrc/include/vcpkg_Files.h b/toolsrc/include/vcpkg_Files.h index 445713965..3f9570946 100644 --- a/toolsrc/include/vcpkg_Files.h +++ b/toolsrc/include/vcpkg_Files.h @@ -1,17 +1,56 @@ #pragma once #include "expected.h" -#include <filesystem> +#include "filesystem_fs.h" +#include <iterator> -namespace vcpkg {namespace Files +namespace vcpkg::Files { static const char* FILESYSTEM_INVALID_CHARACTERS = R"(\/:*?"<>|)"; - void check_is_directory(const std::tr2::sys::path& dirpath); + void check_is_directory(const fs::path& dirpath); - bool has_invalid_chars_for_filesystem(const std::string s); + bool has_invalid_chars_for_filesystem(const std::string& s); - expected<std::string> get_contents(const std::tr2::sys::path& file_path) noexcept; + expected<std::string> read_contents(const fs::path& file_path) noexcept; - std::tr2::sys::path find_file_recursively_up(const std::tr2::sys::path& starting_dir, const std::string& filename); -}} + expected<std::vector<std::string>> read_all_lines(const fs::path& file_path); + + void write_all_lines(const fs::path& file_path, const std::vector<std::string>& lines); + + fs::path find_file_recursively_up(const fs::path& starting_dir, const std::string& filename); + + template <class Pred> + void non_recursive_find_matching_paths_in_dir(const fs::path& dir, const Pred predicate, std::vector<fs::path>* output) + { + std::copy_if(fs::directory_iterator(dir), fs::directory_iterator(), std::back_inserter(*output), predicate); + } + + template <class Pred> + void recursive_find_matching_paths_in_dir(const fs::path& dir, const Pred predicate, std::vector<fs::path>* output) + { + std::copy_if(fs::recursive_directory_iterator(dir), fs::recursive_directory_iterator(), std::back_inserter(*output), predicate); + } + + template <class Pred> + std::vector<fs::path> recursive_find_matching_paths_in_dir(const fs::path& dir, const Pred predicate) + { + std::vector<fs::path> v; + recursive_find_matching_paths_in_dir(dir, predicate, &v); + return v; + } + + void recursive_find_files_with_extension_in_dir(const fs::path& dir, const std::string& extension, std::vector<fs::path>* output); + + std::vector<fs::path> recursive_find_files_with_extension_in_dir(const fs::path& dir, const std::string& extension); + + void recursive_find_all_files_in_dir(const fs::path& dir, std::vector<fs::path>* output); + + std::vector<fs::path> recursive_find_all_files_in_dir(const fs::path& dir); + + void non_recursive_find_all_files_in_dir(const fs::path& dir, std::vector<fs::path>* output); + + std::vector<fs::path> non_recursive_find_all_files_in_dir(const fs::path& dir); + + void print_paths(const std::vector<fs::path>& paths); +} diff --git a/toolsrc/include/vcpkg_Graphs.h b/toolsrc/include/vcpkg_Graphs.h index 81b189f0e..933d9ac67 100644 --- a/toolsrc/include/vcpkg_Graphs.h +++ b/toolsrc/include/vcpkg_Graphs.h @@ -1,8 +1,9 @@ #pragma once #include <unordered_map> +#include <unordered_set> -namespace vcpkg { namespace Graphs +namespace vcpkg::Graphs { enum class ExplorationStatus { @@ -21,7 +22,7 @@ namespace vcpkg { namespace Graphs { static void find_topological_sort_internal(V vertex, ExplorationStatus& status, - const std::unordered_map<V, std::vector<V>>& adjacency_list, + const std::unordered_map<V, std::unordered_set<V>>& adjacency_list, std::unordered_map<V, ExplorationStatus>& exploration_status, std::vector<V>& sorted) { @@ -63,7 +64,7 @@ namespace vcpkg { namespace Graphs void add_edge(V u, V v) { this->vertices[v]; - this->vertices[u].push_back(v); + this->vertices[u].insert(v); } std::vector<V> find_topological_sort() const @@ -108,12 +109,12 @@ namespace vcpkg { namespace Graphs return indegrees; } - const std::unordered_map<V, std::vector<V>>& adjacency_list() const + const std::unordered_map<V, std::unordered_set<V>>& adjacency_list() const { return this->vertices; } private: - std::unordered_map<V, std::vector<V>> vertices; + std::unordered_map<V, std::unordered_set<V>> vertices; }; -}} +} diff --git a/toolsrc/include/vcpkg_Input.h b/toolsrc/include/vcpkg_Input.h new file mode 100644 index 000000000..96cbeecc3 --- /dev/null +++ b/toolsrc/include/vcpkg_Input.h @@ -0,0 +1,15 @@ +#pragma once +#include <vector> +#include "package_spec.h" +#include "vcpkg_paths.h" + +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); + + std::vector<package_spec> check_and_get_package_specs(const std::vector<std::string>& package_specs_as_strings, const triplet& default_target_triplet, const std::string& example_text); + + void check_triplet(const triplet& t, const vcpkg_paths& paths); + + void check_triplets(const std::vector<package_spec>& triplets, const vcpkg_paths& paths); +} diff --git a/toolsrc/include/vcpkg_Maps.h b/toolsrc/include/vcpkg_Maps.h index 5b7b8ed46..5e2f92f55 100644 --- a/toolsrc/include/vcpkg_Maps.h +++ b/toolsrc/include/vcpkg_Maps.h @@ -2,8 +2,9 @@ #include <unordered_map> #include <unordered_set> +#include <map> -namespace vcpkg { namespace Maps +namespace vcpkg::Maps { template <typename K, typename V> std::unordered_set<K> extract_key_set(const std::unordered_map<K, V>& input_map) @@ -15,4 +16,26 @@ namespace vcpkg { namespace Maps } return key_set; } -}} + + template <typename K, typename V> + std::vector<K> extract_keys(const std::unordered_map<K, V>& input_map) + { + std::vector<K> key_set; + for (auto const& element : input_map) + { + key_set.push_back(element.first); + } + return key_set; + } + + template <typename K, typename V> + std::vector<K> extract_keys(const std::map<K, V>& input_map) + { + std::vector<K> key_set; + for (auto const& element : input_map) + { + key_set.push_back(element.first); + } + return key_set; + } +} diff --git a/toolsrc/include/vcpkg_Sets.h b/toolsrc/include/vcpkg_Sets.h index 7b330f31c..ec4800864 100644 --- a/toolsrc/include/vcpkg_Sets.h +++ b/toolsrc/include/vcpkg_Sets.h @@ -3,15 +3,15 @@ #include "vcpkg_Checks.h" #include <unordered_set> -namespace vcpkg { namespace Sets +namespace vcpkg::Sets { template <typename T, typename Container> void remove_all(std::unordered_set<T>* input_set, Container remove_these) { - Checks::check_throw(input_set != nullptr, "Input set cannot be null"); + Checks::check_exit(input_set != nullptr, "Input set cannot be null"); for (const T& r : remove_these) { input_set->erase(r); } } -}} +} diff --git a/toolsrc/include/vcpkg_Strings.h b/toolsrc/include/vcpkg_Strings.h index f4b989292..abf3651e5 100644 --- a/toolsrc/include/vcpkg_Strings.h +++ b/toolsrc/include/vcpkg_Strings.h @@ -1,8 +1,8 @@ #pragma once -#include <string> +#include <vector> -namespace vcpkg {namespace Strings {namespace details +namespace vcpkg::Strings::details { inline const char* to_printf_arg(const std::string& s) { @@ -19,6 +19,21 @@ namespace vcpkg {namespace Strings {namespace details return s; } + inline long long to_printf_arg(const long long s) + { + return s; + } + + inline double to_printf_arg(const double s) + { + return s; + } + + inline size_t to_printf_arg(const size_t s) + { + return s; + } + std::string format_internal(const char* fmtstr, ...); inline const wchar_t* to_wprintf_arg(const std::wstring& s) @@ -31,10 +46,10 @@ namespace vcpkg {namespace Strings {namespace details return s; } - std::wstring format_internal(const wchar_t* fmtstr, ...); -}}} + std::wstring wformat_internal(const wchar_t* fmtstr, ...); +} -namespace vcpkg {namespace Strings +namespace vcpkg::Strings { template <class...Args> std::string format(const char* fmtstr, const Args&...args) @@ -44,15 +59,74 @@ namespace vcpkg {namespace Strings } template <class...Args> - std::wstring format(const wchar_t* fmtstr, const Args&...args) + std::wstring wformat(const wchar_t* fmtstr, const Args&...args) { using vcpkg::Strings::details::to_wprintf_arg; - return details::format_internal(fmtstr, to_wprintf_arg(to_wprintf_arg(args))...); + return details::wformat_internal(fmtstr, to_wprintf_arg(to_wprintf_arg(args))...); } std::wstring utf8_to_utf16(const std::string& s); std::string utf16_to_utf8(const std::wstring& w); - std::string::const_iterator case_insensitive_find(const std::string& s, const std::string& pattern); -}} + std::string::const_iterator case_insensitive_ascii_find(const std::string& s, const std::string& pattern); + + std::string ascii_to_lowercase(const std::string& input); + + template <class T, class Transformer> + std::string join(const std::string& delimiter, const std::vector<T>& v, Transformer transformer) + { + if (v.empty()) + { + return std::string(); + } + + std::string output; + size_t size = v.size(); + + output.append(transformer(v.at(0))); + + for (size_t i = 1; i < size; ++i) + { + output.append(delimiter); + output.append(transformer(v.at(i))); + } + + return output; + } + + std::string join(const std::string& delimiter, const std::vector<std::string>& v); + + template <class T, class Transformer> + std::wstring wjoin(const std::wstring& delimiter, const std::vector<T>& v, Transformer transformer) + { + if (v.empty()) + { + return std::wstring(); + } + + std::wstring output; + size_t size = v.size(); + + output.append(transformer(v.at(0))); + + for (size_t i = 1; i < size; ++i) + { + output.append(delimiter); + output.append(transformer(v.at(i))); + } + + return output; + } + + std::wstring wjoin(const std::wstring& delimiter, const std::vector<std::wstring>& v); + + + void trim(std::string* s); + + std::string trimmed(const std::string& s); + + void trim_all_and_remove_whitespace_strings(std::vector<std::string>* strings); + + std::vector<std::string> split(const std::string& s, const std::string& delimiter); +} diff --git a/toolsrc/include/vcpkg_System.h b/toolsrc/include/vcpkg_System.h index f47fc9aab..71caeed5e 100644 --- a/toolsrc/include/vcpkg_System.h +++ b/toolsrc/include/vcpkg_System.h @@ -1,12 +1,15 @@ #pragma once +#include <Windows.h> #include "vcpkg_Strings.h" +#include "filesystem_fs.h" +#include "vcpkg_optional.h" -#include <filesystem> - -namespace vcpkg {namespace System +namespace vcpkg::System { - std::tr2::sys::path get_exe_path_of_current_process(); + optional<std::wstring> get_registry_string(HKEY base, const wchar_t* subkey, const wchar_t* valuename); + + fs::path get_exe_path_of_current_process(); struct exit_code_and_output { @@ -14,6 +17,13 @@ namespace vcpkg {namespace System std::string output; }; + int cmd_execute_clean(const wchar_t* cmd_line); + + inline int cmd_execute_clean(const std::wstring& cmd_line) + { + return cmd_execute_clean(cmd_line.c_str()); + } + int cmd_execute(const wchar_t* cmd_line); inline int cmd_execute(const std::wstring& cmd_line) @@ -28,6 +38,10 @@ namespace vcpkg {namespace System return cmd_execute_and_capture_output(cmd_line.c_str()); } + std::wstring create_powershell_script_cmd(const fs::path& script_path); + + std::wstring create_powershell_script_cmd(const fs::path& script_path, const std::wstring& args); + enum class color { success = 10, @@ -37,8 +51,28 @@ namespace vcpkg {namespace System void print(const char* message); void println(const char* message); - void print(color c, const char* message); - void println(color c, const char* message); + void print(const color c, const char* message); + void println(const color c, const char* message); + + inline void print(const std::string& message) + { + return print(message.c_str()); + } + + inline void println(const std::string& message) + { + return println(message.c_str()); + } + + inline void print(const color c, const std::string& message) + { + return print(c, message.c_str()); + } + + inline void println(const color c, const std::string& message) + { + return println(c, message.c_str()); + } template <class...Args> void print(const char* messageTemplate, const Args&... messageArgs) @@ -47,7 +81,7 @@ namespace vcpkg {namespace System } template <class...Args> - void print(color c, const char* messageTemplate, const Args&... messageArgs) + void print(const color c, const char* messageTemplate, const Args&... messageArgs) { return print(c, Strings::format(messageTemplate, messageArgs...).c_str()); } @@ -59,19 +93,12 @@ namespace vcpkg {namespace System } template <class...Args> - void println(color c, const char* messageTemplate, const Args&... messageArgs) + void println(const color c, const char* messageTemplate, const Args&... messageArgs) { return println(c, Strings::format(messageTemplate, messageArgs...).c_str()); } - struct Stopwatch - { - int64_t start_time, end_time, freq; - - void start(); - void stop(); - double microseconds() const; - }; + optional<std::wstring> get_environmental_variable(const wchar_t* varname) noexcept; - std::wstring wdupenv_str(const wchar_t* varname) noexcept; -}} + void set_environmental_variable(const wchar_t* varname, const wchar_t* varvalue) noexcept; +} diff --git a/toolsrc/include/vcpkg_cmd_arguments.h b/toolsrc/include/vcpkg_cmd_arguments.h index 7df3d64b1..91f7de8ac 100644 --- a/toolsrc/include/vcpkg_cmd_arguments.h +++ b/toolsrc/include/vcpkg_cmd_arguments.h @@ -4,30 +4,30 @@ #include <vector> #include <unordered_set> #include "opt_bool.h" -#include "package_spec.h" -#include "vcpkg_paths.h" -#include "StatusParagraphs.h" namespace vcpkg { struct vcpkg_cmd_arguments { static vcpkg_cmd_arguments create_from_command_line(const int argc, const wchar_t* const* const argv); - static vcpkg_cmd_arguments create_from_arg_sequence(const std::string* arg_begin, const std::string* arg_end); std::unique_ptr<std::string> vcpkg_root_dir; std::unique_ptr<std::string> target_triplet; - opt_bool debug = opt_bool::unspecified; - opt_bool sendmetrics = opt_bool::unspecified; - opt_bool printmetrics = opt_bool::unspecified; + opt_bool_t debug = opt_bool_t::UNSPECIFIED; + opt_bool_t sendmetrics = opt_bool_t::UNSPECIFIED; + opt_bool_t printmetrics = opt_bool_t::UNSPECIFIED; std::string command; std::vector<std::string> command_arguments; std::unordered_set<std::string> check_and_get_optional_command_arguments(const std::vector<std::string>& valid_options) const; - void check_max_args(size_t arg_count, const char* example_text = nullptr) const; - std::vector<package_spec> parse_all_arguments_as_package_specs(const triplet& default_target_triplet, const char* example_text = nullptr) const; + void check_max_arg_count(const size_t expected_arg_count) const; + void check_max_arg_count(const size_t expected_arg_count, const std::string& example_text) const; + void check_min_arg_count(const size_t expected_arg_count) const; + void check_min_arg_count(const size_t expected_arg_count, const std::string& example_text) const; + void check_exact_arg_count(const size_t expected_arg_count) const; + void check_exact_arg_count(const size_t expected_arg_count, const std::string& example_text) const; private: std::unordered_set<std::string> optional_command_arguments; diff --git a/toolsrc/include/vcpkg_optional.h b/toolsrc/include/vcpkg_optional.h new file mode 100644 index 000000000..7b935bea9 --- /dev/null +++ b/toolsrc/include/vcpkg_optional.h @@ -0,0 +1,5 @@ +#pragma once +#include <memory> + +template<class T> +using optional = std::unique_ptr<T>; diff --git a/toolsrc/include/vcpkg_paths.h b/toolsrc/include/vcpkg_paths.h index 72cba01b7..99fd14905 100644 --- a/toolsrc/include/vcpkg_paths.h +++ b/toolsrc/include/vcpkg_paths.h @@ -1,35 +1,49 @@ #pragma once -#include <filesystem> +#include "filesystem_fs.h" #include "expected.h" #include "package_spec.h" +#include "BinaryParagraph.h" +#include "lazy.h" namespace vcpkg { - namespace fs = std::tr2::sys; - struct vcpkg_paths { - static expected<vcpkg_paths> create(const std::tr2::sys::path& vcpkg_root_dir); + static expected<vcpkg_paths> create(const fs::path& vcpkg_root_dir); fs::path package_dir(const package_spec& spec) const; fs::path port_dir(const package_spec& spec) const; + fs::path build_info_file_path(const package_spec& spec) const; + fs::path listfile_path(const BinaryParagraph& pgh) const; + + bool is_valid_triplet(const triplet& t) const; + + fs::path root; + fs::path packages; + fs::path buildtrees; + fs::path downloads; + fs::path ports; + fs::path installed; + fs::path triplets; + fs::path scripts; + + fs::path buildsystems; + fs::path buildsystems_msbuild_targets; - std::tr2::sys::path root; - std::tr2::sys::path packages; - std::tr2::sys::path buildtrees; - std::tr2::sys::path downloads; - std::tr2::sys::path ports; - std::tr2::sys::path installed; - std::tr2::sys::path triplets; + fs::path vcpkg_dir; + fs::path vcpkg_dir_status_file; + fs::path vcpkg_dir_info; + fs::path vcpkg_dir_updates; - std::tr2::sys::path buildsystems; - std::tr2::sys::path buildsystems_msbuild_targets; + fs::path ports_cmake; - std::tr2::sys::path vcpkg_dir; - std::tr2::sys::path vcpkg_dir_status_file; - std::tr2::sys::path vcpkg_dir_info; - std::tr2::sys::path vcpkg_dir_updates; + const fs::path& get_cmake_exe() const; + const fs::path& get_git_exe() const; + const fs::path& get_nuget_exe() const; - std::tr2::sys::path ports_cmake; + private: + lazy<fs::path> cmake_exe; + lazy<fs::path> git_exe; + lazy<fs::path> nuget_exe; }; } diff --git a/toolsrc/include/vcpkglib.h b/toolsrc/include/vcpkglib.h new file mode 100644 index 000000000..353bfb0a0 --- /dev/null +++ b/toolsrc/include/vcpkglib.h @@ -0,0 +1,34 @@ +#pragma once + +#include "StatusParagraphs.h" +#include "vcpkg_paths.h" +#include "ImmutableSortedVector.h" + +namespace vcpkg +{ + StatusParagraphs database_load_check(const vcpkg_paths& paths); + + void write_update(const vcpkg_paths& paths, const StatusParagraph& p); + + struct StatusParagraph_and_associated_files + { + StatusParagraph pgh; + ImmutableSortedVector<std::string> files; + }; + + std::vector<StatusParagraph_and_associated_files> get_installed_files(const vcpkg_paths& paths, const StatusParagraphs& status_db); + + + struct CMakeVariable + { + CMakeVariable(const std::wstring& varname, const wchar_t* varvalue); + CMakeVariable(const std::wstring& varname, const std::string& varvalue); + CMakeVariable(const std::wstring& varname, const std::wstring& varvalue); + CMakeVariable(const std::wstring& varname, const fs::path& path); + + std::wstring s; + }; + + std::wstring make_cmake_cmd(const fs::path& cmake_exe, const fs::path& cmake_script, const std::vector<CMakeVariable>& pass_variables); + +} // namespace vcpkg diff --git a/toolsrc/include/vcpkglib_helpers.h b/toolsrc/include/vcpkglib_helpers.h index e15b59b0b..8a08513f3 100644 --- a/toolsrc/include/vcpkglib_helpers.h +++ b/toolsrc/include/vcpkglib_helpers.h @@ -2,11 +2,13 @@ #include <unordered_map> -namespace vcpkg {namespace details +namespace vcpkg::details { - void optional_field(const std::unordered_map<std::string, std::string>& fields, std::string& out, const std::string& fieldname); + std::string optional_field(const std::unordered_map<std::string, std::string>& fields, const std::string& fieldname); + std::string remove_optional_field(std::unordered_map<std::string, std::string>* fields, const std::string& fieldname); - void required_field(const std::unordered_map<std::string, std::string>& fields, std::string& out, const std::string& fieldname); + std::string required_field(const std::unordered_map<std::string, std::string>& fields, const std::string& fieldname); + std::string remove_required_field(std::unordered_map<std::string, std::string>* fields, const std::string& fieldname); - void parse_depends(const std::string& depends_string, std::vector<std::string>& out); -}} + std::string shorten_description(const std::string& desc); +} diff --git a/toolsrc/src/BinaryParagraph.cpp b/toolsrc/src/BinaryParagraph.cpp index 274bd879e..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" @@ -6,57 +7,70 @@ using namespace vcpkg::details; namespace vcpkg { + // + namespace BinaryParagraphRequiredField + { + static const std::string PACKAGE = "Package"; + static const std::string VERSION = "Version"; + static const std::string ARCHITECTURE = "Architecture"; + static const std::string MULTI_ARCH = "Multi-Arch"; + } + + namespace BinaryParagraphOptionalField + { + static const std::string DESCRIPTION = "Description"; + static const std::string MAINTAINER = "Maintainer"; + static const std::string DEPENDS = "Depends"; + } + BinaryParagraph::BinaryParagraph() = default; - BinaryParagraph::BinaryParagraph(const std::unordered_map<std::string, std::string>& fields) + BinaryParagraph::BinaryParagraph(std::unordered_map<std::string, std::string> fields) { - details::required_field(fields, name, "Package"); - required_field(fields, version, "Version"); - required_field(fields, target_triplet.value, "Architecture"); - { - std::string multi_arch; - required_field(fields, multi_arch, "Multi-Arch"); - Checks::check_throw(multi_arch == "same", "Multi-Arch must be 'same' but was %s", multi_arch); - } - optional_field(fields, description, "Description"); - std::string deps; - optional_field(fields, deps, "Depends"); - if (!deps.empty()) - { - depends.clear(); - parse_depends(deps, depends); - } - optional_field(fields, maintainer, "Maintainer"); + const std::string name = details::remove_required_field(&fields, BinaryParagraphRequiredField::PACKAGE); + const std::string architecture = details::remove_required_field(&fields, BinaryParagraphRequiredField::ARCHITECTURE); + const triplet target_triplet = triplet::from_canonical_name(architecture); + + this->spec = package_spec::from_name_and_triplet(name, target_triplet).get_or_throw(); + this->version = details::remove_required_field(&fields, BinaryParagraphRequiredField::VERSION); + + this->description = details::remove_optional_field(&fields, BinaryParagraphOptionalField::DESCRIPTION); + this->maintainer = details::remove_optional_field(&fields, BinaryParagraphOptionalField::MAINTAINER); + + std::string multi_arch = details::remove_required_field(&fields, BinaryParagraphRequiredField::MULTI_ARCH); + Checks::check_exit(multi_arch == "same", "Multi-Arch must be 'same' but was %s", multi_arch); + + std::string deps = details::remove_optional_field(&fields, BinaryParagraphOptionalField::DEPENDS); + this->depends = parse_depends(deps); } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const triplet& target_triplet) { - this->name = spgh.name; + this->spec = package_spec::from_name_and_triplet(spgh.name, target_triplet).get_or_throw(); this->version = spgh.version; this->description = spgh.description; this->maintainer = spgh.maintainer; - this->depends = spgh.depends; - this->target_triplet = target_triplet; + this->depends = filter_dependencies(spgh.depends, target_triplet); } std::string BinaryParagraph::displayname() const { - return Strings::format("%s:%s", this->name, this->target_triplet); + return this->spec.display_name(); } std::string BinaryParagraph::dir() const { - return Strings::format("%s_%s", this->name, this->target_triplet); + return this->spec.dir(); } std::string BinaryParagraph::fullstem() const { - return Strings::format("%s_%s_%s", this->name, this->version, this->target_triplet); + return Strings::format("%s_%s_%s", this->spec.name(), this->version, this->spec.target_triplet()); } std::ostream& operator<<(std::ostream& os, const BinaryParagraph& p) { - os << "Package: " << p.name << "\n"; + os << "Package: " << p.spec.name() << "\n"; os << "Version: " << p.version << "\n"; if (!p.depends.empty()) { @@ -71,7 +85,7 @@ namespace vcpkg os << "\n"; } - os << "Architecture: " << p.target_triplet << "\n"; + os << "Architecture: " << p.spec.target_triplet() << "\n"; os << "Multi-Arch: same\n"; if (!p.maintainer.empty()) os << "Maintainer: " << p.maintainer << "\n"; 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 new file mode 100644 index 000000000..cb90ed1ec --- /dev/null +++ b/toolsrc/src/Paragraphs.cpp @@ -0,0 +1,227 @@ +#include "pch.h" +#include "Paragraphs.h" +#include "vcpkg_Files.h" + +namespace vcpkg::Paragraphs +{ + struct Parser + { + Parser(const char* c, const char* e) : cur(c), end(e) { } + + private: + const char* cur; + const char* const end; + + void peek(char& ch) const + { + if (cur == end) + ch = 0; + else + ch = *cur; + } + + void next(char& ch) + { + if (cur == end) + ch = 0; + else + { + ++cur; + peek(ch); + } + } + + void skip_spaces(char& ch) + { + while (ch == ' ' || ch == '\t') + next(ch); + } + + static bool is_alphanum(char ch) + { + return (ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9'); + } + + static bool is_lineend(char ch) + { + return ch == '\r' || ch == '\n' || ch == 0; + } + + void get_fieldvalue(char& ch, std::string& fieldvalue) + { + fieldvalue.clear(); + + auto beginning_of_line = cur; + do + { + // scan to end of current line (it is part of the field value) + while (!is_lineend(ch)) + next(ch); + + fieldvalue.append(beginning_of_line, cur); + + if (ch == '\r') + next(ch); + if (ch == '\n') + next(ch); + + if (is_alphanum(ch)) + { + // Line begins a new field. + return; + } + + beginning_of_line = cur; + + // Line may continue the current field with data or terminate the paragraph, + // depending on first nonspace character. + skip_spaces(ch); + + if (is_lineend(ch)) + { + // Line was whitespace or empty. + // This terminates the field and the paragraph. + // We leave the blank line's whitespace consumed, because it doesn't matter. + return; + } + + // First nonspace is not a newline. This continues the current field value. + // We forcibly convert all newlines into single '\n' for ease of text handling later on. + fieldvalue.push_back('\n'); + } + while (true); + } + + void get_fieldname(char& ch, std::string& fieldname) + { + auto begin_fieldname = cur; + while (is_alphanum(ch) || ch == '-') + next(ch); + Checks::check_exit(ch == ':', "Expected ':'"); + fieldname = std::string(begin_fieldname, cur); + + // skip ': ' + next(ch); + skip_spaces(ch); + } + + void get_paragraph(char& ch, std::unordered_map<std::string, std::string>& fields) + { + fields.clear(); + std::string fieldname; + std::string fieldvalue; + do + { + get_fieldname(ch, fieldname); + + auto it = fields.find(fieldname); + Checks::check_exit(it == fields.end(), "Duplicate field"); + + get_fieldvalue(ch, fieldvalue); + + fields.emplace(fieldname, fieldvalue); + } + while (!is_lineend(ch)); + } + + public: + std::vector<std::unordered_map<std::string, std::string>> get_paragraphs() + { + std::vector<std::unordered_map<std::string, std::string>> paragraphs; + + char ch; + peek(ch); + + while (ch != 0) + { + if (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t') + { + next(ch); + continue; + } + + paragraphs.emplace_back(); + get_paragraph(ch, paragraphs.back()); + } + + return paragraphs; + } + }; + + std::vector<std::unordered_map<std::string, std::string>> get_paragraphs(const fs::path& control_path) + { + 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/PostBuildLint.cpp b/toolsrc/src/PostBuildLint.cpp new file mode 100644 index 000000000..8abf71bb3 --- /dev/null +++ b/toolsrc/src/PostBuildLint.cpp @@ -0,0 +1,719 @@ +#include "pch.h" +#include "vcpkg_paths.h" +#include "package_spec.h" +#include "vcpkg_Files.h" +#include "vcpkg_System.h" +#include "vcpkg_Environment.h" +#include "coff_file_reader.h" +#include "PostBuildLint_BuildInfo.h" +#include "PostBuildLint_BuildType.h" + +namespace vcpkg::PostBuildLint +{ + enum class lint_status + { + SUCCESS = 0, + ERROR_DETECTED = 1 + }; + + 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) + { + const fs::path include_dir = package_dir / "include"; + if (!fs::exists(include_dir) || fs::is_empty(include_dir)) + { + System::println(System::color::warning, "The folder /include is empty. This indicates the library was not correctly installed."); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_for_files_in_debug_include_directory(const fs::path& package_dir) + { + const fs::path debug_include_dir = package_dir / "debug" / "include"; + std::vector<fs::path> files_found; + + Files::recursive_find_matching_paths_in_dir(debug_include_dir, [&](const fs::path& current) + { + return !fs::is_directory(current) && current.extension() != ".ifc"; + }, &files_found); + + if (!files_found.empty()) + { + System::println(System::color::warning, "Include files should not be duplicated into the /debug/include directory. If this cannot be disabled in the project cmake, use\n" + " file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include)" + ); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_for_files_in_debug_share_directory(const fs::path& package_dir) + { + const fs::path debug_share = package_dir / "debug" / "share"; + + if (fs::exists(debug_share) && !fs::is_empty(debug_share)) + { + System::println(System::color::warning, "No files should be present in /debug/share"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_folder_lib_cmake(const fs::path& package_dir) + { + const fs::path lib_cmake = package_dir / "lib" / "cmake"; + if (fs::exists(lib_cmake)) + { + System::println(System::color::warning, "The /lib/cmake folder should be moved to just /cmake"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_for_misplaced_cmake_files(const fs::path& package_dir, const package_spec& spec) + { + std::vector<fs::path> misplaced_cmake_files; + Files::recursive_find_files_with_extension_in_dir(package_dir / "cmake", ".cmake", &misplaced_cmake_files); + Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "cmake", ".cmake", &misplaced_cmake_files); + Files::recursive_find_files_with_extension_in_dir(package_dir / "lib" / "cmake", ".cmake", &misplaced_cmake_files); + Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "lib" / "cmake", ".cmake", &misplaced_cmake_files); + + if (!misplaced_cmake_files.empty()) + { + System::println(System::color::warning, "The following cmake files were found outside /share/%s. Please place cmake files in /share/%s.", spec.name(), spec.name()); + Files::print_paths(misplaced_cmake_files); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_folder_debug_lib_cmake(const fs::path& package_dir) + { + const fs::path lib_cmake_debug = package_dir / "debug" / "lib" / "cmake"; + if (fs::exists(lib_cmake_debug)) + { + System::println(System::color::warning, "The /debug/lib/cmake folder should be moved to just /debug/cmake"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_for_dlls_in_lib_dirs(const fs::path& package_dir) + { + std::vector<fs::path> dlls; + Files::recursive_find_files_with_extension_in_dir(package_dir / "lib", ".dll", &dlls); + Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "lib", ".dll", &dlls); + + if (!dlls.empty()) + { + System::println(System::color::warning, "\nThe following dlls were found in /lib and /debug/lib. Please move them to /bin or /debug/bin, respectively."); + Files::print_paths(dlls); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_for_copyright_file(const package_spec& spec, const vcpkg_paths& paths) + { + const fs::path packages_dir = paths.packages / spec.dir(); + const fs::path copyright_file = packages_dir / "share" / spec.name() / "copyright"; + if (fs::exists(copyright_file)) + { + return lint_status::SUCCESS; + } + const fs::path current_buildtrees_dir = paths.buildtrees / spec.name(); + const fs::path current_buildtrees_dir_src = current_buildtrees_dir / "src"; + + std::vector<fs::path> potential_copyright_files; + // Only searching one level deep + for (auto it = fs::recursive_directory_iterator(current_buildtrees_dir_src); it != fs::recursive_directory_iterator(); ++it) + { + if (it.depth() > 1) + { + continue; + } + + const std::string filename = it->path().filename().string(); + if (filename == "LICENSE" || filename == "LICENSE.txt" || filename == "COPYING") + { + potential_copyright_files.push_back(it->path()); + } + } + + System::println(System::color::warning, "The software license must be available at ${CURRENT_PACKAGES_DIR}/share/%s/copyright .", spec.name()); + if (potential_copyright_files.size() == 1) // if there is only one candidate, provide the cmake lines needed to place it in the proper location + { + const fs::path found_file = potential_copyright_files[0]; + const fs::path relative_path = found_file.string().erase(0, current_buildtrees_dir.string().size() + 1); // The +1 is needed to remove the "/" + System::println("\n file(COPY ${CURRENT_BUILDTREES_DIR}/%s DESTINATION ${CURRENT_PACKAGES_DIR}/share/%s)\n" + " file(RENAME ${CURRENT_PACKAGES_DIR}/share/%s/%s ${CURRENT_PACKAGES_DIR}/share/%s/copyright)", + relative_path.generic_string(), spec.name(), spec.name(), found_file.filename().generic_string(), spec.name()); + return lint_status::ERROR_DETECTED; + } + + if (potential_copyright_files.size() > 1) + { + System::println(System::color::warning, "The following files are potential copyright files:"); + Files::print_paths(potential_copyright_files); + } + + System::println(" %s/share/%s/copyright", packages_dir.generic_string(), spec.name()); + return lint_status::ERROR_DETECTED; + } + + static lint_status check_for_exes(const fs::path& package_dir) + { + std::vector<fs::path> exes; + Files::recursive_find_files_with_extension_in_dir(package_dir / "bin", ".exe", &exes); + Files::recursive_find_files_with_extension_in_dir(package_dir / "debug" / "bin", ".exe", &exes); + + if (!exes.empty()) + { + System::println(System::color::warning, "The following EXEs were found in /bin and /debug/bin. EXEs are not valid distribution targets."); + Files::print_paths(exes); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + 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()); + 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)); + + if (ec_data.output.find("ordinal hint RVA name") == std::string::npos) + { + dlls_with_no_exports.push_back(dll); + } + } + + if (!dlls_with_no_exports.empty()) + { + System::println(System::color::warning, "The following DLLs have no exports:"); + Files::print_paths(dlls_with_no_exports); + System::println(System::color::warning, "DLLs without any exports are likely a bug in the build script."); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + 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") + { + return lint_status::SUCCESS; + } + + 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()); + 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)); + + if (ec_data.output.find("App Container") == std::string::npos) + { + dlls_with_improper_uwp_bit.push_back(dll); + } + } + + if (!dlls_with_improper_uwp_bit.empty()) + { + System::println(System::color::warning, "The following DLLs do not have the App Container bit set:"); + Files::print_paths(dlls_with_improper_uwp_bit); + System::println(System::color::warning, "This bit is required for Windows Store apps."); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + struct file_and_arch + { + fs::path file; + std::string actual_arch; + }; + + static std::string get_actual_architecture(const MachineType& machine_type) + { + switch (machine_type) + { + case MachineType::AMD64: + case MachineType::IA64: + return "x64"; + case MachineType::I386: + return "x86"; + case MachineType::ARM: + case MachineType::ARMNT: + return "arm"; + default: + return "Machine Type Code = " + std::to_string(static_cast<uint16_t>(machine_type)); + } + } + + static void print_invalid_architecture_files(const std::string& expected_architecture, std::vector<file_and_arch> binaries_with_invalid_architecture) + { + System::println(System::color::warning, "The following files were built for an incorrect architecture:"); + System::println(""); + for (const file_and_arch& b : binaries_with_invalid_architecture) + { + System::println(" %s", b.file.generic_string()); + System::println("Expected %s, but was: %s", expected_architecture, b.actual_arch); + System::println(""); + } + } + + static lint_status check_dll_architecture(const std::string& expected_architecture, const std::vector<fs::path>& files) + { + std::vector<file_and_arch> binaries_with_invalid_architecture; + + for (const fs::path& file : files) + { + Checks::check_exit(file.extension() == ".dll", "The file extension was not .dll: %s", file.generic_string()); + COFFFileReader::dll_info info = COFFFileReader::read_dll(file); + const std::string actual_architecture = get_actual_architecture(info.machine_type); + + if (expected_architecture != actual_architecture) + { + binaries_with_invalid_architecture.push_back({ file, actual_architecture }); + } + } + + if (!binaries_with_invalid_architecture.empty()) + { + print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_lib_architecture(const std::string& expected_architecture, const std::vector<fs::path>& files) + { + std::vector<file_and_arch> binaries_with_invalid_architecture; + + for (const fs::path& file : files) + { + Checks::check_exit(file.extension() == ".lib", "The file extension was not .lib: %s", file.generic_string()); + COFFFileReader::lib_info info = COFFFileReader::read_lib(file); + Checks::check_exit(info.machine_types.size() == 1, "Found more than 1 architecture in file %s", file.generic_string()); + + 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 }); + } + } + + if (!binaries_with_invalid_architecture.empty()) + { + print_invalid_architecture_files(expected_architecture, binaries_with_invalid_architecture); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_no_dlls_present(const std::vector<fs::path>& dlls) + { + if (dlls.empty()) + { + return lint_status::SUCCESS; + } + + System::println(System::color::warning, "DLLs should not be present in a static build, but the following DLLs were found:"); + Files::print_paths(dlls); + return lint_status::ERROR_DETECTED; + } + + static lint_status check_matching_debug_and_release_binaries(const std::vector<fs::path>& debug_binaries, const std::vector<fs::path>& release_binaries) + { + const size_t debug_count = debug_binaries.size(); + const size_t release_count = release_binaries.size(); + if (debug_count == release_count) + { + return lint_status::SUCCESS; + } + + System::println(System::color::warning, "Mismatching number of debug and release binaries. Found %d for debug but %d for release.", debug_count, release_count); + System::println("Debug binaries"); + Files::print_paths(debug_binaries); + + System::println("Release binaries"); + Files::print_paths(release_binaries); + + if (debug_count == 0) + { + System::println(System::color::warning, "Debug binaries were not found"); + } + if (release_count == 0) + { + System::println(System::color::warning, "Release binaries were not found"); + } + + System::println(""); + + return lint_status::ERROR_DETECTED; + } + + 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) + { + auto it = policies.find(BuildPolicies::DLLS_WITHOUT_LIBS); + if (it != policies.cend() && it->second == opt_bool_t::DISABLED) + { + return lint_status::SUCCESS; + } + + if (lib_count == 0 && dll_count != 0) + { + 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; + } + + return lint_status::SUCCESS; + } + + static lint_status check_bin_folders_are_not_present_in_static_build(const fs::path& package_dir) + { + const fs::path bin = package_dir / "bin"; + const fs::path debug_bin = package_dir / "debug" / "bin"; + + if (!fs::exists(bin) && !fs::exists(debug_bin)) + { + return lint_status::SUCCESS; + } + + if (fs::exists(bin)) + { + System::println(System::color::warning, R"(There should be no bin\ directory in a static build, but %s is present.)", bin.generic_string()); + } + + if (fs::exists(debug_bin)) + { + System::println(System::color::warning, R"(There should be no debug\bin\ directory in a static build, but %s is present.)", debug_bin.generic_string()); + } + + System::println(System::color::warning, R"(If the creation of bin\ and/or debug\bin\ cannot be disabled, use this in the portfile to remove them)" "\n" + "\n" + R"###( if(VCPKG_LIBRARY_LINKAGE STREQUAL static))###""\n" + R"###( file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/bin ${CURRENT_PACKAGES_DIR}/debug/bin))###""\n" + R"###( endif())###" + "\n" + ); + + return lint_status::ERROR_DETECTED; + } + + static lint_status check_no_empty_folders(const fs::path& dir) + { + const std::vector<fs::path> empty_directories = Files::recursive_find_matching_paths_in_dir(dir, [](const fs::path& current) + { + return fs::is_directory(current) && fs::is_empty(current); + }); + + if (!empty_directories.empty()) + { + System::println(System::color::warning, "There should be no empty directories in %s", dir.generic_string()); + 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" + "\n" + R"###( file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/a/dir ${CURRENT_PACKAGES_DIR}/some/other/dir))###""\n" + "\n"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + struct BuildType_and_file + { + fs::path file; + BuildType::type build_type; + }; + + 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::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()); + 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::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 }); + break; + } + } + } + + if (!libs_with_invalid_crt.empty()) + { + System::println(System::color::warning, "Expected %s crt linkage, but the following libs had invalid crt linkage:", expected_build_type.toString()); + System::println(""); + for (const BuildType_and_file btf : libs_with_invalid_crt) + { + System::println(" %s: %s", btf.file.generic_string(), btf.build_type.toString()); + } + System::println(""); + + System::println(System::color::warning, "To inspect the lib files, use:\n dumpbin.exe /directives mylibfile.lib"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + struct OutdatedDynamicCrt_and_file + { + 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, const fs::path dumpbin_exe) + { + 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()); + 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.regex)) + { + dlls_with_outdated_crt.push_back({ dll, outdated_crt }); + break; + } + } + } + + if (!dlls_with_outdated_crt.empty()) + { + System::println(System::color::warning, "Detected outdated dynamic CRT in the following files:"); + System::println(""); + for (const OutdatedDynamicCrt_and_file btf : dlls_with_outdated_crt) + { + System::println(" %s: %s", btf.file.generic_string(), btf.outdated_crt.name); + } + System::println(""); + + System::println(System::color::warning, "To inspect the dll files, use:\n dumpbin.exe /dependents mydllfile.dll"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static lint_status check_no_files_in_package_dir_and_debug_dir(const fs::path& package_dir) + { + std::vector<fs::path> misplaced_files; + + Files::non_recursive_find_matching_paths_in_dir(package_dir, [](const fs::path& current) + { + const std::string filename = current.filename().generic_string(); + return !fs::is_directory(current) && !((_stricmp(filename.c_str(), "CONTROL") == 0 || _stricmp(filename.c_str(), "BUILD_INFO") == 0)); + }, &misplaced_files); + + const fs::path debug_dir = package_dir / "debug"; + Files::non_recursive_find_all_files_in_dir(debug_dir, &misplaced_files); + + if (!misplaced_files.empty()) + { + System::println(System::color::warning, "The following files are placed in\n%s and\n%s: ", package_dir.generic_string(), debug_dir.generic_string()); + Files::print_paths(misplaced_files); + System::println(System::color::warning, "Files cannot be present in those directories.\n"); + return lint_status::ERROR_DETECTED; + } + + return lint_status::SUCCESS; + } + + static void operator +=(size_t& left, const lint_status& right) + { + left += static_cast<size_t>(right); + } + + template <class T> + static bool contains_and_enabled(const std::map<T, opt_bool_t> map, const T& key) + { + 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); + error_count += check_folder_lib_cmake(package_dir); + error_count += check_for_misplaced_cmake_files(package_dir, spec); + error_count += check_folder_debug_lib_cmake(package_dir); + error_count += check_for_dlls_in_lib_dirs(package_dir); + error_count += check_for_copyright_file(spec, paths); + error_count += check_for_exes(package_dir); + + const fs::path debug_lib_dir = package_dir / "debug" / "lib"; + const fs::path release_lib_dir = package_dir / "lib"; + const fs::path debug_bin_dir = package_dir / "debug" / "bin"; + const fs::path release_bin_dir = package_dir / "bin"; + + const std::vector<fs::path> debug_libs = Files::recursive_find_files_with_extension_in_dir(debug_lib_dir, ".lib"); + const std::vector<fs::path> release_libs = Files::recursive_find_files_with_extension_in_dir(release_lib_dir, ".lib"); + + error_count += check_matching_debug_and_release_binaries(debug_libs, release_libs); + + std::vector<fs::path> libs; + libs.insert(libs.cend(), debug_libs.cbegin(), debug_libs.cend()); + libs.insert(libs.cend(), release_libs.cbegin(), release_libs.cend()); + + error_count += check_lib_architecture(spec.target_triplet().architecture(), libs); + + switch (build_info.library_linkage) + { + 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(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, 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, dumpbin_exe); + break; + } + case LinkageType::backing_enum_t::STATIC: + { + std::vector<fs::path> dlls; + Files::recursive_find_files_with_extension_in_dir(package_dir, ".dll", &dlls); + error_count += check_no_dlls_present(dlls); + + error_count += check_bin_folders_are_not_present_in_static_build(package_dir); + + 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(); + } + + 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()); + } + + 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 7e3b0403e..4d144191f 100644 --- a/toolsrc/src/SourceParagraph.cpp +++ b/toolsrc/src/SourceParagraph.cpp @@ -1,21 +1,145 @@ +#include "pch.h" #include "SourceParagraph.h" #include "vcpkglib_helpers.h" +#include "vcpkg_System.h" +#include "vcpkg_Maps.h" +#include "triplet.h" -using namespace vcpkg::details; +namespace vcpkg +{ + // + namespace SourceParagraphRequiredField + { + static const std::string SOURCE = "Source"; + static const std::string VERSION = "Version"; + } -vcpkg::SourceParagraph::SourceParagraph() = default; + namespace SourceParagraphOptionalField + { + static const std::string DESCRIPTION = "Description"; + static const std::string MAINTAINER = "Maintainer"; + static const std::string BUILD_DEPENDS = "Build-Depends"; + } -vcpkg::SourceParagraph::SourceParagraph(const std::unordered_map<std::string, std::string>& fields) -{ - required_field(fields, name, "Source"); - required_field(fields, version, "Version"); - optional_field(fields, description, "Description"); - std::string deps; - optional_field(fields, deps, "Build-Depends"); - if (!deps.empty()) + static const std::vector<std::string>& get_list_of_valid_fields() + { + static const std::vector<std::string> valid_fields = + { + SourceParagraphRequiredField::SOURCE, + SourceParagraphRequiredField::VERSION, + + SourceParagraphOptionalField::DESCRIPTION, + SourceParagraphOptionalField::MAINTAINER, + SourceParagraphOptionalField::BUILD_DEPENDS + }; + + return valid_fields; + } + + SourceParagraph::SourceParagraph() = default; + + SourceParagraph::SourceParagraph(std::unordered_map<std::string, std::string> fields) + { + this->name = details::remove_required_field(&fields, SourceParagraphRequiredField::SOURCE); + this->version = details::remove_required_field(&fields, SourceParagraphRequiredField::VERSION); + this->description = details::remove_optional_field(&fields, SourceParagraphOptionalField::DESCRIPTION); + this->maintainer = details::remove_optional_field(&fields, SourceParagraphOptionalField::MAINTAINER); + + std::string deps = details::remove_optional_field(&fields, SourceParagraphOptionalField::BUILD_DEPENDS); + this->depends = expand_qualified_dependencies(parse_depends(deps)); + + if (!fields.empty()) + { + 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("\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); + System::println("This is the list of valid fields (case-sensitive): \n\n %s\n", valid_fields_as_string); + exit(EXIT_FAILURE); + } + } + + std::vector<dependency> vcpkg::expand_qualified_dependencies(const std::vector<std::string>& depends) + { + auto convert = [&](const std::string& depend_string) -> dependency { + auto pos = depend_string.find(' '); + if (pos == std::string::npos) + return{ depend_string, "" }; + // expect of the form "\w+ \[\w+\]" + dependency dep; + dep.name = depend_string.substr(0, pos); + if (depend_string.c_str()[pos + 1] != '[' || depend_string[depend_string.size() - 1] != ']') + { + // Error, but for now just slurp the entire string. + return{ depend_string, "" }; + } + dep.qualifier = depend_string.substr(pos + 2, depend_string.size() - pos - 3); + return dep; + }; + + std::vector<vcpkg::dependency> ret; + + for (auto&& depend_string : depends) + { + ret.push_back(convert(depend_string)); + } + + return ret; + } + + std::vector<std::string> parse_depends(const std::string& depends_string) + { + if (depends_string.empty()) + { + return{}; + } + + std::vector<std::string> out; + + size_t cur = 0; + do + { + auto pos = depends_string.find(',', cur); + if (pos == std::string::npos) + { + out.push_back(depends_string.substr(cur)); + break; + } + out.push_back(depends_string.substr(cur, pos - cur)); + + // skip comma and space + ++pos; + if (depends_string[pos] == ' ') + { + ++pos; + } + + cur = pos; + } while (cur != std::string::npos); + + return out; + } + + std::vector<std::string> filter_dependencies(const std::vector<vcpkg::dependency>& deps, const triplet& t) + { + std::vector<std::string> ret; + for (auto&& dep : deps) + { + if (dep.qualifier.empty() || t.canonical_name().find(dep.qualifier) != std::string::npos) + { + ret.push_back(dep.name); + } + } + return ret; + } + + std::ostream & operator<<(std::ostream & os, const dependency & p) { - depends.clear(); - parse_depends(deps, depends); + os << p.name; + return os; } - optional_field(fields, maintainer, "Maintainer"); } diff --git a/toolsrc/src/StatusParagraph.cpp b/toolsrc/src/StatusParagraph.cpp index 09a3b4d45..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" @@ -5,6 +6,12 @@ using namespace vcpkg::details; namespace vcpkg { + // + namespace BinaryParagraphRequiredField + { + static const std::string STATUS = "Status"; + } + StatusParagraph::StatusParagraph() : want(want_t::error), state(install_state_t::error) { } @@ -19,8 +26,7 @@ namespace vcpkg StatusParagraph::StatusParagraph(const std::unordered_map<std::string, std::string>& fields) : package(fields) { - std::string status_field; - required_field(fields, status_field, "Status"); + std::string status_field = required_field(fields, BinaryParagraphRequiredField::STATUS); auto b = status_field.begin(); auto mark = b; diff --git a/toolsrc/src/StatusParagraphs.cpp b/toolsrc/src/StatusParagraphs.cpp index 463e3e3b8..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 @@ -13,23 +13,25 @@ namespace vcpkg StatusParagraphs::const_iterator StatusParagraphs::find(const std::string& name, const triplet& target_triplet) const { - return std::find_if(begin(), end(), [&](const auto& pgh) + return std::find_if(begin(), end(), [&](const std::unique_ptr<StatusParagraph>& pgh) { - return pgh->package.name == name && pgh->package.target_triplet == target_triplet; + const package_spec& spec = pgh->package.spec; + return spec.name() == name && spec.target_triplet() == target_triplet; }); } StatusParagraphs::iterator StatusParagraphs::find(const std::string& name, const triplet& target_triplet) { - return std::find_if(begin(), end(), [&](const auto& pgh) + return std::find_if(begin(), end(), [&](const std::unique_ptr<StatusParagraph>& pgh) { - return pgh->package.name == name && pgh->package.target_triplet == target_triplet; + const package_spec& spec = pgh->package.spec; + return spec.name() == name && spec.target_triplet() == target_triplet; }); } - 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; @@ -40,19 +42,18 @@ namespace vcpkg StatusParagraphs::iterator StatusParagraphs::insert(std::unique_ptr<StatusParagraph> pgh) { - Checks::check_throw(pgh != nullptr, "Inserted null paragraph"); - auto ptr = find(pgh->package.name, pgh->package.target_triplet); + 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()) { paragraphs.push_back(std::move(pgh)); return paragraphs.rbegin(); } - else - { - // consume data from provided pgh. - **ptr = std::move(*pgh); - return ptr; - } + + // consume data from provided pgh. + **ptr = std::move(*pgh); + return ptr; } std::ostream& vcpkg::operator<<(std::ostream& os, const StatusParagraphs& l) diff --git a/toolsrc/src/coff_file_reader.cpp b/toolsrc/src/coff_file_reader.cpp new file mode 100644 index 000000000..f48f912c1 --- /dev/null +++ b/toolsrc/src/coff_file_reader.cpp @@ -0,0 +1,307 @@ +#include "pch.h" +#include "coff_file_reader.h" +#include "vcpkg_Checks.h" + +using namespace std; + +namespace vcpkg::COFFFileReader +{ + template <class T> + static T reinterpret_bytes(const char* data) + { + return (*reinterpret_cast<const T *>(&data[0])); + } + + template <class T> + static T read_value_from_stream(fstream& fs) + { + T data; + fs.read(reinterpret_cast<char*>(&data), sizeof data); + return data; + } + + template <class T> + static T peek_value_from_stream(fstream& fs) + { + fpos_t original_pos = fs.tellg().seekpos(); + T data; + fs.read(reinterpret_cast<char*>(&data), sizeof data); + fs.seekg(original_pos); + return data; + } + + static void verify_equal_strings(const char* expected, const char* actual, int size, const char* label) + { + Checks::check_exit(memcmp(expected, actual, size) == 0, "Incorrect string (%s) found. Expected: (%s) but found (%s)", label, expected, actual); + } + + static void read_and_verify_PE_signature(fstream& fs) + { + static const size_t OFFSET_TO_PE_SIGNATURE_OFFSET = 0x3c; + + static const char* PE_SIGNATURE = "PE\0\0"; + static const size_t PE_SIGNATURE_SIZE = 4; + + fs.seekg(OFFSET_TO_PE_SIGNATURE_OFFSET, ios_base::beg); + const int32_t offset_to_PE_signature = read_value_from_stream<int32_t>(fs); + + fs.seekg(offset_to_PE_signature); + char signature[PE_SIGNATURE_SIZE]; + fs.read(signature, PE_SIGNATURE_SIZE); + verify_equal_strings(PE_SIGNATURE, signature, PE_SIGNATURE_SIZE, "PE_SIGNATURE"); + fs.seekg(offset_to_PE_signature + PE_SIGNATURE_SIZE, ios_base::beg); + } + + static fpos_t align_to_size(const uint64_t unaligned, const uint64_t alignment_size) + { + fpos_t aligned = unaligned - 1; + aligned /= alignment_size; + aligned += 1; + aligned *= alignment_size; + return aligned; + } + + struct coff_file_header + { + static const size_t HEADER_SIZE = 20; + + static coff_file_header read(fstream& fs) + { + coff_file_header ret; + ret.data.resize(HEADER_SIZE); + fs.read(&ret.data[0], HEADER_SIZE); + return ret; + } + + MachineType machineType() const + { + static const size_t MACHINE_TYPE_OFFSET = 0; + static const size_t MACHINE_TYPE_SIZE = 2; + + std::string machine_field_as_string = data.substr(MACHINE_TYPE_OFFSET, MACHINE_TYPE_SIZE); + const uint16_t machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str()); + return getMachineType(machine); + } + + private: + std::string data; + }; + + struct archive_member_header + { + static const size_t HEADER_SIZE = 60; + + static archive_member_header read(fstream& fs) + { + static const size_t HEADER_END_OFFSET = 58; + static const char* HEADER_END = "`\n"; + static const size_t HEADER_END_SIZE = 2; + + archive_member_header ret; + ret.data.resize(HEADER_SIZE); + fs.read(&ret.data[0], HEADER_SIZE); + + if (ret.data[0] != '\0') // Due to freeglut. github issue #223 + { + const std::string header_end = ret.data.substr(HEADER_END_OFFSET, HEADER_END_SIZE); + verify_equal_strings(HEADER_END, header_end.c_str(), HEADER_END_SIZE, "LIB HEADER_END"); + } + + return ret; + } + + std::string name() const + { + static const size_t HEADER_NAME_OFFSET = 0; + static const size_t HEADER_NAME_SIZE = 16; + return data.substr(HEADER_NAME_OFFSET, HEADER_NAME_SIZE); + } + + uint64_t member_size() const + { + static const size_t ALIGNMENT_SIZE = 2; + + static const size_t HEADER_SIZE_OFFSET = 48; + static const size_t HEADER_SIZE_FIELD_SIZE = 10; + const std::string as_string = data.substr(HEADER_SIZE_OFFSET, HEADER_SIZE_FIELD_SIZE); + // This is in ASCII decimal representation + const uint64_t value = std::strtoull(as_string.c_str(), nullptr, 10); + + const uint64_t aligned = align_to_size(value, ALIGNMENT_SIZE); + return aligned; + } + + std::string data; + }; + + struct offsets_array + { + static offsets_array read(fstream& fs, const uint32_t offset_count) + { + static const size_t OFFSET_WIDTH = 4; + + std::string raw_offsets; + const size_t raw_offset_size = offset_count * OFFSET_WIDTH; + raw_offsets.resize(raw_offset_size); + fs.read(&raw_offsets[0], raw_offset_size); + + offsets_array ret; + for (uint32_t i = 0; i < offset_count; ++i) + { + const std::string value_as_string = raw_offsets.substr(OFFSET_WIDTH * i, OFFSET_WIDTH * (i + 1)); + const uint32_t value = reinterpret_bytes<uint32_t>(value_as_string.c_str()); + + // Ignore offsets that point to offset 0. See vcpkg github #223 #288 #292 + if (value != 0) + { + ret.data.push_back(value); + } + } + + // Sort the offsets, because it is possible for them to be unsorted. See vcpkg github #292 + std::sort(ret.data.begin(), ret.data.end()); + return ret; + } + + std::vector<uint32_t> data; + }; + + struct import_header + { + static const size_t HEADER_SIZE = 20; + + static import_header read(fstream& fs) + { + static const size_t SIG1_OFFSET = 0; + static const uint16_t SIG1 = static_cast<uint16_t>(MachineType::UNKNOWN); + static const size_t SIG1_SIZE = 2; + + static const size_t SIG2_OFFSET = 2; + static const uint16_t SIG2 = 0xFFFF; + static const size_t SIG2_SIZE = 2; + + import_header ret; + ret.data.resize(HEADER_SIZE); + fs.read(&ret.data[0], HEADER_SIZE); + + const std::string sig1_as_string = ret.data.substr(SIG1_OFFSET, SIG1_SIZE); + const uint16_t sig1 = reinterpret_bytes<uint16_t>(sig1_as_string.c_str()); + Checks::check_exit(sig1 == SIG1, "Sig1 was incorrect. Expected %s but got %s", SIG1, sig1); + + const std::string sig2_as_string = ret.data.substr(SIG2_OFFSET, SIG2_SIZE); + const uint16_t sig2 = reinterpret_bytes<uint16_t>(sig2_as_string.c_str()); + Checks::check_exit(sig2 == SIG2, "Sig2 was incorrect. Expected %s but got %s", SIG2, sig2); + + return ret; + } + + MachineType machineType() const + { + static const size_t MACHINE_TYPE_OFFSET = 6; + static const size_t MACHINE_TYPE_SIZE = 2; + + std::string machine_field_as_string = data.substr(MACHINE_TYPE_OFFSET, MACHINE_TYPE_SIZE); + const uint16_t machine = reinterpret_bytes<uint16_t>(machine_field_as_string.c_str()); + return getMachineType(machine); + } + + private: + std::string data; + }; + + static void read_and_verify_archive_file_signature(fstream& fs) + { + static const char* FILE_START = "!<arch>\n"; + static const size_t FILE_START_SIZE = 8; + + fs.seekg(fs.beg); + + char file_start[FILE_START_SIZE]; + fs.read(file_start, FILE_START_SIZE); + verify_equal_strings(FILE_START, file_start, FILE_START_SIZE, "LIB FILE_START"); + } + + dll_info read_dll(const fs::path& path) + { + std::fstream fs(path, std::ios::in | std::ios::binary | std::ios::ate); + Checks::check_exit(fs.is_open(), "Could not open file %s for reading", path.generic_string()); + + read_and_verify_PE_signature(fs); + coff_file_header header = coff_file_header::read(fs); + MachineType machine = header.machineType(); + return {machine}; + } + + struct marker_t + { + void set_to_offset(const fpos_t position) + { + this->m_absolute_position = position; + } + + void set_to_current_pos(fstream& fs) + { + this->m_absolute_position = fs.tellg().seekpos(); + } + + void seek_to_marker(fstream& fs) const + { + fs.seekg(this->m_absolute_position, ios_base::beg); + } + + void advance_by(const uint64_t offset) + { + this->m_absolute_position += offset; + } + + private: + fpos_t m_absolute_position = 0; + }; + + lib_info read_lib(const fs::path& path) + { + std::fstream fs(path, std::ios::in | std::ios::binary | std::ios::ate); + Checks::check_exit(fs.is_open(), "Could not open file %s for reading", path.generic_string()); + + read_and_verify_archive_file_signature(fs); + + marker_t marker; + marker.set_to_current_pos(fs); + + // First Linker Member + const archive_member_header first_linker_member_header = archive_member_header::read(fs); + Checks::check_exit(first_linker_member_header.name().substr(0, 2) == "/ ", "Could not find proper first linker member"); + marker.advance_by(archive_member_header::HEADER_SIZE + first_linker_member_header.member_size()); + marker.seek_to_marker(fs); + + const archive_member_header second_linker_member_header = archive_member_header::read(fs); + Checks::check_exit(second_linker_member_header.name().substr(0, 2) == "/ ", "Could not find proper second linker member"); + // The first 4 bytes contains the number of archive members + const uint32_t archive_member_count = read_value_from_stream<uint32_t>(fs); + const offsets_array offsets = offsets_array::read(fs, archive_member_count); + marker.advance_by(archive_member_header::HEADER_SIZE + second_linker_member_header.member_size()); + marker.seek_to_marker(fs); + + bool hasLongnameMemberHeader = peek_value_from_stream<uint16_t>(fs) == 0x2F2F; + if (hasLongnameMemberHeader) + { + const archive_member_header longnames_member_header = archive_member_header::read(fs); + marker.advance_by(archive_member_header::HEADER_SIZE + longnames_member_header.member_size()); + marker.seek_to_marker(fs); + } + + std::set<MachineType> machine_types; + // Next we have the obj and pseudo-object files + for (const uint32_t offset : offsets.data) + { + marker.set_to_offset(offset + archive_member_header::HEADER_SIZE); // Skip the header, no need to read it. + marker.seek_to_marker(fs); + const uint16_t first_two_bytes = peek_value_from_stream<uint16_t>(fs); + const bool isImportHeader = getMachineType(first_two_bytes) == MachineType::UNKNOWN; + const MachineType machine = isImportHeader ? import_header::read(fs).machineType() : coff_file_header::read(fs).machineType(); + machine_types.insert(machine); + } + + 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 3a08c4a64..e255b5dff 100644 --- a/toolsrc/src/commands_cache.cpp +++ b/toolsrc/src/commands_cache.cpp @@ -1,36 +1,74 @@ +#include "pch.h" #include "vcpkg_Commands.h" #include "vcpkg_System.h" #include "vcpkg_Files.h" -#include "vcpkg.h" +#include "Paragraphs.h" +#include "BinaryParagraph.h" -namespace vcpkg +namespace vcpkg::Commands::Cache { - void cache_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + static std::vector<BinaryParagraph> read_all_binary_paragraphs(const vcpkg_paths& paths) { - args.check_max_args(0); + std::vector<BinaryParagraph> output; + for (auto it = fs::directory_iterator(paths.packages); it != fs::directory_iterator(); ++it) + { + const fs::path& path = it->path(); + + try + { + auto file_contents = Files::read_contents(path / "CONTROL"); + if (auto text = file_contents.get()) + { + auto pghs = Paragraphs::parse_paragraphs(*text); + if (pghs.size() != 1) + continue; + + const BinaryParagraph binary_paragraph = BinaryParagraph(pghs[0]); + output.push_back(binary_paragraph); + } + } + catch (std::runtime_error const&) + { + } + } - auto begin_it = fs::directory_iterator(paths.packages); - auto end_it = fs::directory_iterator(); + return output; + } + + 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", Commands::Help::create_example_string("cache png")); + args.check_max_arg_count(1, example); + args.check_and_get_optional_command_arguments({}); - if (begin_it == end_it) + const std::vector<BinaryParagraph> binary_paragraphs = read_all_binary_paragraphs(paths); + if (binary_paragraphs.empty()) { System::println("No packages are cached."); exit(EXIT_SUCCESS); } - for (; begin_it != end_it; ++begin_it) + if (args.command_arguments.size() == 0) { - const auto& path = begin_it->path(); - - auto file_contents = Files::get_contents(path / "CONTROL"); - if (auto text = file_contents.get()) + for (const BinaryParagraph& binary_paragraph : binary_paragraphs) + { + const std::string displayname = binary_paragraph.displayname(); + System::println(displayname); + } + } + else + { + // At this point there is 1 argument + for (const BinaryParagraph& binary_paragraph : binary_paragraphs) { - auto pghs = parse_paragraphs(*text); - if (pghs.size() != 1) + const std::string displayname = binary_paragraph.displayname(); + if (Strings::case_insensitive_ascii_find(displayname, args.command_arguments[0]) == displayname.end()) + { continue; + } - auto src = BinaryParagraph(pghs[0]); - System::println(src.displayname().c_str()); + System::println(displayname); } } 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 76ba644e4..b74693ed5 100644 --- a/toolsrc/src/commands_create.cpp +++ b/toolsrc/src/commands_create.cpp @@ -1,50 +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, const triplet& default_target_triplet) + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) { - args.check_max_args(3); - if (args.command_arguments.size() < 2) - { - System::println(System::color::error, "Error: create requires the archive's URL as the second argument."); - print_usage(); - exit(EXIT_FAILURE); - } - - expected<package_spec> current_spec = package_spec::from_string(args.command_arguments[0], default_target_triplet); - if (const package_spec* spec = current_spec.get()) - { - Environment::ensure_utilities_on_path(paths); + 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); + const std::string url = args.command_arguments.at(1); - // 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::format(LR"( -DFILENAME="%s" )", Strings::utf8_to_utf16(zip_file_name)); - } + const fs::path& cmake_exe = paths.get_cmake_exe(); - const std::wstring cmdline = Strings::format(LR"(cmake -DCMD=SCAFFOLD -DPORT=%s -DTARGET_TRIPLET=%s -DURL=%s%s-P "%s")", - Strings::utf8_to_utf16(spec->name), - Strings::utf8_to_utf16(spec->target_triplet.value), - Strings::utf8_to_utf16(args.command_arguments.at(1)), - custom_filename, - paths.ports_cmake.generic_wstring()); + std::vector<CMakeVariable> cmake_args + { + { L"CMD", L"CREATE" }, + { L"PORT", port_name }, + { L"URL", url } + }; - exit(System::cmd_execute(cmdline)); - } - else + if (args.command_arguments.size() >= 3) { - System::println(System::color::error, "Error: %s: %s", current_spec.error_code().message(), args.command_arguments[0]); - print_example(Strings::format("%s zlib:x64-windows", args.command).c_str()); - exit(EXIT_FAILURE); + 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); + cmake_args.push_back({ L"FILENAME", zip_file_name }); } + + 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 71ae8b2c8..ce0557e09 100644 --- a/toolsrc/src/commands_edit.cpp +++ b/toolsrc/src/commands_edit.cpp @@ -1,21 +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, const triplet& default_target_triplet) + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) { - static auto example = "edit zlib"; - args.check_max_args(1, example); - package_spec spec = args.parse_all_arguments_as_package_specs(default_target_triplet, example).at(0); + 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; + } + } + + if (env_EDITOR.empty()) + { + 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; + } + } + + 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) + { + 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; + } + } + } + } - // Find editor - std::wstring env_EDITOR = System::wdupenv_str(L"EDITOR"); if (env_EDITOR.empty()) - env_EDITOR = LR"(C:\Program Files (x86)\Microsoft VS Code\Code.exe)"; + { + Checks::exit_with_message("Visual Studio Code was not found and the environment variable EDITOR is not set"); + } - auto portpath = paths.ports / spec.name; - std::wstring cmdLine = Strings::format(LR"("%s" "%s" "%s")", env_EDITOR, portpath.native(), (portpath / "portfile.cmake").native()); + 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 new file mode 100644 index 000000000..805da4153 --- /dev/null +++ b/toolsrc/src/commands_hash.cpp @@ -0,0 +1,46 @@ +#include "pch.h" +#include "vcpkg_Commands.h" +#include "vcpkg_System.h" + +namespace vcpkg::Commands::Hash +{ + static void do_file_hash(fs::path const& path, std::wstring const& hashType) + { + auto cmd_line = Strings::wformat(LR"(CertUtil.exe -hashfile "%s" %s)", + path.c_str(), hashType.c_str()); + auto 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)); + + std::string const& output = ec_data.output; + + auto start = output.find_first_of("\r\n"); + Checks::check_exit(start != std::string::npos, "Unexpected output format from command: %s", Strings::utf16_to_utf8(cmd_line)); + + auto end = output.find_first_of("\r\n", start + 1); + Checks::check_exit(end != std::string::npos, "Unexpected output format from command: %s", Strings::utf16_to_utf8(cmd_line)); + + auto hash = output.substr(start, end - start); + hash.erase(std::remove_if(hash.begin(), hash.end(), isspace), hash.end()); + System::println(hash); + } + + 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", 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) + { + do_file_hash(args.command_arguments[0], L"SHA512"); + } + if (args.command_arguments.size() == 2) + { + do_file_hash(args.command_arguments[0], Strings::utf8_to_utf16(args.command_arguments[1])); + } + + exit(EXIT_SUCCESS); + } +} diff --git a/toolsrc/src/commands_help.cpp b/toolsrc/src/commands_help.cpp index 4e1ae9c49..49b5697c3 100644 --- a/toolsrc/src/commands_help.cpp +++ b/toolsrc/src/commands_help.cpp @@ -1,23 +1,74 @@ +#include "pch.h" #include "vcpkg_Commands.h" -#include "vcpkg.h" #include "vcpkg_System.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_max_args(0); - System::println("Vcpkg package management program version %s\n" - "\n" - "Vcpkg is provided \"as-is\" without warranty of any kind, express or implied.\n" - "All rights reserved.", vcpkg::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_args(1); + args.check_max_arg_count(1); + args.check_and_get_optional_command_arguments({}); + if (args.command_arguments.empty()) { print_usage(); @@ -36,20 +87,4 @@ namespace vcpkg } exit(EXIT_SUCCESS); } - - void contact_command(const vcpkg_cmd_arguments& /*args*/) - { - System::println("Send an email to vcpkg@microsoft.com with any feedback."); - 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 b1eae277c..11924b4b2 100644 --- a/toolsrc/src/commands_import.cpp +++ b/toolsrc/src/commands_import.cpp @@ -1,30 +1,85 @@ +#include "pch.h" #include "vcpkg_Commands.h" -#include "vcpkg.h" -#include "vcpkg_System.h" +#include "Paragraphs.h" +#include "StatusParagraph.h" +#include "vcpkg_Files.h" -namespace vcpkg +namespace vcpkg::Commands::Import { - void import_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + struct Binaries { - if (args.command_arguments.size() != 3) + std::vector<fs::path> dlls; + std::vector<fs::path> libs; + }; + + static Binaries find_binaries_in_dir(const fs::path& path) + { + Files::check_is_directory(path); + + Binaries binaries; + 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; + } + + static void copy_files_into_directory(const std::vector<fs::path>& files, const fs::path& destination_folder) + { + fs::create_directory(destination_folder); + + for (auto const& src_path : files) { - System::println(System::color::error, "Error: %s requires 3 parameters", args.command); - print_example(Strings::format(R"(%s C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)", args.command).c_str()); - exit(EXIT_FAILURE); + fs::path dest_path = destination_folder / src_path.filename(); + fs::copy(src_path, dest_path, fs::copy_options::overwrite_existing); } + } + + static void place_library_files_in(const fs::path& include_directory, const fs::path& project_directory, const fs::path& destination_path) + { + Files::check_is_directory(include_directory); + Files::check_is_directory(project_directory); + Files::check_is_directory(destination_path); + 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); + + copy_files_into_directory(release_binaries.dlls, destination_path / "bin"); + copy_files_into_directory(release_binaries.libs, destination_path / "lib"); + + fs::create_directory(destination_path / "debug"); + copy_files_into_directory(debug_binaries.dlls, destination_path / "debug" / "bin"); + copy_files_into_directory(debug_binaries.libs, destination_path / "debug" / "lib"); + } + + static void do_import(const vcpkg_paths& paths, const fs::path& include_directory, const fs::path& project_directory, const BinaryParagraph& control_file_data) + { + fs::path library_destination_path = paths.package_dir(control_file_data.spec); + fs::create_directory(library_destination_path); + place_library_files_in(include_directory, project_directory, library_destination_path); + + fs::path control_file_path = library_destination_path / "CONTROL"; + std::ofstream(control_file_path) << control_file_data; + } + + void perform_and_exit(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + { + 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 = get_paragraphs(control_file_path); - Checks::check_throw(pghs.size() == 1, "Invalid control file for package"); + auto pghs = Paragraphs::get_paragraphs(control_file_path); + Checks::check_exit(pghs.size() == 1, "Invalid control file %s for package", control_file_path.generic_string()); StatusParagraph spgh; spgh.package = BinaryParagraph(pghs[0]); auto& control_file_data = spgh.package; - vcpkg::binary_import(paths, include_directory, project_directory, control_file_data); + do_import(paths, include_directory, project_directory, control_file_data); exit(EXIT_SUCCESS); } } 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 24ea7480b..000000000 --- a/toolsrc/src/commands_installation.cpp +++ /dev/null @@ -1,164 +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" - -namespace vcpkg -{ - static void create_binary_control_file(const vcpkg_paths& paths, const fs::path& port_dir, const triplet& target_triplet) - { - auto pghs = get_paragraphs(port_dir / "CONTROL"); - Checks::check_exit(pghs.size() == 1, "Error: invalid control file"); - auto bpgh = BinaryParagraph(SourceParagraph(pghs[0]), target_triplet); - const fs::path binary_control_file = paths.packages / bpgh.dir() / "CONTROL"; - std::ofstream(binary_control_file) << bpgh; - } - - static void build_internal(const package_spec& spec, const vcpkg_paths& paths, const fs::path& port_dir) - { - const fs::path ports_cmake_script_path = paths.ports_cmake; - const std::wstring command = Strings::format(LR"("%%VS140COMNTOOLS%%..\..\VC\vcvarsall.bat" %s && cmake -DCMD=BUILD -DPORT=%s -DTARGET_TRIPLET=%s "-DCURRENT_PORT_DIR=%s/." -P "%s")", - Strings::utf8_to_utf16(spec.target_triplet.architecture()), - Strings::utf8_to_utf16(spec.name), - Strings::utf8_to_utf16(spec.target_triplet.value), - port_dir.generic_wstring(), - ports_cmake_script_path.generic_wstring()); - - System::Stopwatch 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: build command failed"); - TrackProperty("error", "build failed"); - TrackProperty("build_error", std::to_string(return_code)); - exit(EXIT_FAILURE); - } - - perform_all_checks(spec, paths); - - create_binary_control_file(paths, port_dir, spec.target_triplet); - - // const fs::path port_buildtrees_dir = paths.buildtrees / spec.name; - // delete_directory(port_buildtrees_dir); - } - - static void build_internal(const package_spec& spec, const vcpkg_paths& paths) - { - return build_internal(spec, paths, paths.ports / spec.name); - } - - void install_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet) - { - StatusParagraphs status_db = database_load_check(paths); - - std::vector<package_spec> specs = args.parse_all_arguments_as_package_specs(default_target_triplet); - std::vector<package_spec> install_plan = Dependencies::create_dependency_ordered_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]); - for (size_t i = 1; i < install_plan.size(); ++i) - { - specs_string.push_back(','); - specs_string.append(to_string(install_plan[i])); - } - TrackProperty("installplan", specs_string); - Environment::ensure_utilities_on_path(paths); - - for (const package_spec& spec : install_plan) - { - if (status_db.find_installed(spec.name, spec.target_triplet) != status_db.end()) - { - System::println(System::color::success, "Package %s is already installed", spec); - continue; - } - - fs::path package_path = paths.package_dir(spec); - - expected<std::string> file_contents = Files::get_contents(package_path / "CONTROL"); - - try - { - if (file_contents.error_code()) - { - build_internal(spec, paths); - file_contents = Files::get_contents(package_path / "CONTROL"); - if (file_contents.error_code()) - { - file_contents.get_or_throw(); - } - } - - auto pghs = parse_paragraphs(file_contents.get_or_throw()); - Checks::check_throw(pghs.size() == 1, "multiple paragraphs in control file"); - install_package(paths, BinaryParagraph(pghs[0]), status_db); - System::println(System::color::success, "Package %s is installed", spec); - } - catch (const std::exception& e) - { - System::println(System::color::error, "Error: Could not install package %s: %s", 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) - { - // Installing multiple packages leads to unintuitive behavior if one of them depends on another. - // Allowing only 1 package for now. - args.check_max_args(1); - - StatusParagraphs status_db = database_load_check(paths); - - const package_spec spec = args.parse_all_arguments_as_package_specs(default_target_triplet).at(0); - std::unordered_set<package_spec> unmet_dependencies = Dependencies::find_unmet_dependencies(paths, spec, status_db); - 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& p : unmet_dependencies) - { - System::println(" %s", to_string(p)); - } - System::println(""); - exit(EXIT_FAILURE); - } - - Environment::ensure_utilities_on_path(paths); - build_internal(spec, paths); - exit(EXIT_SUCCESS); - } - - void build_external_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet) - { - if (args.command_arguments.size() != 2) - { - System::println(System::color::error, "Error: buildexternal requires the package name and the directory containing the CONTROL file"); - print_example(R"(buildexternal mylib C:\path\to\mylib\)"); - exit(EXIT_FAILURE); - } - - expected<package_spec> current_spec = package_spec::from_string(args.command_arguments[0], default_target_triplet); - if (auto spec = current_spec.get()) - { - Environment::ensure_utilities_on_path(paths); - const fs::path port_dir = args.command_arguments.at(1); - build_internal(*spec, paths, port_dir); - exit(EXIT_SUCCESS); - } - - System::println(System::color::error, "Error: %s: %s", current_spec.error_code().message(), args.command_arguments[0]); - print_example(Strings::format("%s zlib:x64-windows", args.command).c_str()); - exit(EXIT_FAILURE); - } -} diff --git a/toolsrc/src/commands_integration.cpp b/toolsrc/src/commands_integrate.cpp index 4f3fdd20b..f98b9f77c 100644 --- a/toolsrc/src/commands_integration.cpp +++ b/toolsrc/src/commands_integrate.cpp @@ -1,24 +1,17 @@ -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <shellapi.h> +#include "pch.h" #include "vcpkg_Commands.h" -#include "vcpkg.h" -#include <fstream> -#include <iostream> -#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 { @@ -116,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; @@ -143,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) @@ -173,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::get_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; } } @@ -195,7 +185,7 @@ namespace vcpkg const fs::path sys_src_path = tmp_dir / "vcpkg.system.targets"; std::ofstream(sys_src_path) << create_system_targets_shortcut(); - const std::string param = Strings::format(R"(/c echo f | XCOPY "%s" "%s" /Y > nul)", sys_src_path.string(), system_wide_targets_file.string()); + const std::string param = Strings::format(R"(/c mkdir "%s" & copy "%s" "%s" /Y > nul)", system_wide_targets_file.parent_path().string(), sys_src_path.string(), system_wide_targets_file.string()); elevation_prompt_user_choice user_choice = elevated_cmd_execute(param); switch (user_choice) { @@ -221,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::format(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"; @@ -269,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::format(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"( @@ -295,15 +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) { - if (args.command_arguments.size() != 1) - { - std::cout << "Commands:\n" << - INTEGRATE_COMMAND_HELPSTRING << - "\n"; - exit(EXIT_FAILURE); - } + 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 2969ea953..7bfc11f1b 100644 --- a/toolsrc/src/commands_list.cpp +++ b/toolsrc/src/commands_list.cpp @@ -1,32 +1,69 @@ +#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 { - void list_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + static void do_print(const StatusParagraph& pgh) { - args.check_max_args(0); + System::println("%-27s %-16s %s", + pgh.package.displayname(), + pgh.package.version, + details::shorten_description(pgh.package.description)); + } + + 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", Commands::Help::create_example_string("list png")); + args.check_max_arg_count(1, example); + args.check_and_get_optional_command_arguments({}); - std::vector<std::string> packages_output; - for (auto&& pgh : database_load_check(paths)) + const StatusParagraphs status_paragraphs = database_load_check(paths); + std::vector<StatusParagraph> installed_packages; + for (auto&& pgh : status_paragraphs) { if (pgh->state == install_state_t::not_installed && pgh->want == want_t::purge) continue; - packages_output.push_back(Strings::format("%-27s %-16s %s", - pgh->package.displayname(), - pgh->package.version, - shorten_description(pgh->package.description))); + installed_packages.push_back(*pgh); + } + + if (installed_packages.empty()) + { + System::println("No packages are installed. Did you mean `search`?"); + exit(EXIT_SUCCESS); } - std::sort(packages_output.begin(), packages_output.end()); - for (auto&& package : packages_output) + + std::sort(installed_packages.begin(), installed_packages.end(), + [ ]( const StatusParagraph& lhs, const StatusParagraph& rhs ) -> bool + { + return lhs.package.displayname() < rhs.package.displayname(); + }); + + if (args.command_arguments.size() == 0) { - System::println(package.c_str()); + for (const StatusParagraph& status_paragraph : installed_packages) + { + do_print(status_paragraph); + } } - if (packages_output.empty()) + else { - System::println("No packages are installed. Did you mean `search`?"); + // At this point there is 1 argument + for (const StatusParagraph& status_paragraph : installed_packages) + { + const std::string displayname = status_paragraph.package.displayname(); + if (Strings::case_insensitive_ascii_find(displayname, args.command_arguments[0]) == displayname.end()) + { + continue; + } + + do_print(status_paragraph); + } } + exit(EXIT_SUCCESS); } } diff --git a/toolsrc/src/commands_other.cpp b/toolsrc/src/commands_other.cpp deleted file mode 100644 index f4fad6690..000000000 --- a/toolsrc/src/commands_other.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "vcpkg_Commands.h" -#include "vcpkg_System.h" -#include "vcpkg.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" - "\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); - } - - void print_example(const char* command_and_arguments) - { - System::println("Example:\n" - " vcpkg %s", 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}, - {"edit", edit_command}, - {"create", create_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", help_command}, - {"search", search_command}, - {"list", list_command}, - {"integrate", integrate_command}, - {"owns", owns_command}, - {"update", update_command}, - {"import", import_command}, - {"cache", cache_command}, - {"internal_test", internal_test_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} - }; - return t; - } -} diff --git a/toolsrc/src/commands_owns.cpp b/toolsrc/src/commands_owns.cpp index 19c0a8dc6..16bb986e2 100644 --- a/toolsrc/src/commands_owns.cpp +++ b/toolsrc/src/commands_owns.cpp @@ -1,18 +1,33 @@ +#include "pch.h" #include "vcpkg_Commands.h" #include "vcpkg_System.h" -#include "vcpkg.h" +#include "vcpkglib.h" -namespace vcpkg +namespace vcpkg::Commands::Owns { - void owns_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + static void search_file(const vcpkg_paths& paths, const std::string& file_substr, const StatusParagraphs& status_db) { - args.check_max_args(1); - if (args.command_arguments.size() == 0) + const std::vector<StatusParagraph_and_associated_files> installed_files = get_installed_files(paths, status_db); + for (const StatusParagraph_and_associated_files& pgh_and_file : installed_files) { - System::println(System::color::error, "Error: owns requires a pattern to search for as the first argument."); - print_example("owns .dll"); - exit(EXIT_FAILURE); + const StatusParagraph& pgh = pgh_and_file.pgh; + + for (const std::string& file : pgh_and_file.files) + { + if (file.find(file_substr) != std::string::npos) + { + System::println("%s: %s", pgh.package.displayname(), file); + } + } } + } + + 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", 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); exit(EXIT_SUCCESS); diff --git a/toolsrc/src/commands_portsdiff.cpp b/toolsrc/src/commands_portsdiff.cpp new file mode 100644 index 000000000..4d5a589f6 --- /dev/null +++ b/toolsrc/src/commands_portsdiff.cpp @@ -0,0 +1,138 @@ +#include "pch.h" +#include "vcpkg_Commands.h" +#include "vcpkg_System.h" +#include "vcpkg_Maps.h" +#include "SourceParagraph.h" +#include "vcpkg_Environment.h" +#include "Paragraphs.h" + +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); + System::println("%-20s %-16s", name, version); + } + } + + static void do_print_name_and_previous_version_and_current_version(const std::vector<std::string>& ports_to_print, + const std::map<std::string, std::string>& previous_names_and_versions, + const std::map<std::string, std::string>& current_names_and_versions) + { + for (const std::string& name : ports_to_print) + { + const std::string& previous_version = previous_names_and_versions.at(name); + const std::string& current_version = current_names_and_versions.at(name); + System::println("%-20s %-16s -> %s", name, previous_version, current_version); + } + } + + 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"("%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", + 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 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"("%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 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", 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(); + + 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_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); + + // Already sorted, so set_difference can work on std::vector too + std::vector<std::string> current_ports = Maps::extract_keys(current_names_and_versions); + std::vector<std::string> previous_ports = Maps::extract_keys(previous_names_and_versions); + + std::vector<std::string> added_ports; + std::set_difference( + current_ports.cbegin(), current_ports.cend(), + previous_ports.cbegin(), previous_ports.cend(), + std::back_inserter(added_ports)); + + if (!added_ports.empty()) + { + System::println("\nThe following %d ports were added:\n", added_ports.size()); + do_print_name_and_version(added_ports, current_names_and_versions); + } + + std::vector<std::string> removed_ports; + std::set_difference( + previous_ports.cbegin(), previous_ports.cend(), + current_ports.cbegin(), current_ports.cend(), + std::back_inserter(removed_ports)); + + if (!removed_ports.empty()) + { + System::println("\nThe following %d ports were removed:\n", removed_ports.size()); + do_print_name_and_version(removed_ports, previous_names_and_versions); + } + + std::vector<std::string> potentially_updated_ports; + std::set_intersection( + current_ports.cbegin(), current_ports.cend(), + previous_ports.cbegin(), previous_ports.cend(), + std::back_inserter(potentially_updated_ports)); + + std::vector<std::string> updated_ports; + std::copy_if(potentially_updated_ports.cbegin(), potentially_updated_ports.cend(), std::back_inserter(updated_ports), + [&](const std::string& port) -> bool + { + return current_names_and_versions.at(port) != previous_names_and_versions.at(port); + } + ); + + if (!updated_ports.empty()) + { + System::println("\nThe following %d ports were updated:\n", updated_ports.size()); + do_print_name_and_previous_version_and_current_version(updated_ports, previous_names_and_versions, current_names_and_versions); + } + + if (added_ports.empty() && removed_ports.empty() && updated_ports.empty()) + { + System::println("There were no changes in the ports between the two commits."); + } + + exit(EXIT_SUCCESS); + } +} diff --git a/toolsrc/src/commands_remove.cpp b/toolsrc/src/commands_remove.cpp index f5315ccb1..1b7b7923a 100644 --- a/toolsrc/src/commands_remove.cpp +++ b/toolsrc/src/commands_remove.cpp @@ -1,10 +1,18 @@ +#include "pch.h" #include "vcpkg_Commands.h" -#include "vcpkg.h" +#include "vcpkglib.h" #include "vcpkg_System.h" +#include "vcpkg_Input.h" +#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) { @@ -20,24 +28,197 @@ namespace vcpkg } } - void remove_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths, const triplet& default_target_triplet) + static void remove_package(const vcpkg_paths& paths, const package_spec& spec, StatusParagraphs* status_db) + { + StatusParagraph& pkg = **status_db->find(spec.name(), spec.target_triplet()); + + pkg.want = want_t::purge; + pkg.state = install_state_t::half_installed; + write_update(paths, pkg); + + std::fstream listfile(paths.listfile_path(pkg.package), std::ios_base::in | std::ios_base::binary); + if (listfile) + { + std::vector<fs::path> dirs_touched; + std::string suffix; + while (std::getline(listfile, suffix)) + { + if (!suffix.empty() && suffix.back() == '\r') + suffix.pop_back(); + + std::error_code ec; + + auto target = paths.installed / suffix; + + auto status = fs::status(target, ec); + if (ec) + { + System::println(System::color::error, "failed: %s", ec.message()); + continue; + } + + if (fs::is_directory(status)) + { + dirs_touched.push_back(target); + } + else if (fs::is_regular_file(status)) + { + fs::remove(target, ec); + if (ec) + { + System::println(System::color::error, "failed: %s: %s", target.u8string(), ec.message()); + } + } + else if (!fs::status_known(status)) + { + System::println(System::color::warning, "Warning: unknown status: %s", target.u8string()); + } + else + { + System::println(System::color::warning, "Warning: %s: cannot handle file type", target.u8string()); + } + } + + auto b = dirs_touched.rbegin(); + auto e = dirs_touched.rend(); + for (; b != e; ++b) + { + if (fs::directory_iterator(*b) == fs::directory_iterator()) + { + std::error_code ec; + fs::remove(*b, ec); + if (ec) + { + System::println(System::color::error, "failed: %s", ec.message()); + } + } + } + + listfile.close(); + fs::remove(paths.listfile_path(pkg.package)); + } + + pkg.state = install_state_t::not_installed; + write_update(paths, pkg); + } + + static void sort_packages_by_name(std::vector<const package_spec_with_remove_plan*>* packages) { - const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({OPTION_PURGE}); + 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(); + }); + } + + 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(¬_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); + 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(); - std::vector<package_spec> specs = args.parse_all_arguments_as_package_specs(default_target_triplet); - bool alsoRemoveFolderFromPackages = options.find(OPTION_PURGE) != options.end(); + if (has_non_user_requested_packages && !isRecursive) + { + 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& spec : specs) + for (const package_spec_with_remove_plan& action : remove_plan) { - deinstall_package(paths, spec, status_db); + 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 ce02e9c3b..8bac858f1 100644 --- a/toolsrc/src/commands_search.cpp +++ b/toolsrc/src/commands_search.cpp @@ -1,58 +1,92 @@ +#include "pch.h" #include "vcpkg_Commands.h" #include "vcpkg_System.h" -#include "vcpkg.h" -#include <iostream> -#include <iomanip> +#include "Paragraphs.h" +#include "vcpkglib_helpers.h" +#include "SourceParagraph.h" -namespace fs = std::tr2::sys; - -namespace vcpkg +namespace vcpkg::Commands::Search { - template <class Pred> - static void do_print(const vcpkg_paths& paths, Pred predicate) + 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) { - 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 = get_paragraphs(path / "CONTROL"); - if (pghs.empty()) - continue; - auto srcpgh = SourceParagraph(pghs[0]); + static std::string create_graph_as_string(const std::vector<SourceParagraph>& source_paragraphs) + { + int empty_node_count = 0; - if (predicate(srcpgh.name)) - { - std::cout << std::left - << std::setw(20) << srcpgh.name << ' ' - << std::setw(16) << srcpgh.version << ' ' - << shorten_description(srcpgh.description) << '\n'; - } + std::string s; + s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;"); + + 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)); } } + + s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count)); + return s; + } + + static void do_print(const SourceParagraph& source_paragraph) + { + System::println("%-20s %-16s %s", + source_paragraph.name, + source_paragraph.version, + 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) { - args.check_max_args(1); - if (args.command_arguments.size() == 0) + 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 = Paragraphs::load_all_ports(paths.ports); + if (options.find(OPTION_GRAPH) != options.cend()) { - do_print(paths, [](std::string&) -> bool - { - return true; - }); + const std::string graph_as_string = create_graph_as_string(source_paragraphs); + System::println(graph_as_string); exit(EXIT_SUCCESS); } - // At this point there is 1 argument - do_print(paths, [&](std::string& port_name) -> bool - { - return Strings::case_insensitive_find(port_name, args.command_arguments[0]) != port_name.end(); - }); + if (args.command_arguments.empty()) + { + for (const SourceParagraph& source_paragraph : source_paragraphs) + { + do_print(source_paragraph); + } + } + else + { + // At this point there is 1 argument + for (const SourceParagraph& source_paragraph : source_paragraphs) + { + if (Strings::case_insensitive_ascii_find(source_paragraph.name, args.command_arguments[0]) == source_paragraph.name.end()) + { + continue; + } + + do_print(source_paragraph); + } + } System::println("\nIf your library is not listed, please open an issue at:\n" " https://github.com/Microsoft/vcpkg/issues"); diff --git a/toolsrc/src/commands_update.cpp b/toolsrc/src/commands_update.cpp index eec3e46a7..8131d9a73 100644 --- a/toolsrc/src/commands_update.cpp +++ b/toolsrc/src/commands_update.cpp @@ -1,42 +1,31 @@ +#include "pch.h" #include "vcpkg_Commands.h" -#include "vcpkg.h" +#include "vcpkglib.h" #include "vcpkg_System.h" #include "vcpkg_Files.h" +#include "Paragraphs.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) { - auto status_db = database_load_check(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`."); - std::unordered_map<std::string, std::string> src_names_to_versions; + auto status_db = database_load_check(paths); - 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 = 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; std::vector<std::string> packages_output; - for (auto&& pgh : database_load_check(paths)) + for (auto&& pgh : status_db) { if (pgh->state == install_state_t::not_installed && pgh->want == want_t::purge) continue; - auto it = src_names_to_versions.find(pgh->package.name); + auto it = src_names_to_versions.find(pgh->package.spec.name()); if (it == src_names_to_versions.end()) { // Package was not installed from portfile @@ -66,20 +55,20 @@ namespace vcpkg System::println("\nTo update these packages, run\n vcpkg remove --purge <pkgs>...\n vcpkg install <pkgs>..."); } - auto version_file = Files::get_contents(paths.root / "toolsrc" / "VERSION.txt"); + auto version_file = Files::read_contents(paths.root / "toolsrc" / "VERSION.txt"); if (auto version_contents = version_file.get()) { int maj1, min1, rev1; auto num1 = sscanf_s(version_contents->c_str(), "\"%d.%d.%d\"", &maj1, &min1, &rev1); int maj2, min2, rev2; - auto num2 = sscanf_s(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/lib.cpp b/toolsrc/src/lib.cpp deleted file mode 100644 index a717344a4..000000000 --- a/toolsrc/src/lib.cpp +++ /dev/null @@ -1,509 +0,0 @@ -#include "vcpkg.h" -#include <iostream> -#include <iomanip> -#include <fstream> -#include <functional> -#include <string> -#include <unordered_map> -#include <memory> -#include <filesystem> -#include <vector> -#include <cassert> -#include "vcpkg_Files.h" -#include "vcpkg_System.h" - -using namespace vcpkg; - -bool vcpkg::g_do_dry_run = false; - -namespace -{ - template <class M, class K, class V> - auto find_or_default(const M& map, const K& key, const V& val) - { - auto it = map.find(key); - if (it == map.end()) - return decltype(it->second)(val); - else - return it->second; - } -} - -namespace -{ - std::fstream open_status_file(const vcpkg_paths& paths, std::ios_base::openmode mode = std::ios_base::app | std::ios_base::in | std::ios_base::out | std::ios_base::binary) - { - return std::fstream(paths.vcpkg_dir_status_file, mode); - } -} - -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::get_contents(vcpkg_dir_status_file).get_or_throw(); - auto pghs = 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 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); - - 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::get_contents(b->path()).get_or_throw(); - auto pghs = 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; -} - -static fs::path listfile_path(const vcpkg_paths& paths, const BinaryParagraph& pgh) -{ - return paths.vcpkg_dir_info / (pgh.fullstem() + ".list"); -} - -static std::string get_fullpkgname_from_listfile(const fs::path& path) -{ - auto ret = path.stem().generic_u8string(); - std::replace(ret.begin(), ret.end(), '_', ':'); - return ret; -} - -static fs::path prefix_path_for_package(const vcpkg_paths& paths, const BinaryParagraph& pgh) -{ - return paths.package_dir({pgh.name, pgh.target_triplet}); -} - -static 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 install_and_write_listfile(const vcpkg_paths& paths, const BinaryParagraph& bpgh) -{ - std::fstream listfile(listfile_path(paths, bpgh), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); - - auto package_prefix_path = prefix_path_for_package(paths, bpgh); - auto prefix_length = package_prefix_path.native().size(); - - std::error_code ec; - fs::create_directory(paths.installed / bpgh.target_triplet.value, ec); - listfile << bpgh.target_triplet << "\n"; - - for (auto it = fs::recursive_directory_iterator(package_prefix_path); it != fs::recursive_directory_iterator(); ++it) - { - const auto& filename = it->path().filename(); - if (fs::is_regular_file(it->status()) && (filename == "CONTROL" || filename == "control")) - { - // Do not copy the control file - continue; - } - - auto suffix = it->path().generic_u8string().substr(prefix_length + 1); - auto target = paths.installed / bpgh.target_triplet.value / suffix; - - auto status = it->status(ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - continue; - } - if (fs::is_directory(status)) - { - fs::create_directory(target, ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - } - - listfile << bpgh.target_triplet << "/" << suffix << "\n"; - } - else if (fs::is_regular_file(status)) - { - fs::copy_file(*it, target, ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - } - listfile << bpgh.target_triplet << "/" << suffix << "\n"; - } - else if (!fs::status_known(status)) - { - std::cout << "unknown status: " << *it << "\n"; - } - else - std::cout << "warning: file does not exist: " << *it << "\n"; - } - - listfile.close(); -} - -// TODO: Refactoring between this function and install_package -std::vector<std::string> vcpkg::get_unmet_package_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db) -{ - std::vector<std::unordered_map<std::string, std::string>> pghs; - const fs::path packages_dir_control_file_path = paths.package_dir(spec) / "CONTROL"; - - if (fs::exists(packages_dir_control_file_path)) - { - try - { - pghs = get_paragraphs(packages_dir_control_file_path); - } - catch (std::runtime_error) - { - // ?? - } - - Checks::check_throw(pghs.size() == 1, "Invalid control file for package"); - return BinaryParagraph(pghs[0]).depends; - } - - const fs::path ports_dir_control_file_path = paths.port_dir(spec) / "CONTROL"; - try - { - pghs = get_paragraphs(ports_dir_control_file_path); - } - catch (std::runtime_error) - { - // ?? - } - - Checks::check_exit(pghs.size() == 1, "Invalid control file for package %s", spec); - return SourceParagraph(pghs[0]).depends; -} - -void vcpkg::install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs& status_db) -{ - StatusParagraph spgh; - spgh.package = binary_paragraph; - spgh.want = want_t::install; - spgh.state = install_state_t::half_installed; - for (const std::string& dependency : spgh.package.depends) - { - if (status_db.find_installed(dependency, spgh.package.target_triplet) == status_db.end()) - { - std::abort(); - } - } - 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)); -} - -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.target_triplet != pkg.target_triplet) - continue; - - const auto& deps = inst_pkg->package.depends; - - if (std::find(deps.begin(), deps.end(), pkg.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; -} - -void vcpkg::deinstall_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(); - } - - pkg.want = want_t::purge; - pkg.state = install_state_t::half_installed; - write_update(paths, pkg); - - std::fstream listfile(listfile_path(paths, pkg.package), std::ios_base::in | std::ios_base::binary); - if (listfile) - { - std::vector<fs::path> dirs_touched; - std::string suffix; - while (std::getline(listfile, suffix)) - { - if (!suffix.empty() && suffix.back() == '\r') - suffix.pop_back(); - - std::error_code ec; - - auto target = paths.installed / suffix; - - auto status = fs::status(target, ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - continue; - } - - if (fs::is_directory(status)) - { - dirs_touched.push_back(target); - } - else if (fs::is_regular_file(status)) - { - fs::remove(target, ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - } - } - else if (!fs::status_known(status)) - { - System::println(System::color::warning, "Warning: unknown status: %s", target.string()); - } - else - { - System::println(System::color::warning, "Warning: ???: %s", target.string()); - } - } - - auto b = dirs_touched.rbegin(); - auto e = dirs_touched.rend(); - for (; b != e; ++b) - { - if (fs::directory_iterator(*b) == fs::directory_iterator()) - { - std::error_code ec; - fs::remove(*b, ec); - if (ec) - { - System::println(System::color::error, "failed: %s", ec.message()); - } - } - } - - listfile.close(); - fs::remove(listfile_path(paths, pkg.package)); - } - - 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 vcpkg::search_file(const vcpkg_paths& paths, const std::string& file_substr, const StatusParagraphs& status_db) -{ - std::string line; - - for (auto&& pgh : status_db) - { - if (pgh->state != install_state_t::installed) - continue; - - std::fstream listfile(listfile_path(paths, pgh->package)); - while (std::getline(listfile, line)) - { - if (line.empty()) - { - continue; - } - - if (line.find(file_substr) != std::string::npos) - { - System::println("%s: %s", pgh->package.displayname(), line); - } - } - } -} - -namespace -{ - struct Binaries - { - std::vector<fs::path> dlls; - std::vector<fs::path> libs; - }; - - Binaries detect_files_in_directory_ending_with(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); - } - } - - return binaries; - } - - void copy_files_into_directory(const std::vector<fs::path>& files, const fs::path& destination_folder) - { - fs::create_directory(destination_folder); - - for (auto const& src_path : files) - { - fs::path dest_path = destination_folder / src_path.filename(); - fs::copy(src_path, dest_path, fs::copy_options::overwrite_existing); - } - } - - void place_library_files_in(const fs::path& include_directory, const fs::path& project_directory, const fs::path& destination_path) - { - 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"); - - fs::path destination_include_directory = destination_path / "include"; - fs::copy(include_directory, destination_include_directory, fs::copy_options::recursive | fs::copy_options::overwrite_existing); - - copy_files_into_directory(release_binaries.dlls, destination_path / "bin"); - copy_files_into_directory(release_binaries.libs, destination_path / "lib"); - - fs::create_directory(destination_path / "debug"); - copy_files_into_directory(debug_binaries.dlls, destination_path / "debug" / "bin"); - copy_files_into_directory(debug_binaries.libs, destination_path / "debug" / "lib"); - } -} - -void vcpkg::binary_import(const vcpkg_paths& paths, const fs::path& include_directory, const fs::path& project_directory, const BinaryParagraph& control_file_data) -{ - fs::path library_destination_path = prefix_path_for_package(paths, control_file_data); - fs::create_directory(library_destination_path); - place_library_files_in(include_directory, project_directory, library_destination_path); - - fs::path control_file_path = library_destination_path / "CONTROL"; - std::ofstream(control_file_path) << control_file_data; -} diff --git a/toolsrc/src/main.cpp b/toolsrc/src/main.cpp deleted file mode 100644 index a2f6fa10f..000000000 --- a/toolsrc/src/main.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -#include <iostream> -#include <fstream> -#include <memory> -#include <cassert> -#include "vcpkg.h" -#include "vcpkg_Commands.h" -#include "metrics.h" -#include <Shlobj.h> -#include "vcpkg_Files.h" -#include "vcpkg_System.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 = {*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 = {Strings::utf16_to_utf8(vcpkg_default_triplet_env)}; - } - else - { - default_target_triplet = triplet::X86_WINDOWS; - } - } - - if(!default_target_triplet.validate(paths)) - { - System::println(System::color::error, "Error: invalid triplet: %s", default_target_triplet.value); - TrackProperty("error", "invalid triplet: " + default_target_triplet.value); - help_topic_valid_triplet(paths); - exit(EXIT_FAILURE); - } - - 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::get_contents(localappdata / "vcpkg" / "config").get_or_throw(); - - std::unordered_map<std::string, std::string> keys; - auto pghs = 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::Stopwatch 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", version()); - - const std::string trimmed_command_line = trim_path_from_command_line(Strings::utf16_to_utf8(GetCommandLineW())); - TrackProperty("cmdline", trimmed_command_line); - loadConfig(); - - 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" - << " vcpkg@microsoft.com\n" - << "containing a brief summary of what you were trying to do and the following data blob:\n" - << "\n" - << "Version=" << 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 610c71ed1..d0e20fe2d 100644 --- a/toolsrc/src/metrics.cpp +++ b/toolsrc/src/metrics.cpp @@ -1,21 +1,9 @@ +#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> +#include "filesystem_fs.h" #include "vcpkg_Strings.h" #include "vcpkg_System.h" -namespace fs = std::tr2::sys; - namespace vcpkg { static std::string GetCurrentDateTime() @@ -44,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; @@ -113,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,6 +225,16 @@ true return DISABLE_METRICS == 0; } + std::wstring GetSQMUser() + { + auto hkcu_sqmclient = System::get_registry_string(HKEY_CURRENT_USER, LR"(Software\Microsoft\SQMClient)", L"UserId"); + + if (hkcu_sqmclient) + return std::move(*hkcu_sqmclient); + else + return L"{}"; + } + void SetUserInformation(const std::string& user_id, const std::string& first_use_time) { g_metricmessage.user_id = user_id; @@ -334,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); @@ -419,7 +416,7 @@ true const fs::path vcpkg_metrics_txt_path = temp_folder_path / ("vcpkg" + GenerateRandomUUID() + ".txt"); std::ofstream(vcpkg_metrics_txt_path) << payload; - const std::wstring cmdLine = Strings::format(L"start %s %s", temp_folder_path_exe.native(), vcpkg_metrics_txt_path.native()); - System::cmd_execute(cmdLine); + const std::wstring cmdLine = Strings::wformat(L"start %s %s", temp_folder_path_exe.native(), vcpkg_metrics_txt_path.native()); + 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 efa54734e..2713e219f 100644 --- a/toolsrc/src/package_spec.cpp +++ b/toolsrc/src/package_spec.cpp @@ -1,46 +1,82 @@ +#include "pch.h" #include "package_spec.h" namespace vcpkg { - expected<package_spec> package_spec::from_string(const std::string& spec, const triplet& default_target_triplet) + static bool is_valid_package_spec_char(char c) { - auto pos = spec.find(':'); + return (c == '-') || isdigit(c) || (isalpha(c) && islower(c)); + } + + expected<package_spec> package_spec::from_string(const std::string& spec_as_string, const triplet& default_target_triplet) + { + auto pos = spec_as_string.find(':'); if (pos == std::string::npos) { - return package_spec{spec, default_target_triplet}; + return from_name_and_triplet(spec_as_string, default_target_triplet); } - auto pos2 = spec.find(':', pos + 1); + auto pos2 = spec_as_string.find(':', pos + 1); if (pos2 != std::string::npos) { - return std::error_code(package_spec_parse_result::too_many_colons); + return std::error_code(package_spec_parse_result::TOO_MANY_COLONS); + } + + const std::string name = spec_as_string.substr(0, pos); + const triplet target_triplet = triplet::from_canonical_name(spec_as_string.substr(pos + 1)); + return from_name_and_triplet(name, target_triplet); + } + + expected<package_spec> package_spec::from_name_and_triplet(const std::string& name, const triplet& target_triplet) + { + if (std::find_if_not(name.cbegin(), name.cend(), is_valid_package_spec_char) != name.end()) + { + return std::error_code(package_spec_parse_result::INVALID_CHARACTERS); } - return package_spec{spec.substr(0, pos), spec.substr(pos + 1)}; + package_spec p; + p.m_name = name; + p.m_target_triplet = target_triplet; + return p; + } + + const std::string& package_spec::name() const + { + return this->m_name; + } + + const triplet& package_spec::target_triplet() const + { + 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->name, this->target_triplet); + 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) { - return left.name == right.name && left.target_triplet == right.target_triplet; + return left.name() == right.name() && left.target_triplet() == right.target_triplet(); } 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 757b6df53..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 @@ -13,10 +13,12 @@ namespace vcpkg { switch (static_cast<package_spec_parse_result>(ev)) { - case package_spec_parse_result::success: + case package_spec_parse_result::SUCCESS: return "OK"; - case package_spec_parse_result::too_many_colons: + case package_spec_parse_result::TOO_MANY_COLONS: return "Too many colons"; + case package_spec_parse_result::INVALID_CHARACTERS: + return "Contains invalid characters. Only alphanumeric lowercase ASCII characters and dashes are allowed"; default: Checks::unreachable(); } 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/post_build_lint.cpp b/toolsrc/src/post_build_lint.cpp deleted file mode 100644 index 1d4ca0f67..000000000 --- a/toolsrc/src/post_build_lint.cpp +++ /dev/null @@ -1,356 +0,0 @@ -#include <filesystem> -#include "vcpkg_paths.h" -#include "package_spec.h" -#include <iterator> -#include <functional> -#include "vcpkg_System.h" - -namespace fs = std::tr2::sys; - -namespace vcpkg -{ - enum class lint_status - { - SUCCESS = 0, - ERROR = 1 - }; - - static const fs::path DUMPBIN_EXE = R"(%VS140COMNTOOLS%\..\..\VC\bin\dumpbin.exe)"; - - namespace - { - void print_vector_of_files(const std::vector<fs::path>& paths) - { - System::println(""); - for (const fs::path& p : paths) - { - System::println(" %s", p.generic_string()); - } - System::println(""); - } - - template <class Pred> - void recursive_find_matching_paths_in_dir(const fs::path& dir, const Pred predicate, std::vector<fs::path>& output) - { - std::copy_if(fs::recursive_directory_iterator(dir), fs::recursive_directory_iterator(), std::back_inserter(output), predicate); - } - - void recursive_find_files_with_extension_in_dir(const fs::path& dir, const std::string& extension, std::vector<fs::path>& output) - { - recursive_find_matching_paths_in_dir(dir, [&extension](const fs::path& current) - { - return !fs::is_directory(current) && current.extension() == extension; - }, output); - } - } - - static lint_status check_for_files_in_include_directory(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path include_dir = paths.packages / spec.dir() / "include"; - if (!fs::exists(include_dir) || fs::is_empty(include_dir)) - { - System::println(System::color::warning, "The folder /include is empty. This indicates the library was not correctly installed."); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_for_files_in_debug_include_directory(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path debug_include_dir = paths.packages / spec.dir() / "debug" / "include"; - std::vector<fs::path> files_found; - - recursive_find_matching_paths_in_dir(debug_include_dir, [&](const fs::path& current) - { - return !fs::is_directory(current) && current.extension() != ".ifc"; - }, files_found); - - if (!files_found.empty()) - { - System::println(System::color::warning, "Include files should not be duplicated into the /debug/include directory. If this cannot be disabled in the project cmake, use\n" - " file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include)" - ); - return - lint_status::ERROR; - } - - return - lint_status::SUCCESS; - } - - static lint_status check_for_files_in_debug_share_directory(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path debug_share = paths.packages / spec.dir() / "debug" / "share"; - - if (fs::exists(debug_share) && !fs::is_empty(debug_share)) - { - System::println(System::color::warning, "No files should be present in /debug/share"); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_folder_lib_cmake(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path lib_cmake = paths.packages / spec.dir() / "lib" / "cmake"; - if (fs::exists(lib_cmake)) - { - System::println(System::color::warning, "The /lib/cmake folder should be moved to just /cmake"); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_for_misplaced_cmake_files(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path current_packages_dir = paths.packages / spec.dir(); - std::vector<fs::path> misplaced_cmake_files; - recursive_find_files_with_extension_in_dir(current_packages_dir / "cmake", ".cmake", misplaced_cmake_files); - recursive_find_files_with_extension_in_dir(current_packages_dir / "debug" / "cmake", ".cmake", misplaced_cmake_files); - recursive_find_files_with_extension_in_dir(current_packages_dir / "lib" / "cmake", ".cmake", misplaced_cmake_files); - recursive_find_files_with_extension_in_dir(current_packages_dir / "debug" / "lib" / "cmake", ".cmake", misplaced_cmake_files); - - if (!misplaced_cmake_files.empty()) - { - System::println(System::color::warning, "The following cmake files were found outside /share/%s. Please place cmake files in /share/%s.", spec.name, spec.name); - print_vector_of_files(misplaced_cmake_files); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_folder_debug_lib_cmake(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path lib_cmake_debug = paths.packages / spec.dir() / "debug" / "lib" / "cmake"; - if (fs::exists(lib_cmake_debug)) - { - System::println(System::color::warning, "The /debug/lib/cmake folder should be moved to just /debug/cmake"); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_for_dlls_in_lib_dirs(const package_spec& spec, const vcpkg_paths& paths) - { - std::vector<fs::path> dlls; - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "lib", ".dll", dlls); - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "debug" / "lib", ".dll", dlls); - - if (!dlls.empty()) - { - System::println(System::color::warning, "\nThe following dlls were found in /lib and /debug/lib. Please move them to /bin or /debug/bin, respectively."); - print_vector_of_files(dlls); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_for_copyright_file(const package_spec& spec, const vcpkg_paths& paths) - { - const fs::path copyright_file = paths.packages / spec.dir() / "share" / spec.name / "copyright"; - if (fs::exists(copyright_file)) - { - return lint_status::SUCCESS; - } - const fs::path current_buildtrees_dir = paths.buildtrees / spec.name; - const fs::path current_buildtrees_dir_src = current_buildtrees_dir / "src"; - - std::vector<fs::path> potential_copyright_files; - // Only searching one level deep - for (auto it = fs::recursive_directory_iterator(current_buildtrees_dir_src); it != fs::recursive_directory_iterator(); ++it) - { - if (it.depth() > 1) - { - continue; - } - - const std::string filename = it->path().filename().string(); - if (filename == "LICENSE" || filename == "LICENSE.txt" || filename == "COPYING") - { - potential_copyright_files.push_back(it->path()); - } - } - - System::println(System::color::warning, "The software license must be available at ${CURRENT_PACKAGES_DIR}/share/%s/copyright .", spec.name); - if (potential_copyright_files.size() == 1) // if there is only one candidate, provide the cmake lines needed to place it in the proper location - { - const fs::path found_file = potential_copyright_files[0]; - const fs::path relative_path = found_file.string().erase(0, current_buildtrees_dir.string().size() + 1); // The +1 is needed to remove the "/" - System::println("\n file(COPY ${CURRENT_BUILDTREES_DIR}/%s DESTINATION ${CURRENT_PACKAGES_DIR}/share/%s)\n" - " file(RENAME ${CURRENT_PACKAGES_DIR}/share/%s/%s ${CURRENT_PACKAGES_DIR}/share/%s/copyright)", - relative_path.generic_string(), spec.name, spec.name, found_file.filename().generic_string(), spec.name); - return lint_status::ERROR; - } - - if (potential_copyright_files.size() > 1) - { - System::println(System::color::warning, "The following files are potential copyright files:"); - print_vector_of_files(potential_copyright_files); - } - - const fs::path current_packages_dir = paths.packages / spec.dir(); - System::println(" %s/share/%s/copyright", current_packages_dir.generic_string(), spec.name); - - return lint_status::ERROR; - } - - static lint_status check_for_exes(const package_spec& spec, const vcpkg_paths& paths) - { - std::vector<fs::path> exes; - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "bin", ".exe", exes); - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "debug" / "bin", ".exe", exes); - - if (!exes.empty()) - { - System::println(System::color::warning, "The following EXEs were found in /bin and /debug/bin. EXEs are not valid distribution targets."); - print_vector_of_files(exes); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_exports_of_dlls(const std::vector<fs::path>& dlls) - { - std::vector<fs::path> dlls_with_no_exports; - for (const fs::path& dll : dlls) - { - const std::wstring cmd_line = Strings::format(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)); - - if (ec_data.output.find("ordinal hint RVA name") == std::string::npos) - { - dlls_with_no_exports.push_back(dll); - } - } - - if (!dlls_with_no_exports.empty()) - { - System::println(System::color::warning, "The following DLLs have no exports:"); - print_vector_of_files(dlls_with_no_exports); - System::println(System::color::warning, "DLLs without any exports are likely a bug in the build script."); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static lint_status check_uwp_bit_of_dlls(const std::string& expected_system_name, const std::vector<fs::path>& dlls) - { - if (expected_system_name != "uwp") - { - return lint_status::SUCCESS; - } - - std::vector<fs::path> dlls_with_improper_uwp_bit; - for (const fs::path& dll : dlls) - { - const std::wstring cmd_line = Strings::format(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)); - - if (ec_data.output.find("App Container") == std::string::npos) - { - dlls_with_improper_uwp_bit.push_back(dll); - } - } - - if (!dlls_with_improper_uwp_bit.empty()) - { - System::println(System::color::warning, "The following DLLs do not have the App Container bit set:"); - print_vector_of_files(dlls_with_improper_uwp_bit); - System::println(System::color::warning, "This bit is required for Windows Store apps."); - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - struct file_and_arch - { - fs::path file; - std::string actual_arch; - }; - - static lint_status check_architecture(const std::string& expected_architecture, const std::vector<fs::path>& files) - { - std::vector<file_and_arch> binaries_with_invalid_architecture; - for (const fs::path& f : files) - { - const std::wstring cmd_line = Strings::format(LR"("%s" /headers "%s" | findstr machine)", DUMPBIN_EXE.native(), f.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)); - - if (Strings::case_insensitive_find(ec_data.output, expected_architecture) == ec_data.output.end()) - { - binaries_with_invalid_architecture.push_back({f, ec_data.output}); - } - } - - if (!binaries_with_invalid_architecture.empty()) - { - System::println(System::color::warning, "The following files were built for an incorrect architecture:"); - System::println(""); - for (const file_and_arch& b : binaries_with_invalid_architecture) - { - System::println(" %s", b.file.generic_string()); - System::println("Expected %s, but was:\n %s", expected_architecture, b.actual_arch); - } - System::println(""); - - return lint_status::ERROR; - } - - return lint_status::SUCCESS; - } - - static void operator +=(unsigned int& left, const lint_status& right) - { - left += static_cast<unsigned int>(right); - } - - void perform_all_checks(const package_spec& spec, const vcpkg_paths& paths) - { - System::println("-- Performing post-build validation"); - unsigned int error_count = 0; - error_count += check_for_files_in_include_directory(spec, paths); - error_count += check_for_files_in_debug_include_directory(spec, paths); - error_count += check_for_files_in_debug_share_directory(spec, paths); - error_count += check_folder_lib_cmake(spec, paths); - error_count += check_for_misplaced_cmake_files(spec, paths); - error_count += check_folder_debug_lib_cmake(spec, paths); - error_count += check_for_dlls_in_lib_dirs(spec, paths); - error_count += check_for_copyright_file(spec, paths); - error_count += check_for_exes(spec, paths); - - std::vector<fs::path> dlls; - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "bin", ".dll", dlls); - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "debug" / "bin", ".dll", dlls); - - error_count += check_exports_of_dlls(dlls); - error_count += check_uwp_bit_of_dlls(spec.target_triplet.system(), dlls); - error_count += check_architecture(spec.target_triplet.architecture(), dlls); - - std::vector<fs::path> libs; - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "lib", ".lib", libs); - recursive_find_files_with_extension_in_dir(paths.packages / spec.dir() / "debug" / "lib", ".lib", libs); - - error_count += check_architecture(spec.target_triplet.architecture(), libs); - - if (error_count != 0) - { - const fs::path portfile = paths.ports / spec.name / "portfile.cmake"; - System::println(System::color::error, "Found %d error(s). Please correct the portfile:\n %s", error_count, portfile.string()); - exit(EXIT_FAILURE); - } - - System::println("-- Performing post-build validation done"); - } -} diff --git a/toolsrc/src/tests_dependencies.cpp b/toolsrc/src/tests_dependencies.cpp new file mode 100644 index 000000000..bce1cab0e --- /dev/null +++ b/toolsrc/src/tests_dependencies.cpp @@ -0,0 +1,39 @@ +#include "CppUnitTest.h" +#include "SourceParagraph.h" +#include "triplet.h" + +#pragma comment(lib,"version") +#pragma comment(lib,"winhttp") + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +using namespace vcpkg; + +namespace UnitTest1 +{ + TEST_CLASS(DependencyTests) + { + public: + TEST_METHOD(parse_depends_one) + { + auto v = expand_qualified_dependencies(parse_depends("libA [windows]")); + Assert::AreEqual(size_t(1), v.size()); + Assert::AreEqual("libA", v[0].name.c_str()); + Assert::AreEqual("windows", v[0].qualifier.c_str()); + } + + TEST_METHOD(filter_depends) + { + auto deps = expand_qualified_dependencies(parse_depends("libA [windows], libB, libC [uwp]")); + auto v = filter_dependencies(deps, triplet::X64_WINDOWS); + Assert::AreEqual(size_t(2), v.size()); + Assert::AreEqual("libA", v[0].c_str()); + Assert::AreEqual("libB", v[1].c_str()); + + auto v2 = filter_dependencies(deps, triplet::ARM_UWP); + Assert::AreEqual(size_t(2), v.size()); + Assert::AreEqual("libB", v2[0].c_str()); + Assert::AreEqual("libC", v2[1].c_str()); + } + }; +} diff --git a/toolsrc/src/test.cpp b/toolsrc/src/tests_paragraph.cpp index 9c5f1dc87..fb20eee82 100644 --- a/toolsrc/src/test.cpp +++ b/toolsrc/src/tests_paragraph.cpp @@ -1,19 +1,20 @@ #include "CppUnitTest.h" -#include "vcpkg.h" +#include "Paragraphs.h" +#include "BinaryParagraph.h" #pragma comment(lib,"version") #pragma comment(lib,"winhttp") 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 { @@ -48,7 +49,7 @@ namespace UnitTest1 Assert::AreEqual("m", pgh.maintainer.c_str()); Assert::AreEqual("d", pgh.description.c_str()); Assert::AreEqual(size_t(1), pgh.depends.size()); - Assert::AreEqual("bd", pgh.depends[0].c_str()); + Assert::AreEqual("bd", pgh.depends[0].name.c_str()); } TEST_METHOD(SourceParagraph_Two_Depends) @@ -60,8 +61,8 @@ namespace UnitTest1 }); Assert::AreEqual(size_t(2), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].c_str()); - Assert::AreEqual("openssl", pgh.depends[1].c_str()); + Assert::AreEqual("z", pgh.depends[0].name.c_str()); + Assert::AreEqual("openssl", pgh.depends[1].name.c_str()); } TEST_METHOD(SourceParagraph_Three_Depends) @@ -73,9 +74,28 @@ namespace UnitTest1 }); Assert::AreEqual(size_t(3), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].c_str()); - Assert::AreEqual("openssl", pgh.depends[1].c_str()); - Assert::AreEqual("xyz", pgh.depends[2].c_str()); + Assert::AreEqual("z", pgh.depends[0].name.c_str()); + Assert::AreEqual("openssl", pgh.depends[1].name.c_str()); + Assert::AreEqual("xyz", pgh.depends[2].name.c_str()); + } + + TEST_METHOD(SourceParagraph_Construct_Qualified_Depends) + { + vcpkg::SourceParagraph pgh({ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "libA [windows], libB [uwp]"} + }); + + Assert::AreEqual("zlib", pgh.name.c_str()); + Assert::AreEqual("1.2.8", pgh.version.c_str()); + Assert::AreEqual("", pgh.maintainer.c_str()); + Assert::AreEqual("", pgh.description.c_str()); + Assert::AreEqual(size_t(2), pgh.depends.size()); + Assert::AreEqual("libA", pgh.depends[0].name.c_str()); + Assert::AreEqual("windows", pgh.depends[0].qualifier.c_str()); + Assert::AreEqual("libB", pgh.depends[1].name.c_str()); + Assert::AreEqual("uwp", pgh.depends[1].qualifier.c_str()); } TEST_METHOD(BinaryParagraph_Construct_Minimum) @@ -83,15 +103,15 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "zlib"}, {"Version", "1.2.8"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Multi-Arch", "same"}, }); - Assert::AreEqual("zlib", pgh.name.c_str()); + Assert::AreEqual("zlib", pgh.spec.name().c_str()); Assert::AreEqual("1.2.8", pgh.version.c_str()); Assert::AreEqual("", pgh.maintainer.c_str()); Assert::AreEqual("", pgh.description.c_str()); - Assert::AreEqual("a", pgh.target_triplet.value.c_str()); + Assert::AreEqual("x86-windows", pgh.spec.target_triplet().canonical_name().c_str()); Assert::AreEqual(size_t(0), pgh.depends.size()); } @@ -100,13 +120,13 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "s"}, {"Version", "v"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Multi-Arch", "same"}, {"Maintainer", "m"}, {"Description", "d"}, {"Depends", "bd"} }); - Assert::AreEqual("s", pgh.name.c_str()); + Assert::AreEqual("s", pgh.spec.name().c_str()); Assert::AreEqual("v", pgh.version.c_str()); Assert::AreEqual("m", pgh.maintainer.c_str()); Assert::AreEqual("d", pgh.description.c_str()); @@ -119,7 +139,7 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "zlib"}, {"Version", "1.2.8"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Multi-Arch", "same"}, {"Depends", "a, b, c"}, }); @@ -133,14 +153,14 @@ namespace UnitTest1 TEST_METHOD(parse_paragraphs_empty) { const char* str = ""; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::IsTrue(pghs.empty()); } TEST_METHOD(parse_paragraphs_one_field) { const char* str = "f1: v1"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(1), pghs[0].size()); Assert::AreEqual("v1", pghs[0]["f1"].c_str()); @@ -151,7 +171,7 @@ namespace UnitTest1 const char* str = "f1: v1\n" "f2: v2"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(2), pghs[0].size()); Assert::AreEqual("v1", pghs[0]["f1"].c_str()); @@ -166,7 +186,7 @@ namespace UnitTest1 "\n" "f3: v3\n" "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(2), pghs.size()); Assert::AreEqual(size_t(2), pghs[0].size()); Assert::AreEqual("v1", pghs[0]["f1"].c_str()); @@ -184,7 +204,7 @@ namespace UnitTest1 "F:\n" "0:\n" "F-2:\n"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(5), pghs[0].size()); } @@ -198,7 +218,7 @@ namespace UnitTest1 "\n" "f3: v3\n" "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(2), pghs.size()); } @@ -207,7 +227,7 @@ namespace UnitTest1 const char* str = "f1:\n" "f2: "; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(2), pghs[0].size()); Assert::AreEqual("", pghs[0]["f1"].c_str()); @@ -223,7 +243,7 @@ namespace UnitTest1 "f2:\r\n" " f2\r\n" " continue\r\n"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual("simple\n f1", pghs[0]["f1"].c_str()); Assert::AreEqual("\n f2\n continue", pghs[0]["f2"].c_str()); @@ -237,7 +257,7 @@ namespace UnitTest1 "\r\n" "f3: v3\r\n" "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str); Assert::AreEqual(size_t(2), pghs.size()); Assert::AreEqual(size_t(2), pghs[0].size()); Assert::AreEqual("v1", pghs[0]["f1"].c_str()); @@ -253,16 +273,16 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "zlib"}, {"Version", "1.2.8"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Multi-Arch", "same"}, }); ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss.str()); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(4), pghs[0].size()); Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("a", pghs[0]["Architecture"].c_str()); + Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); } @@ -272,19 +292,19 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "zlib"}, {"Version", "1.2.8"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Description", "first line\n second line"}, {"Maintainer", "abc <abc@abc.abc>"}, {"Depends", "dep"}, {"Multi-Arch", "same"}, }); ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss.str()); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual(size_t(7), pghs[0].size()); Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("a", pghs[0]["Architecture"].c_str()); + Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); Assert::AreEqual("first line\n second line", pghs[0]["Description"].c_str()); Assert::AreEqual("dep", pghs[0]["Depends"].c_str()); @@ -296,12 +316,12 @@ namespace UnitTest1 vcpkg::BinaryParagraph pgh({ {"Package", "zlib"}, {"Version", "1.2.8"}, - {"Architecture", "a"}, + {"Architecture", "x86-windows"}, {"Multi-Arch", "same"}, {"Depends", "a, b, c"}, }); ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss.str()); Assert::AreEqual(size_t(1), pghs.size()); Assert::AreEqual("a, b, c", pghs[0]["Depends"].c_str()); } @@ -309,23 +329,23 @@ namespace UnitTest1 TEST_METHOD(package_spec_parse) { vcpkg::expected<vcpkg::package_spec> spec = vcpkg::package_spec::from_string("zlib", vcpkg::triplet::X86_WINDOWS); - Assert::AreEqual(vcpkg::package_spec_parse_result::success, vcpkg::to_package_spec_parse_result(spec.error_code())); - Assert::AreEqual("zlib", spec.get()->name.c_str()); - Assert::AreEqual(vcpkg::triplet::X86_WINDOWS.value, spec.get()->target_triplet.value); + Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); + Assert::AreEqual("zlib", spec.get()->name().c_str()); + Assert::AreEqual(vcpkg::triplet::X86_WINDOWS.canonical_name(), spec.get()->target_triplet().canonical_name()); } TEST_METHOD(package_spec_parse_with_arch) { vcpkg::expected<vcpkg::package_spec> spec = vcpkg::package_spec::from_string("zlib:x64-uwp", vcpkg::triplet::X86_WINDOWS); - Assert::AreEqual(vcpkg::package_spec_parse_result::success, vcpkg::to_package_spec_parse_result(spec.error_code())); - Assert::AreEqual("zlib", spec.get()->name.c_str()); - Assert::AreEqual(vcpkg::triplet::X64_UWP.value, spec.get()->target_triplet.value); + Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); + Assert::AreEqual("zlib", spec.get()->name().c_str()); + Assert::AreEqual(vcpkg::triplet::X64_UWP.canonical_name(), spec.get()->target_triplet().canonical_name()); } TEST_METHOD(package_spec_parse_with_multiple_colon) { auto ec = vcpkg::package_spec::from_string("zlib:x86-uwp:", vcpkg::triplet::X86_WINDOWS).error_code(); - Assert::AreEqual(vcpkg::package_spec_parse_result::too_many_colons, vcpkg::to_package_spec_parse_result(ec)); + Assert::AreEqual(vcpkg::package_spec_parse_result::TOO_MANY_COLONS, vcpkg::to_package_spec_parse_result(ec)); } TEST_METHOD(utf8_to_utf16) diff --git a/toolsrc/src/triplet.cpp b/toolsrc/src/triplet.cpp index 14f19d5cd..d91e0e68f 100644 --- a/toolsrc/src/triplet.cpp +++ b/toolsrc/src/triplet.cpp @@ -1,19 +1,19 @@ +#include "pch.h" #include "triplet.h" -#include "vcpkg.h" -#include "vcpkg_System.h" #include "vcpkg_Checks.h" +#include "vcpkg_Strings.h" namespace vcpkg { - const triplet triplet::X86_WINDOWS = {"x86-windows"}; - const triplet triplet::X64_WINDOWS = {"x64-windows"}; - const triplet triplet::X86_UWP = {"x86-uwp"}; - const triplet triplet::X64_UWP = {"x64-uwp"}; - const triplet triplet::ARM_UWP = {"arm-uwp"}; + const triplet triplet::X86_WINDOWS = from_canonical_name("x86-windows"); + const triplet triplet::X64_WINDOWS = from_canonical_name("x64-windows"); + const triplet triplet::X86_UWP = from_canonical_name("x86-uwp"); + const triplet triplet::X64_UWP = from_canonical_name("x64-uwp"); + const triplet triplet::ARM_UWP = from_canonical_name("arm-uwp"); std::string to_string(const triplet& t) { - return t.value; + return t.canonical_name(); } std::string to_printf_arg(const triplet& t) @@ -23,7 +23,7 @@ namespace vcpkg bool operator==(const triplet& left, const triplet& right) { - return left.value == right.value; + return left.canonical_name() == right.canonical_name(); } bool operator!=(const triplet& left, const triplet& right) @@ -36,40 +36,31 @@ namespace vcpkg return os << to_string(t); } - std::string triplet::architecture() const + triplet triplet::from_canonical_name(const std::string& triplet_as_string) { - if (*this == X86_WINDOWS || *this == X86_UWP) - return "x86"; - if (*this == X64_WINDOWS || *this == X64_UWP) - return "x64"; - if (*this == ARM_UWP) - return "arm"; + 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); - Checks::exit_with_message("Unknown architecture: %s", value); + triplet t; + t.m_canonical_name = s; + return t; } - std::string triplet::system() const + const std::string& triplet::canonical_name() const { - if (*this == X86_WINDOWS || *this == X64_WINDOWS) - return "windows"; - if (*this == X86_UWP || *this == X64_UWP || *this == ARM_UWP) - return "uwp"; + return this->m_canonical_name; + } - Checks::exit_with_message("Unknown system: %s", value); + std::string triplet::architecture() const + { + auto it = std::find(this->m_canonical_name.cbegin(), this->m_canonical_name.cend(), '-'); + return std::string(this->m_canonical_name.cbegin(), it); } - bool triplet::validate(const vcpkg_paths & paths) + std::string triplet::system() const { - auto it = fs::directory_iterator(paths.triplets); - for(; it != fs::directory_iterator(); ++it) - { - std::string triplet_file_name = it->path().stem().generic_u8string(); - if(value == triplet_file_name) // TODO: fuzzy compare - { - //value = triplet_file_name; // NOTE: uncomment when implementing fuzzy compare - return true; - } - } - return false; + auto it = std::find(this->m_canonical_name.cbegin(), this->m_canonical_name.cend(), '-'); + return std::string(it + 1, this->m_canonical_name.cend()); } } diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index f705858cc..e94d2538b 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -1,178 +1,250 @@ -#include "vcpkg.h" -#include <regex> +#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 "vcpkglib_helpers.h" +#include "vcpkg_System.h" +#include "vcpkg_Input.h" +#include "Paragraphs.h" +#include "vcpkg_Strings.h" +#include "vcpkg_Chrono.h" -namespace +using namespace vcpkg; + +bool g_debugging = false; + +void invalid_command(const std::string& cmd) { - using namespace vcpkg; + System::println(System::color::error, "invalid command: %s", cmd); + Commands::Help::print_usage(); + exit(EXIT_FAILURE); +} - struct Parser +static void inner(const vcpkg_cmd_arguments& args) +{ + TrackProperty("command", args.command); + if (args.command.empty()) { - Parser(const char* c, const char* e) : cur(c), end(e) - { - } + Commands::Help::print_usage(); + exit(EXIT_FAILURE); + } - private: - const char* cur; - const char* const end; + if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_c())) + { + return command_function(args); + } - void peek(char& ch) const + 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) { - if (cur == end) - ch = 0; - else - ch = *cur; + vcpkg_root_dir = fs::absolute(*vcpkg_root_dir_env); } - - void next(char& ch) + else { - if (cur == end) - ch = 0; - else - { - ++cur; - peek(ch); - } + vcpkg_root_dir = Files::find_file_recursively_up(fs::absolute(System::get_exe_path_of_current_process()), ".vcpkg-root"); } + } - void skip_spaces(char& ch) - { - while (ch == ' ' || ch == '\t') - next(ch); - } + Checks::check_exit(!vcpkg_root_dir.empty(), "Error: Could not detect vcpkg-root."); - static bool is_alphanum(char ch) - { - return (ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z') - || (ch >= '0' && ch <= '9'); - } + 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"); - static bool is_lineend(char ch) - { - return ch == '\r' || ch == '\n' || ch == 0; - } + if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_b())) + { + return command_function(args, paths); + } - void get_fieldvalue(char& ch, std::string& fieldvalue) + triplet default_target_triplet; + if (args.target_triplet != nullptr) + { + 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) { - fieldvalue.clear(); - - auto beginning_of_line = cur; - do - { - // scan to end of current line (it is part of the field value) - while (!is_lineend(ch)) - next(ch); - - fieldvalue.append(beginning_of_line, cur); - - if (ch == '\r') - next(ch); - if (ch == '\n') - next(ch); - - if (is_alphanum(ch)) - { - // Line begins a new field. - return; - } - - beginning_of_line = cur; - - // Line may continue the current field with data or terminate the paragraph, - // depending on first nonspace character. - skip_spaces(ch); - - if (is_lineend(ch)) - { - // Line was whitespace or empty. - // This terminates the field and the paragraph. - // We leave the blank line's whitespace consumed, because it doesn't matter. - return; - } - - // First nonspace is not a newline. This continues the current field value. - // We forcibly convert all newlines into single '\n' for ease of text handling later on. - fieldvalue.push_back('\n'); - } - while (true); + default_target_triplet = triplet::from_canonical_name(Strings::utf16_to_utf8(*vcpkg_default_triplet_env)); } - - void get_fieldname(char& ch, std::string& fieldname) + else { - auto begin_fieldname = cur; - while (is_alphanum(ch) || ch == '-') - next(ch); - Checks::check_throw(ch == ':', "Expected ':'"); - fieldname = std::string(begin_fieldname, cur); - - // skip ': ' - next(ch); - skip_spaces(ch); + default_target_triplet = triplet::X86_WINDOWS; } + } - void get_paragraph(char& ch, std::unordered_map<std::string, std::string>& fields) - { - fields.clear(); - std::string fieldname; - std::string fieldvalue; - do - { - get_fieldname(ch, fieldname); + Input::check_triplet(default_target_triplet, paths); - auto it = fields.find(fieldname); - Checks::check_throw(it == fields.end(), "Duplicate field"); + if (auto command_function = Commands::find(args.command, Commands::get_available_commands_type_a())) + { + return command_function(args, paths, default_target_triplet); + } - get_fieldvalue(ch, fieldvalue); + return invalid_command(args.command); +} - fields.emplace(fieldname, fieldvalue); - } - while (!is_lineend(ch)); - } +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(); - public: - std::vector<std::unordered_map<std::string, std::string>> get_paragraphs() + 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) { - std::vector<std::unordered_map<std::string, std::string>> paragraphs; + for (auto&& p : pghs[x]) + keys.insert(p); + } - char ch; - peek(ch); + 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 - while (ch != 0) - { - if (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t') - { - next(ch); - continue; - } + SetUserInformation(user_id, user_time); + return; + } + catch (...) + { + } - paragraphs.emplace_back(); - get_paragraph(ch, paragraphs.back()); - } + // 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 (...) + { + } +} - return paragraphs; - } - }; +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()); } -namespace vcpkg +static ElapsedTime g_timer; + +int wmain(const int argc, const wchar_t* const* const argv) { - std::string shorten_description(const std::string& desc) + if (argc == 0) + std::abort(); + + g_timer = ElapsedTime::createStarted(); + atexit([]() + { + 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 vcpkg_cmd_arguments args = vcpkg_cmd_arguments::create_from_command_line(argc, argv); + + 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); + + if (args.debug != opt_bool_t::UNSPECIFIED) { - auto simple_desc = std::regex_replace(desc.substr(0, 49), std::regex("\\n( |\\t)?"), ""); - if (desc.size() > 49) - simple_desc.append("..."); - return simple_desc; + g_debugging = (args.debug == opt_bool_t::ENABLED); } - std::vector<std::unordered_map<std::string, std::string>> get_paragraphs(const fs::path& control_path) + if (g_debugging) { - return parse_paragraphs(Files::get_contents(control_path).get_or_throw()); + inner(args); + exit(EXIT_FAILURE); } - std::vector<std::unordered_map<std::string, std::string>> parse_paragraphs(const std::string& str) + std::string exc_msg; + try + { + inner(args); + exit(EXIT_FAILURE); + } + catch (std::exception& e) + { + exc_msg = e.what(); + } + catch (...) { - return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); + exc_msg = "unknown error(...)"; } + 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 d5433b1f5..02d3480a2 100644 --- a/toolsrc/src/vcpkg_Checks.cpp +++ b/toolsrc/src/vcpkg_Checks.cpp @@ -1,23 +1,26 @@ +#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 + std::abort(); +#else exit(EXIT_FAILURE); +#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); } @@ -30,12 +33,19 @@ namespace vcpkg {namespace Checks } } - void check_exit(bool expression, const char* errorMessage) + void check_exit(bool expression) { if (!expression) { - System::println(System::color::error, errorMessage); exit(EXIT_FAILURE); } } -}} + + void check_exit(bool expression, const char* errorMessage) + { + if (!expression) + { + exit_with_message(errorMessage); + } + } +} diff --git a/toolsrc/src/vcpkg_Chrono.cpp b/toolsrc/src/vcpkg_Chrono.cpp new file mode 100644 index 000000000..e39842df9 --- /dev/null +++ b/toolsrc/src/vcpkg_Chrono.cpp @@ -0,0 +1,63 @@ +#include "pch.h" +#include "vcpkg_Chrono.h" +#include "vcpkg_Checks.h" + +namespace vcpkg +{ + static std::string format_time_userfriendly(const std::chrono::nanoseconds& nanos) + { + using std::chrono::hours; + using std::chrono::minutes; + using std::chrono::seconds; + using std::chrono::milliseconds; + using std::chrono::microseconds; + using std::chrono::nanoseconds; + using std::chrono::duration_cast; + + const double nanos_as_double = static_cast<double>(nanos.count()); + + if (duration_cast<hours>(nanos) > hours()) + { + auto t = nanos_as_double / duration_cast<nanoseconds>(hours(1)).count(); + return Strings::format("%.4g h", t); + } + + if (duration_cast<minutes>(nanos) > minutes()) + { + auto t = nanos_as_double / duration_cast<nanoseconds>(minutes(1)).count(); + return Strings::format("%.4g min", t); + } + + if (duration_cast<seconds>(nanos) > seconds()) + { + auto t = nanos_as_double / duration_cast<nanoseconds>(seconds(1)).count(); + return Strings::format("%.4g s", t); + } + + if (duration_cast<milliseconds>(nanos) > milliseconds()) + { + auto t = nanos_as_double / duration_cast<nanoseconds>(milliseconds(1)).count(); + return Strings::format("%.4g ms", t); + } + + if (duration_cast<microseconds>(nanos) > microseconds()) + { + auto t = nanos_as_double / duration_cast<nanoseconds>(microseconds(1)).count(); + return Strings::format("%.4g us", t); + } + + return Strings::format("%.4g ns", nanos_as_double); + } + + ElapsedTime ElapsedTime::createStarted() + { + ElapsedTime t; + t.m_startTick = std::chrono::high_resolution_clock::now(); + return t; + } + + std::string ElapsedTime::toString() const + { + return format_time_userfriendly(elapsed<std::chrono::nanoseconds>()); + } +} diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp index 6ffb4959d..e8bf10617 100644 --- a/toolsrc/src/vcpkg_Dependencies.cpp +++ b/toolsrc/src/vcpkg_Dependencies.cpp @@ -1,26 +1,114 @@ +#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.h" -#include "vcpkg_Maps.h" -#include "vcpkg_Sets.h" +#include "vcpkg_Files.h" +#include "Paragraphs.h" -namespace vcpkg { namespace Dependencies +namespace vcpkg::Dependencies { - static Graphs::Graph<package_spec> build_dependency_graph(const vcpkg_paths& paths, const std::vector<package_spec>& specs, const StatusParagraphs& status_db) + 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 + Graphs::Graph<package_spec> graph; + graph.add_vertices(specs); + std::vector<package_spec> examine_stack(specs); - std::unordered_set<package_spec> was_examined; // Examine = we have checked its immediate (non-recursive) dependencies + while (!examine_stack.empty()) + { + const package_spec spec = examine_stack.back(); + examine_stack.pop_back(); + + if (was_examined.find(spec) != was_examined.end()) + { + continue; + } + + auto process_dependencies = [&](const std::vector<std::string>& dependencies_as_string) + { + for (const std::string& dep_as_string : dependencies_as_string) + { + const package_spec current_dep = package_spec::from_name_and_triplet(dep_as_string, spec.target_triplet()).get_or_throw(); + graph.add_edge(spec, current_dep); + if (was_examined.find(current_dep) == was_examined.end()) + { + examine_stack.push_back(std::move(current_dep)); + } + } + }; + + auto it = status_db.find(spec); + if (it != status_db.end() && (*it)->want == want_t::install) + { + was_examined.emplace(spec, install_plan_action{install_plan_type::ALREADY_INSTALLED, nullptr, nullptr}); + continue; + } + + expected<BinaryParagraph> maybe_bpgh = Paragraphs::try_load_cached_package(paths, spec); + if (BinaryParagraph* bpgh = maybe_bpgh.get()) + { + process_dependencies(bpgh->depends); + was_examined.emplace(spec, install_plan_action{install_plan_type::INSTALL, std::make_unique<BinaryParagraph>(std::move(*bpgh)), nullptr}); + continue; + } + + 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())); + was_examined.emplace(spec, install_plan_action{install_plan_type::BUILD_AND_INSTALL, nullptr, std::make_unique<SourceParagraph>(std::move(*spgh))}); + } + + std::vector<package_spec_with_install_plan> ret; + + const std::vector<package_spec> pkgs = graph.find_topological_sort(); + for (const package_spec& pkg : pkgs) + { + 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(examine_stack); + graph.add_vertices(specs); + std::vector<package_spec> examine_stack(specs); while (!examine_stack.empty()) { - package_spec spec = examine_stack.back(); + const package_spec spec = examine_stack.back(); examine_stack.pop_back(); if (was_examined.find(spec) != was_examined.end()) @@ -28,40 +116,41 @@ namespace vcpkg { namespace Dependencies continue; } - std::vector<std::string> dependencies_as_string = get_unmet_package_dependencies(paths, spec, status_db); + 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::string& dep_as_string : dependencies_as_string) + for (const std::unique_ptr<StatusParagraph>& an_installed_package : status_db) { - package_spec current_dep = {dep_as_string, spec.target_triplet}; - auto it = status_db.find(current_dep.name, current_dep.target_triplet); - if (it != status_db.end() && (*it)->want == want_t::install) - { + if (an_installed_package->want != want_t::install) + continue; + if (an_installed_package->package.spec.target_triplet() != spec.target_triplet()) continue; - } - graph.add_edge(spec, current_dep); - if (was_examined.find(current_dep) == was_examined.end()) + const std::vector<std::string>& deps = an_installed_package->package.depends; + if (std::find(deps.begin(), deps.end(), spec.name()) == deps.end()) { - examine_stack.push_back(std::move(current_dep)); + continue; } + + graph.add_edge(spec, an_installed_package.get()->package.spec); + examine_stack.push_back(an_installed_package.get()->package.spec); } - was_examined.insert(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)); } - return graph; - } - - std::vector<package_spec> create_dependency_ordered_install_plan(const vcpkg_paths& paths, const std::vector<package_spec>& specs, const StatusParagraphs& status_db) - { - return build_dependency_graph(paths, specs, status_db).find_topological_sort(); - } + std::vector<package_spec_with_remove_plan> ret; - std::unordered_set<package_spec> find_unmet_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db) - { - const Graphs::Graph<package_spec> dependency_graph = build_dependency_graph(paths, {spec}, status_db); - std::unordered_set<package_spec> key_set = Maps::extract_key_set(dependency_graph.adjacency_list()); - key_set.erase(spec); - return key_set; + 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 f70f2b893..8aaaba8a8 100644 --- a/toolsrc/src/vcpkg_Environment.cpp +++ b/toolsrc/src/vcpkg_Environment.cpp @@ -1,87 +1,187 @@ -#include <regex> -#include <array> +#include "pch.h" #include "vcpkg_Environment.h" #include "vcpkg_Commands.h" -#include "vcpkg.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::format(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::format(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::format(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 611aa7450..57d4c665c 100644 --- a/toolsrc/src/vcpkg_Files.cpp +++ b/toolsrc/src/vcpkg_Files.cpp @@ -1,25 +1,22 @@ +#include "pch.h" #include "vcpkg_Files.h" -#include <fstream> -#include <filesystem> -#include <regex> +#include "vcpkg_System.h" -namespace fs = std::tr2::sys; - -namespace vcpkg {namespace Files +namespace vcpkg::Files { static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); void check_is_directory(const fs::path& dirpath) { - Checks::check_throw(fs::is_directory(dirpath), "The path %s is not a directory", dirpath.string()); + Checks::check_exit(fs::is_directory(dirpath), "The path %s is not a directory", dirpath.string()); } - bool has_invalid_chars_for_filesystem(const std::string s) + bool has_invalid_chars_for_filesystem(const std::string& s) { return std::regex_search(s, FILESYSTEM_INVALID_CHARACTERS_REGEX); } - expected<std::string> get_contents(const fs::path& file_path) noexcept + expected<std::string> read_contents(const fs::path& file_path) noexcept { std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary); if (file_stream.fail()) @@ -44,6 +41,35 @@ namespace vcpkg {namespace Files return std::move(output); } + expected<std::vector<std::string>> read_all_lines(const fs::path& file_path) + { + std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary); + if (file_stream.fail()) + { + return std::errc::no_such_file_or_directory; + } + + std::vector<std::string> output; + std::string line; + while (std::getline(file_stream, line)) + { + output.push_back(line); + } + file_stream.close(); + + return std::move(output); + } + + void write_all_lines(const fs::path& file_path, const std::vector<std::string>& lines) + { + std::fstream output(file_path, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); + for (const std::string& line : lines) + { + output << line << "\n"; + } + output.close(); + } + fs::path find_file_recursively_up(const fs::path& starting_dir, const std::string& filename) { fs::path current_dir = starting_dir; @@ -58,4 +84,59 @@ namespace vcpkg {namespace Files return current_dir; } -}} + + void recursive_find_files_with_extension_in_dir(const fs::path& dir, const std::string& extension, std::vector<fs::path>* output) + { + recursive_find_matching_paths_in_dir(dir, [&extension](const fs::path& current) + { + return !fs::is_directory(current) && current.extension() == extension; + }, output); + } + + std::vector<fs::path> recursive_find_files_with_extension_in_dir(const fs::path& dir, const std::string& extension) + { + std::vector<fs::path> v; + recursive_find_files_with_extension_in_dir(dir, extension, &v); + return v; + } + + 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) + { + return !fs::is_directory(current); + }, output); + } + + std::vector<fs::path> recursive_find_all_files_in_dir(const fs::path& dir) + { + std::vector<fs::path> v; + recursive_find_all_files_in_dir(dir, &v); + return v; + } + + 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) + { + return !fs::is_directory(current); + }, output); + } + + std::vector<fs::path> non_recursive_find_all_files_in_dir(const fs::path& dir) + { + std::vector<fs::path> v; + non_recursive_find_all_files_in_dir(dir, &v); + return v; + } + + void print_paths(const std::vector<fs::path>& paths) + { + System::println(""); + for (const fs::path& p : paths) + { + System::println(" %s", p.generic_string()); + } + System::println(""); + } +} diff --git a/toolsrc/src/vcpkg_Input.cpp b/toolsrc/src/vcpkg_Input.cpp new file mode 100644 index 000000000..5720cadc0 --- /dev/null +++ b/toolsrc/src/vcpkg_Input.cpp @@ -0,0 +1,53 @@ +#include "pch.h" +#include "vcpkg_Input.h" +#include "vcpkg_System.h" +#include "metrics.h" +#include "vcpkg_Commands.h" + +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) + { + const std::string as_lowercase = Strings::ascii_to_lowercase(package_spec_as_string); + expected<package_spec> expected_spec = package_spec::from_string(as_lowercase, default_target_triplet); + if (auto spec = expected_spec.get()) + { + return *spec; + } + + // Intentionally show the lowercased string + System::println(System::color::error, "Error: %s: %s", expected_spec.error_code().message(), as_lowercase); + System::print(example_text); + exit(EXIT_FAILURE); + } + + std::vector<package_spec> check_and_get_package_specs(const std::vector<std::string>& package_specs_as_strings, const triplet& default_target_triplet, const std::string& example_text) + { + std::vector<package_spec> specs; + for (const std::string& spec : package_specs_as_strings) + { + specs.push_back(check_and_get_package_spec(spec, default_target_triplet, example_text)); + } + + return specs; + } + + void check_triplet(const triplet& t, const vcpkg_paths& paths) + { + if (!paths.is_valid_triplet(t)) + { + System::println(System::color::error, "Error: invalid triplet: %s", t.canonical_name()); + TrackProperty("error", "invalid triplet: " + t.canonical_name()); + Commands::Help::help_topic_valid_triplet(paths); + exit(EXIT_FAILURE); + } + } + + 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 b0312536a..044fd3c05 100644 --- a/toolsrc/src/vcpkg_Strings.cpp +++ b/toolsrc/src/vcpkg_Strings.cpp @@ -1,40 +1,54 @@ +#include "pch.h" #include "vcpkg_Strings.h" -#include <cstdarg> -#include <algorithm> -#include <codecvt> -#include <iterator> - -namespace vcpkg {namespace Strings {namespace details +namespace vcpkg::Strings::details { + // To disambiguate between two overloads + static const auto isspace = [](const char c) + { + 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; } - std::wstring format_internal(const wchar_t* fmtstr, ...) + std::wstring wformat_internal(const wchar_t* fmtstr, ...) { 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) { @@ -48,13 +62,75 @@ namespace vcpkg {namespace Strings return conversion.to_bytes(w); } - std::string::const_iterator case_insensitive_find(const std::string& s, const std::string& pattern) + std::string::const_iterator case_insensitive_ascii_find(const std::string& s, const std::string& pattern) { - std::string patter_as_lower_case; - std::transform(pattern.begin(), pattern.end(), back_inserter(patter_as_lower_case), tolower); - return search(s.begin(), s.end(), patter_as_lower_case.begin(), patter_as_lower_case.end(), [](const char a, const char b) + 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(), &details::tolower_char); + return output; + } + + std::string join(const std::string& delimiter, const std::vector<std::string>& v) + { + return join(delimiter, v, [](const std::string& p) -> const std::string& { return p; }); + } + + 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) + { + s->erase(std::find_if_not(s->rbegin(), s->rend(), details::isspace).base(), s->end()); + s->erase(s->begin(), std::find_if_not(s->begin(), s->end(), details::isspace)); + } + + std::string trimmed(const std::string& s) + { + auto whitespace_back = std::find_if_not(s.rbegin(), s.rend(), details::isspace).base(); + auto whitespace_front = std::find_if_not(s.begin(), whitespace_back, details::isspace); + return std::string(whitespace_front, whitespace_back); + } + + void trim_all_and_remove_whitespace_strings(std::vector<std::string>* strings) + { + for (std::string& s : *strings) + { + trim(&s); + } + + strings->erase(std::remove_if(strings->begin(), strings->end(), [](const std::string& s)-> bool + { + 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 71b4087d2..472f8450f 100644 --- a/toolsrc/src/vcpkg_System.cpp +++ b/toolsrc/src/vcpkg_System.cpp @@ -1,39 +1,116 @@ +#include "pch.h" #include "vcpkg_System.h" -#include <iostream> -#include <Windows.h> -#include <regex> +#include "vcpkg_Checks.h" -namespace fs = std::tr2::sys; - -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::format(LR"###("%s")###", cmd_line); + const std::wstring& actual_cmd_line = Strings::wformat(LR"###("%s")###", cmd_line); int exit_code = _wsystem(actual_cmd_line.c_str()); return exit_code; } exit_code_and_output cmd_execute_and_capture_output(const wchar_t* cmd_line) { - const std::wstring& actual_cmd_line = Strings::format(LR"###("%s")###", 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; char buf[1024]; auto pipe = _wpopen(actual_cmd_line.c_str(), L"r"); if (pipe == nullptr) { - return {1, output}; + return { 1, output }; } while (fgets(buf, 1024, pipe)) { @@ -41,24 +118,35 @@ 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(color c, const char* message) + void print(const color c, const char* message) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); @@ -66,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(color c, const char* message) + 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 Stopwatch::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 Stopwatch::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 Stopwatch::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 ec6946b98..fdeb6e877 100644 --- a/toolsrc/src/vcpkg_cmd_arguments.cpp +++ b/toolsrc/src/vcpkg_cmd_arguments.cpp @@ -1,11 +1,7 @@ -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> +#include "pch.h" #include "vcpkg_cmd_arguments.h" #include "vcpkg_Commands.h" -#include "vcpkg_Graphs.h" -#include <unordered_set> #include "metrics.h" -#include "vcpkg.h" #include "vcpkg_System.h" namespace vcpkg @@ -20,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); } @@ -28,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); } @@ -36,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; @@ -98,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; } @@ -158,7 +154,7 @@ namespace vcpkg System::println(System::color::error, "Unknown option(s) for command '%s':", this->command); for (const std::string& option : options_copy) { - System::println(option.c_str()); + System::println(option); } exit(EXIT_FAILURE); } @@ -166,49 +162,51 @@ namespace vcpkg return output; } - void vcpkg_cmd_arguments::check_max_args(size_t arg_count, const char* example_text) const + void vcpkg_cmd_arguments::check_max_arg_count(const size_t expected_arg_count) const { - if (command_arguments.size() > arg_count) + return check_max_arg_count(expected_arg_count, ""); + } + + void vcpkg_cmd_arguments::check_min_arg_count(const size_t expected_arg_count) const + { + return check_min_arg_count(expected_arg_count, ""); + } + + void vcpkg_cmd_arguments::check_exact_arg_count(const size_t expected_arg_count) const + { + return check_exact_arg_count(expected_arg_count, ""); + } + + void vcpkg_cmd_arguments::check_max_arg_count(const size_t expected_arg_count, const std::string& example_text) const + { + const size_t actual_arg_count = command_arguments.size(); + if (actual_arg_count > expected_arg_count) { - System::println(System::color::error, "Error: too many arguments to command %s", command); - if (example_text != nullptr) - print_example(example_text); - else - print_usage(); + System::println(System::color::error, "Error: `%s` requires at most %u arguments, but %u were provided", this->command, expected_arg_count, actual_arg_count); + System::print(example_text); exit(EXIT_FAILURE); } } - std::vector<package_spec> vcpkg_cmd_arguments::parse_all_arguments_as_package_specs(const triplet& default_target_triplet, const char* example_text) const + void vcpkg_cmd_arguments::check_min_arg_count(const size_t expected_arg_count, const std::string& example_text) const { - size_t arg_count = command_arguments.size(); - if (arg_count < 1) + const size_t actual_arg_count = command_arguments.size(); + if (actual_arg_count < expected_arg_count) { - System::println(System::color::error, "Error: %s requires one or more package specifiers", this->command); - if (example_text == nullptr) - print_example(Strings::format("%s zlib zlib:x64-windows curl boost", this->command).c_str()); - else - print_example(example_text); + System::println(System::color::error, "Error: `%s` requires at least %u arguments, but %u were provided", this->command, expected_arg_count, actual_arg_count); + System::print(example_text); exit(EXIT_FAILURE); } - std::vector<package_spec> specs; - specs.reserve(arg_count); + } - for (const std::string& command_argument : command_arguments) + void vcpkg_cmd_arguments::check_exact_arg_count(const size_t expected_arg_count, const std::string& example_text) const + { + const size_t actual_arg_count = command_arguments.size(); + if (actual_arg_count != expected_arg_count) { - expected<package_spec> current_spec = package_spec::from_string(command_argument, default_target_triplet); - if (auto spec = current_spec.get()) - { - specs.push_back(std::move(*spec)); - } - else - { - System::println(System::color::error, "Error: %s: %s", current_spec.error_code().message(), command_argument); - print_example(Strings::format("%s zlib:x64-windows", this->command).c_str()); - exit(EXIT_FAILURE); - } + System::println(System::color::error, "Error: `%s` requires %u arguments, but %u were provided", this->command, expected_arg_count, actual_arg_count); + System::print(example_text); + exit(EXIT_FAILURE); } - - return specs; } } diff --git a/toolsrc/src/vcpkg_metrics_uploader.cpp b/toolsrc/src/vcpkg_metrics_uploader.cpp index f1f4a52ed..82dcd4b03 100644 --- a/toolsrc/src/vcpkg_metrics_uploader.cpp +++ b/toolsrc/src/vcpkg_metrics_uploader.cpp @@ -1,19 +1,11 @@ #include "metrics.h" -#include <filesystem> #include "vcpkg_Checks.h" #include "vcpkg_Files.h" #include <Windows.h> -namespace fs = std::tr2::sys; 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; @@ -21,5 +13,5 @@ WinMain( szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount); Checks::check_exit(argCount == 2, "Requires exactly one argument, the path to the payload file"); - Upload(Files::get_contents(szArgList[1]).get_or_throw()); + Upload(Files::read_contents(szArgList[1]).get_or_throw()); } diff --git a/toolsrc/src/vcpkg_paths.cpp b/toolsrc/src/vcpkg_paths.cpp index 30d32a99b..fa6fca370 100644 --- a/toolsrc/src/vcpkg_paths.cpp +++ b/toolsrc/src/vcpkg_paths.cpp @@ -1,14 +1,156 @@ -#include <filesystem> +#include "pch.h" #include "expected.h" #include "vcpkg_paths.h" #include "metrics.h" #include "vcpkg_System.h" #include "package_spec.h" - -namespace fs = std::tr2::sys; +#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; @@ -34,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"; @@ -43,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; } @@ -54,6 +198,46 @@ namespace vcpkg fs::path vcpkg_paths::port_dir(const package_spec& spec) const { - return this->ports / spec.name; + return this->ports / spec.name(); + } + + fs::path vcpkg_paths::build_info_file_path(const package_spec& spec) const + { + return this->package_dir(spec) / "BUILD_INFO"; + } + + fs::path vcpkg_paths::listfile_path(const BinaryParagraph& pgh) const + { + return this->vcpkg_dir_info / (pgh.fullstem() + ".list"); + } + + bool vcpkg_paths::is_valid_triplet(const triplet& t) const + { + auto it = fs::directory_iterator(this->triplets); + for (; it != fs::directory_iterator(); ++it) + { + std::string triplet_file_name = it->path().stem().generic_u8string(); + if (t.canonical_name() == triplet_file_name) // TODO: fuzzy compare + { + //t.value = triplet_file_name; // NOTE: uncomment when implementing fuzzy compare + return true; + } + } + 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/vcpkg_version.cpp b/toolsrc/src/vcpkg_version.cpp deleted file mode 100644 index da52b7cab..000000000 --- a/toolsrc/src/vcpkg_version.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "vcpkg.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 - -const std::string& vcpkg::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; -} 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 e947dc647..6b96c25cb 100644 --- a/toolsrc/src/vcpkglib_helpers.cpp +++ b/toolsrc/src/vcpkglib_helpers.cpp @@ -1,50 +1,55 @@ +#include "pch.h" #include "vcpkg_Checks.h" #include "vcpkglib_helpers.h" -#include <unordered_map> -namespace vcpkg {namespace details +namespace vcpkg::details { - void optional_field(const std::unordered_map<std::string, std::string>& fields, std::string& out, const std::string& fieldname) + std::string optional_field(const std::unordered_map<std::string, std::string>& fields, const std::string& fieldname) { auto it = fields.find(fieldname); if (it == fields.end()) { - out.clear(); + return std::string(); } - else + return it->second; + } + + std::string remove_optional_field(std::unordered_map<std::string, std::string>* fields, const std::string& fieldname) + { + auto it = fields->find(fieldname); + if (it == fields->end()) { - out = it->second; + return std::string(); } - }; - void required_field(const std::unordered_map<std::string, std::string>& fields, std::string& out, const std::string& fieldname) + const std::string value = std::move(it->second); + fields->erase(it); + return value; + } + + std::string required_field(const std::unordered_map<std::string, std::string>& fields, const std::string& fieldname) { auto it = fields.find(fieldname); - vcpkg::Checks::check_throw(it != fields.end(), "Required field not present: %s", fieldname); - out = it->second; - }; + Checks::check_exit(it != fields.end(), "Required field not present: %s", fieldname); + return it->second; + } - void parse_depends(const std::string& depends_string, std::vector<std::string>& out) + std::string remove_required_field(std::unordered_map<std::string, std::string>* fields, const std::string& fieldname) { - size_t cur = 0; - do - { - auto pos = depends_string.find(',', cur); - if (pos == std::string::npos) - { - out.push_back(depends_string.substr(cur)); - return; - } - out.push_back(depends_string.substr(cur, pos - cur)); - - // skip comma and space - ++pos; - if (depends_string[pos] == ' ') - ++pos; - - cur = pos; - } - while (cur != std::string::npos); + auto it = fields->find(fieldname); + Checks::check_exit(it != fields->end(), "Required field not present: %s", fieldname); + + const std::string value = std::move(it->second); + fields->erase(it); + return value; + } + + std::string shorten_description(const std::string& desc) + { + auto simple_desc = std::regex_replace(desc.substr(0, 49), std::regex("\\n( |\\t)?"), ""); + if (desc.size() > 49) + simple_desc.append("..."); + return simple_desc; } -}} +} diff --git a/toolsrc/vcpkg.sln b/toolsrc/vcpkg.sln index 83051670a..c97756c21 100644 --- a/toolsrc/vcpkg.sln +++ b/toolsrc/vcpkg.sln @@ -5,12 +5,8 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkg", "vcpkg\vcpkg.vcxproj", "{34671B80-54F9-46F5-8310-AC429C11D4FB}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkgcommon", "vcpkgcommon\vcpkgcommon.vcxproj", "{7129F242-F20C-43E7-BBEC-4E15B71890B2}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkglib", "vcpkglib\vcpkglib.vcxproj", "{B98C92B7-2874-4537-9D46-D14E5C237F04}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkgmetrics", "vcpkgmetrics\vcpkgmetrics.vcxproj", "{7226078C-1D2A-4123-9EF1-8DF2B722B8F1}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkgmetricsuploader", "vcpkgmetricsuploader\vcpkgmetricsuploader.vcxproj", "{7D6FDEEB-B299-4A23-85EE-F67C4DED47BE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcpkgtest", "vcpkgtest\vcpkgtest.vcxproj", "{F27B8DB0-1279-4AF8-A2E3-1D49C4F0220D}" @@ -31,14 +27,6 @@ Global {34671B80-54F9-46F5-8310-AC429C11D4FB}.Release|x64.Build.0 = Release|x64 {34671B80-54F9-46F5-8310-AC429C11D4FB}.Release|x86.ActiveCfg = Release|Win32 {34671B80-54F9-46F5-8310-AC429C11D4FB}.Release|x86.Build.0 = Release|Win32 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Debug|x64.ActiveCfg = Debug|x64 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Debug|x64.Build.0 = Debug|x64 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Debug|x86.ActiveCfg = Debug|Win32 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Debug|x86.Build.0 = Debug|Win32 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Release|x64.ActiveCfg = Release|x64 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Release|x64.Build.0 = Release|x64 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Release|x86.ActiveCfg = Release|Win32 - {7129F242-F20C-43E7-BBEC-4E15B71890B2}.Release|x86.Build.0 = Release|Win32 {B98C92B7-2874-4537-9D46-D14E5C237F04}.Debug|x64.ActiveCfg = Debug|x64 {B98C92B7-2874-4537-9D46-D14E5C237F04}.Debug|x64.Build.0 = Debug|x64 {B98C92B7-2874-4537-9D46-D14E5C237F04}.Debug|x86.ActiveCfg = Debug|Win32 @@ -47,14 +35,6 @@ Global {B98C92B7-2874-4537-9D46-D14E5C237F04}.Release|x64.Build.0 = Release|x64 {B98C92B7-2874-4537-9D46-D14E5C237F04}.Release|x86.ActiveCfg = Release|Win32 {B98C92B7-2874-4537-9D46-D14E5C237F04}.Release|x86.Build.0 = Release|Win32 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Debug|x64.ActiveCfg = Debug|x64 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Debug|x64.Build.0 = Debug|x64 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Debug|x86.ActiveCfg = Debug|Win32 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Debug|x86.Build.0 = Debug|Win32 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Release|x64.ActiveCfg = Release|x64 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Release|x64.Build.0 = Release|x64 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Release|x86.ActiveCfg = Release|Win32 - {7226078C-1D2A-4123-9EF1-8DF2B722B8F1}.Release|x86.Build.0 = Release|Win32 {7D6FDEEB-B299-4A23-85EE-F67C4DED47BE}.Debug|x64.ActiveCfg = Debug|x64 {7D6FDEEB-B299-4A23-85EE-F67C4DED47BE}.Debug|x64.Build.0 = Debug|x64 {7D6FDEEB-B299-4A23-85EE-F67C4DED47BE}.Debug|x86.ActiveCfg = Debug|Win32 diff --git a/toolsrc/vcpkg/vcpkg.vcxproj b/toolsrc/vcpkg/vcpkg.vcxproj index a59683470..fd8e5d33e 100644 --- a/toolsrc/vcpkg/vcpkg.vcxproj +++ b/toolsrc/vcpkg/vcpkg.vcxproj @@ -22,31 +22,28 @@ <ProjectGuid>{34671B80-54F9-46F5-8310-AC429C11D4FB}</ProjectGuid> <RootNamespace>vcpkg</RootNamespace> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + <PlatformToolset>v140</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> @@ -76,6 +73,8 @@ <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <AdditionalDependencies>winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -88,6 +87,8 @@ <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <AdditionalDependencies>winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -103,6 +104,7 @@ <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -120,6 +122,7 @@ <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -128,42 +131,12 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="..\src\commands_cache.cpp" /> - <ClCompile Include="..\src\commands_create.cpp" /> - <ClCompile Include="..\src\commands_edit.cpp" /> - <ClCompile Include="..\src\commands_import.cpp" /> - <ClCompile Include="..\src\commands_list.cpp" /> - <ClCompile Include="..\src\commands_owns.cpp" /> - <ClCompile Include="..\src\commands_remove.cpp" /> - <ClCompile Include="..\src\commands_search.cpp" /> - <ClCompile Include="..\src\commands_update.cpp" /> - <ClCompile Include="..\src\vcpkg_cmd_arguments.cpp" /> - <ClCompile Include="..\src\commands_other.cpp" /> - <ClCompile Include="..\src\vcpkg_Dependencies.cpp" /> - <ClCompile Include="..\src\vcpkg_Environment.cpp" /> - <ClCompile Include="..\src\commands_installation.cpp" /> - <ClCompile Include="..\src\commands_integration.cpp" /> - <ClCompile Include="..\src\main.cpp" /> - <ClCompile Include="..\src\commands_help.cpp" /> - <ClCompile Include="..\src\post_build_lint.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\include\vcpkg_cmd_arguments.h" /> - <ClInclude Include="..\include\vcpkg_Commands.h" /> - <ClInclude Include="..\include\vcpkg_Dependencies.h" /> - <ClInclude Include="..\include\vcpkg_Environment.h" /> - <ClInclude Include="..\include\post_build_lint.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\vcpkgcommon\vcpkgcommon.vcxproj"> - <Project>{7129f242-f20c-43e7-bbec-4e15b71890b2}</Project> - </ProjectReference> <ProjectReference Include="..\vcpkglib\vcpkglib.vcxproj"> <Project>{b98c92b7-2874-4537-9d46-d14e5c237f04}</Project> </ProjectReference> - <ProjectReference Include="..\vcpkgmetrics\vcpkgmetrics.vcxproj"> - <Project>{7226078c-1d2a-4123-9ef1-8df2b722b8f1}</Project> - </ProjectReference> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\src\vcpkg.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/toolsrc/vcpkg/vcpkg.vcxproj.filters b/toolsrc/vcpkg/vcpkg.vcxproj.filters index 2e8a343fc..ca9723bbf 100644 --- a/toolsrc/vcpkg/vcpkg.vcxproj.filters +++ b/toolsrc/vcpkg/vcpkg.vcxproj.filters @@ -15,76 +15,8 @@ </Filter> </ItemGroup> <ItemGroup> - <ClCompile Include="..\src\main.cpp"> + <ClCompile Include="..\src\vcpkg.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\src\commands_other.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_help.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_integration.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_installation.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\post_build_lint.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_cmd_arguments.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_Environment.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_remove.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_search.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_cache.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_update.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_list.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_edit.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_create.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_owns.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\commands_import.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_Dependencies.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\include\post_build_lint.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_cmd_arguments.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Commands.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Environment.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Dependencies.h"> - <Filter>Header Files</Filter> - </ClInclude> </ItemGroup> </Project>
\ No newline at end of file diff --git a/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj b/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj deleted file mode 100644 index d5e68fde3..000000000 --- a/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj +++ /dev/null @@ -1,142 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{7129F242-F20C-43E7-BBEC-4E15B71890B2}</ProjectGuid> - <RootNamespace>vcpkgcommon</RootNamespace> - <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="Shared"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup /> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\src\vcpkg_Checks.cpp" /> - <ClCompile Include="..\src\vcpkg_Files.cpp" /> - <ClCompile Include="..\src\vcpkg_Strings.cpp" /> - <ClCompile Include="..\src\vcpkg_System.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\include\expected.h" /> - <ClInclude Include="..\include\opt_bool.h" /> - <ClInclude Include="..\include\vcpkg_Checks.h" /> - <ClInclude Include="..\include\vcpkg_Files.h" /> - <ClInclude Include="..\include\vcpkg_Graphs.h" /> - <ClInclude Include="..\include\vcpkg_Maps.h" /> - <ClInclude Include="..\include\vcpkg_Sets.h" /> - <ClInclude Include="..\include\vcpkg_Strings.h" /> - <ClInclude Include="..\include\vcpkg_System.h" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project>
\ No newline at end of file diff --git a/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj.filters b/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj.filters deleted file mode 100644 index ae747d687..000000000 --- a/toolsrc/vcpkgcommon/vcpkgcommon.vcxproj.filters +++ /dev/null @@ -1,60 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\src\vcpkg_Checks.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_Strings.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_System.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_Files.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\include\vcpkg_Checks.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Strings.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_System.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\expected.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Files.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Graphs.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\opt_bool.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Maps.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\include\vcpkg_Sets.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> -</Project>
\ No newline at end of file diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj b/toolsrc/vcpkglib/vcpkglib.vcxproj index 99e16e431..dd5dd124a 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj @@ -22,34 +22,34 @@ <ProjectGuid>{B98C92B7-2874-4537-9D46-D14E5C237F04}</ProjectGuid> <RootNamespace>vcpkglib</RootNamespace> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + <PlatformToolset>v140</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> + <PropertyGroup> + <DISABLE_METRICS Condition="'$(DISABLE_METRICS)' == ''">0</DISABLE_METRICS> + </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> @@ -75,18 +75,26 @@ <Optimization>Disabled</Optimization> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> - <WarningLevel>Level3</WarningLevel> + <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> @@ -97,8 +105,11 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -113,8 +124,11 @@ <IntrinsicFunctions>true</IntrinsicFunctions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);VCPKG_VERSION=$(VCPKG_VERSION);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -123,29 +137,105 @@ </ItemDefinitionGroup> <ItemGroup> <ClInclude Include="..\include\BinaryParagraph.h" /> + <ClInclude Include="..\include\lazy.h" /> + <ClInclude Include="..\include\PostBuildLint_BuildInfo.h" /> + <ClInclude Include="..\include\PostBuildLint_BuildPolicies.h" /> + <ClInclude Include="..\include\coff_file_reader.h" /> + <ClInclude Include="..\include\expected.h" /> + <ClInclude Include="..\include\filesystem_fs.h" /> + <ClInclude Include="..\include\ImmutableSortedVector.h" /> + <ClInclude Include="..\include\MachineType.h" /> + <ClInclude Include="..\include\metrics.h" /> + <ClInclude Include="..\include\opt_bool.h" /> <ClInclude Include="..\include\package_spec.h" /> <ClInclude Include="..\include\package_spec_parse_result.h" /> + <ClInclude Include="..\include\Paragraphs.h" /> + <ClInclude Include="..\include\pch.h" /> + <ClInclude Include="..\include\PostBuildLint.h" /> + <ClInclude Include="..\include\PostBuildLint_BuildType.h" /> + <ClInclude Include="..\include\PostBuildLint_ConfigurationType.h" /> + <ClInclude Include="..\include\PostBuildLint_LinkageType.h" /> <ClInclude Include="..\include\SourceParagraph.h" /> <ClInclude Include="..\include\StatusParagraph.h" /> <ClInclude Include="..\include\StatusParagraphs.h" /> + <ClInclude Include="..\include\vcpkg_Chrono.h" /> <ClInclude Include="..\include\triplet.h" /> - <ClInclude Include="..\include\vcpkg.h" /> + <ClInclude Include="..\include\vcpkglib.h" /> <ClInclude Include="..\include\vcpkglib_helpers.h" /> + <ClInclude Include="..\include\vcpkg_Checks.h" /> + <ClInclude Include="..\include\vcpkg_cmd_arguments.h" /> + <ClInclude Include="..\include\vcpkg_Commands.h" /> + <ClInclude Include="..\include\vcpkg_Dependencies.h" /> + <ClInclude Include="..\include\vcpkg_Enums.h" /> + <ClInclude Include="..\include\vcpkg_Environment.h" /> + <ClInclude Include="..\include\vcpkg_Files.h" /> + <ClInclude Include="..\include\vcpkg_Graphs.h" /> + <ClInclude Include="..\include\vcpkg_Input.h" /> + <ClInclude Include="..\include\vcpkg_Maps.h" /> + <ClInclude Include="..\include\vcpkg_optional.h" /> <ClInclude Include="..\include\vcpkg_paths.h" /> + <ClInclude Include="..\include\vcpkg_Sets.h" /> + <ClInclude Include="..\include\vcpkg_Strings.h" /> + <ClInclude Include="..\include\vcpkg_System.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="..\src\BinaryParagraph.cpp" /> - <ClCompile Include="..\src\lib.cpp" /> + <ClCompile Include="..\src\commands_ci.cpp" /> + <ClCompile Include="..\src\PostBuildLint_BuildInfo.cpp" /> + <ClCompile Include="..\src\PostBuildLint_BuildPolicies.cpp" /> + <ClCompile Include="..\src\coff_file_reader.cpp" /> + <ClCompile Include="..\src\commands_available_commands.cpp" /> + <ClCompile Include="..\src\commands_build.cpp" /> + <ClCompile Include="..\src\commands_build_external.cpp" /> + <ClCompile Include="..\src\commands_cache.cpp" /> + <ClCompile Include="..\src\commands_contact.cpp" /> + <ClCompile Include="..\src\commands_create.cpp" /> + <ClCompile Include="..\src\commands_edit.cpp" /> + <ClCompile Include="..\src\commands_hash.cpp" /> + <ClCompile Include="..\src\commands_help.cpp" /> + <ClCompile Include="..\src\commands_import.cpp" /> + <ClCompile Include="..\src\commands_install.cpp" /> + <ClCompile Include="..\src\commands_integrate.cpp" /> + <ClCompile Include="..\src\commands_list.cpp" /> + <ClCompile Include="..\src\commands_owns.cpp" /> + <ClCompile Include="..\src\commands_portsdiff.cpp" /> + <ClCompile Include="..\src\commands_remove.cpp" /> + <ClCompile Include="..\src\commands_search.cpp" /> + <ClCompile Include="..\src\commands_update.cpp" /> + <ClCompile Include="..\src\commands_version.cpp" /> + <ClCompile Include="..\src\MachineType.cpp" /> + <ClCompile Include="..\src\metrics.cpp" /> + <ClCompile Include="..\src\opt_bool.cpp" /> + <ClCompile Include="..\src\pch.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint.cpp" /> + <ClCompile Include="..\src\PostBuildLint_ConfigurationType.cpp" /> + <ClCompile Include="..\src\PostBuildLint_LinkageType.cpp" /> + <ClCompile Include="..\src\PostBuildLint_BuildType.cpp" /> + <ClCompile Include="..\src\vcpkg_Chrono.cpp" /> + <ClCompile Include="..\src\vcpkglib.cpp" /> <ClCompile Include="..\src\package_spec.cpp" /> <ClCompile Include="..\src\package_spec_parse_result.cpp" /> + <ClCompile Include="..\src\Paragraphs.cpp" /> <ClCompile Include="..\src\SourceParagraph.cpp" /> <ClCompile Include="..\src\StatusParagraph.cpp" /> <ClCompile Include="..\src\StatusParagraphs.cpp" /> <ClCompile Include="..\src\triplet.cpp" /> - <ClCompile Include="..\src\vcpkg.cpp" /> <ClCompile Include="..\src\vcpkglib_helpers.cpp" /> + <ClCompile Include="..\src\vcpkg_Checks.cpp" /> + <ClCompile Include="..\src\vcpkg_cmd_arguments.cpp" /> + <ClCompile Include="..\src\vcpkg_Dependencies.cpp" /> + <ClCompile Include="..\src\vcpkg_Enums.cpp" /> + <ClCompile Include="..\src\vcpkg_Environment.cpp" /> + <ClCompile Include="..\src\vcpkg_Files.cpp" /> + <ClCompile Include="..\src\vcpkg_Input.cpp" /> <ClCompile Include="..\src\vcpkg_paths.cpp" /> - <ClCompile Include="..\src\vcpkg_version.cpp" /> + <ClCompile Include="..\src\vcpkg_Strings.cpp" /> + <ClCompile Include="..\src\vcpkg_System.cpp" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters index eec73a445..d701321be 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters @@ -15,15 +15,6 @@ </Filter> </ItemGroup> <ItemGroup> - <ClCompile Include="..\src\vcpkg.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\lib.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\src\vcpkg_version.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\src\package_spec.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -51,11 +42,137 @@ <ClCompile Include="..\src\vcpkg_paths.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\src\Paragraphs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\metrics.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Input.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Environment.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\coff_file_reader.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_available_commands.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_build.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_build_external.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_cache.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_contact.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_create.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_edit.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_hash.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_help.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_import.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_install.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_integrate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_list.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_owns.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_portsdiff.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_remove.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_search.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_update.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_version.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\MachineType.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_cmd_arguments.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Dependencies.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkglib.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_System.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Checks.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Files.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Strings.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\pch.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\opt_bool.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint_BuildInfo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint_BuildPolicies.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint_LinkageType.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint_ConfigurationType.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\PostBuildLint_BuildType.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Enums.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\commands_ci.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\vcpkg_Chrono.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> - <ClInclude Include="..\include\vcpkg.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\include\package_spec.h"> <Filter>Header Files</Filter> </ClInclude> @@ -83,5 +200,101 @@ <ClInclude Include="..\include\vcpkg_paths.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\include\Paragraphs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\metrics.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Input.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\coff_file_reader.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\filesystem_fs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\MachineType.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_cmd_arguments.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Commands.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Dependencies.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Environment.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkglib.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\expected.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\ImmutableSortedVector.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\opt_bool.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Checks.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Files.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Graphs.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Maps.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Sets.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Strings.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_System.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_optional.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint_BuildInfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint_BuildPolicies.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint_LinkageType.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint_ConfigurationType.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\PostBuildLint_BuildType.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Enums.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\vcpkg_Chrono.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\include\lazy.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project>
\ No newline at end of file diff --git a/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj b/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj deleted file mode 100644 index 7b7fe89ed..000000000 --- a/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj +++ /dev/null @@ -1,140 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{7226078C-1D2A-4123-9EF1-8DF2B722B8F1}</ProjectGuid> - <RootNamespace>vcpkgmetrics</RootNamespace> - <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>StaticLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> - </PropertyGroup> - <PropertyGroup> - <DISABLE_METRICS Condition="'$(DISABLE_METRICS)' == ''">0</DISABLE_METRICS> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="Shared"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup /> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - </ClCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - </ClCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> - <PreprocessorDefinitions>DISABLE_METRICS=$(DISABLE_METRICS);_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - <Link> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup> - <ClCompile> - <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">DISABLE_METRICS=$(DISABLE_METRICS);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">DISABLE_METRICS=$(DISABLE_METRICS);_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/std:c++latest %(AdditionalOptions)</AdditionalOptions> - <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/std:c++latest %(AdditionalOptions)</AdditionalOptions> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClInclude Include="..\include\metrics.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\src\metrics.cpp" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project>
\ No newline at end of file diff --git a/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj.filters b/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj.filters deleted file mode 100644 index 7116a4247..000000000 --- a/toolsrc/vcpkgmetrics/vcpkgmetrics.vcxproj.filters +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\include\metrics.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\src\metrics.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> -</Project>
\ No newline at end of file diff --git a/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj b/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj index 1e2a85087..472d74e30 100644 --- a/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj +++ b/toolsrc/vcpkgmetricsuploader/vcpkgmetricsuploader.vcxproj @@ -22,31 +22,28 @@ <ProjectGuid>{7D6FDEEB-B299-4A23-85EE-F67C4DED47BE}</ProjectGuid> <RootNamespace>vcpkgmetricsuploader</RootNamespace> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + <PlatformToolset>v140</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> @@ -76,6 +73,8 @@ <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <AdditionalDependencies>winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -83,11 +82,13 @@ </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> - <WarningLevel>Level3</WarningLevel> + <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <AdditionalDependencies>winhttp.lib;version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -103,6 +104,7 @@ <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -120,6 +122,7 @@ <AdditionalIncludeDirectories>..\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -131,11 +134,8 @@ <ClCompile Include="..\src\vcpkg_metrics_uploader.cpp" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\vcpkgcommon\vcpkgcommon.vcxproj"> - <Project>{7129f242-f20c-43e7-bbec-4e15b71890b2}</Project> - </ProjectReference> - <ProjectReference Include="..\vcpkgmetrics\vcpkgmetrics.vcxproj"> - <Project>{7226078c-1d2a-4123-9ef1-8df2b722b8f1}</Project> + <ProjectReference Include="..\vcpkglib\vcpkglib.vcxproj"> + <Project>{b98c92b7-2874-4537-9d46-d14e5c237f04}</Project> </ProjectReference> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj b/toolsrc/vcpkgtest/vcpkgtest.vcxproj index 3d9503374..c12c2dd31 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj @@ -19,37 +19,31 @@ </ProjectConfiguration> </ItemGroup> <ItemGroup> - <ClCompile Include="..\src\test.cpp" /> + <ClCompile Include="..\src\tests_dependencies.cpp" /> + <ClCompile Include="..\src\tests_paragraph.cpp" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\vcpkgcommon\vcpkgcommon.vcxproj"> - <Project>{7129f242-f20c-43e7-bbec-4e15b71890b2}</Project> - </ProjectReference> <ProjectReference Include="..\vcpkglib\vcpkglib.vcxproj"> <Project>{b98c92b7-2874-4537-9d46-d14e5c237f04}</Project> </ProjectReference> - <ProjectReference Include="..\vcpkgmetrics\vcpkgmetrics.vcxproj"> - <Project>{7226078c-1d2a-4123-9ef1-8df2b722b8f1}</Project> - </ProjectReference> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{F27B8DB0-1279-4AF8-A2E3-1D49C4F0220D}</ProjectGuid> <Keyword>Win32Proj</Keyword> <RootNamespace>vcpkgtest</RootNamespace> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + <PlatformToolset>v140</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>Unicode</CharacterSet> <UseOfMfc>false</UseOfMfc> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> <UseOfMfc>false</UseOfMfc> @@ -57,14 +51,12 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <CharacterSet>Unicode</CharacterSet> <UseOfMfc>false</UseOfMfc> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v140</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> <UseOfMfc>false</UseOfMfc> @@ -105,6 +97,8 @@ <UseFullPaths>true</UseFullPaths> <PrecompiledHeaderFile /> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <SubSystem>Windows</SubSystem> @@ -114,13 +108,15 @@ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <PrecompiledHeader>NotUsing</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> + <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>..\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\include;$(VCInstallDir)UnitTest\include;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <UseFullPaths>true</UseFullPaths> <PrecompiledHeaderFile /> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <SubSystem>Windows</SubSystem> @@ -139,6 +135,7 @@ <UseFullPaths>true</UseFullPaths> <PrecompiledHeaderFile /> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <SubSystem>Windows</SubSystem> @@ -159,6 +156,7 @@ <UseFullPaths>true</UseFullPaths> <PrecompiledHeaderFile /> <AdditionalOptions>/std:c++latest %(AdditionalOptions)</AdditionalOptions> + <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> <SubSystem>Windows</SubSystem> diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters index 9db7e6ef8..bbbc6bd40 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters @@ -15,7 +15,10 @@ </Filter> </ItemGroup> <ItemGroup> - <ClCompile Include="..\src\test.cpp"> + <ClCompile Include="..\src\tests_paragraph.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\src\tests_dependencies.cpp"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> |
