diff options
| author | nicole mazzuca <mazzucan@outlook.com> | 2020-06-30 10:40:18 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-30 10:40:18 -0700 |
| commit | 1d8f0acc9c3085d18152a3f639077a28109196b6 (patch) | |
| tree | 1daa4780e0d5f51844217dc61dbf275433153abf /toolsrc/include | |
| parent | 67ab6130b64cce6701c5a95ca3b9bdc4d949cb8a (diff) | |
| download | vcpkg-1d8f0acc9c3085d18152a3f639077a28109196b6.tar.gz vcpkg-1d8f0acc9c3085d18152a3f639077a28109196b6.zip | |
[vcpkg manifest] Manifest Implementation (#11757)
==== Changes Related to manifests ====
* Add the `manifests` feature flag
* This only says whether we look for a `vcpkg.json` in the cwd, not
whether we support parsing manifests (for ports, for example)
* Changes to the manifests RFC
* `"authors"` -> `"maintainers"`
* `--x-classic-mode` -> `-manifests` \in `vcpkg_feature_flags`
* reserve `"core"` in addition to `"default"`, since that's already
reserved for features
* Add a small helper note about what identifiers must look like
* `<license-string>`: SPDX v3.8 -> v3.9
* `"feature"."description"` is allowed to be an array of strings as well
* `"version"` -> `"version-string"` for forward-compat with versions
RFC
* Add the `--feature-flags` option
* Add the ability to turn off feature flags via passing
`-<feature-flag>` to `VCPKG_FEATURE_FLAGS` or `--feature-flags`
* Add CMake toolchain support for manifests
* Requires either:
* a feature flag of `manifests` in either `Env{VCPKG_FEATURE_FLAGS}`
or `VCPKG_FEATURE_FLAGS`
* Passing the `VCPKG_ENABLE_MANIFESTS` option
* The toolchain will install your packages to
`${VCPKG_MANIFEST_DIR}/vcpkg_installed`.
* Add MSBuild `vcpkg integrate install` support for manifests
* Requires `VcpkgEnableManifest` to be true
* `vcpkg create` creates a port that has a `vcpkg.json` instead of a
`CONTROL`
* argparse, abseil, 3fd, and avisynthplus ports switched to manifest
from CONTROL
* Add support for `--x-manifest-root`, as well as code for finding it if
not passed
* Add support for parsing manifests!
* Add a filesystem lock!
==== Important Changes which are somewhat unrelated to manifests ====
* Rename `logicexpression.{h,cpp}` to `platform-expression.{h,cpp}`
* Add `PlatformExpression` type which takes the place of the old logic
expression
* Split the parsing of platform expressions from checking whether
they're true or not
* Eagerly parse PlatformExpressions as opposed to leaving them as
strings
* Add checking for feature flag consistency
* i.e., if `-binarycaching` is passed, you shouldn't be passing
`--binarysource`
* Add the `Json::Reader` type which, with the help of user-defined
visitors, converts JSON to your internal type
* VcpkgArgParser: place the switch names into a constant as opposed to
using magic constants
* In general update the parsing code so that this ^ works
* Add `Port-Version` fields to CONTROL files
* This replaces the existing practice of
`Version: <my-version>-<port-version>`
==== Smaller changes ====
* small drive-by cleanups to some CMake
* `${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}` ->
`${CURRENT_INSTALLED_DIR}`
* Remove `-analyze` when compiling with clang-cl, since that's not a
supported flag (vcpkg's build system)
* Add a message about which compiler is detected by vcpkg's build
system machinery
* Fix `Expected::then`
* Convert `""` to `{}` for `std::string` and `fs::path`, to avoid a
`strlen` (additionally, `.empty()` instead of `== ""`, and `.clear()`)
* Add `Strings::strto` which converts strings to numeric types
* Support built-in arrays and `StringView` for `Strings::join`
* Add `operator<` and friends to `StringView`
* Add `substr` to `StringView`
* SourceParagraphParser gets some new errors
Diffstat (limited to 'toolsrc/include')
| -rw-r--r-- | toolsrc/include/vcpkg/base/expected.h | 20 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/base/files.h | 25 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/base/json.h | 144 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/base/strings.h | 98 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/base/stringview.h | 26 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/binaryparagraph.h | 10 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/commands.h | 25 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/dependencies.h | 2 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/logicexpression.h | 24 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/metrics.h | 1 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/packagespec.h | 14 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/paragraphparser.h | 22 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/paragraphs.h | 7 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/platform-expression.h | 73 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/portfileprovider.h | 2 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/sourceparagraph.h | 27 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/statusparagraphs.h | 4 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/vcpkgcmdarguments.h | 41 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg/vcpkgpaths.h | 9 |
19 files changed, 488 insertions, 86 deletions
diff --git a/toolsrc/include/vcpkg/base/expected.h b/toolsrc/include/vcpkg/base/expected.h index ff60149ac..40f5af40f 100644 --- a/toolsrc/include/vcpkg/base/expected.h +++ b/toolsrc/include/vcpkg/base/expected.h @@ -31,7 +31,7 @@ namespace vcpkg template<> struct ErrorHolder<std::string> { - ErrorHolder() : m_is_error(false) {} + ErrorHolder() : m_is_error(false) { } template<class U> ErrorHolder(U&& err) : m_is_error(true), m_err(std::forward<U>(err)) { @@ -53,7 +53,7 @@ namespace vcpkg struct ErrorHolder<std::error_code> { ErrorHolder() = default; - ErrorHolder(const std::error_code& err) : m_err(err) {} + ErrorHolder(const std::error_code& err) : m_err(err) { } bool has_error() const { return bool(m_err); } @@ -79,8 +79,8 @@ namespace vcpkg struct ExpectedHolder { ExpectedHolder() = default; - ExpectedHolder(const T& t) : t(t) {} - ExpectedHolder(T&& t) : t(std::move(t)) {} + ExpectedHolder(const T& t) : t(t) { } + ExpectedHolder(T&& t) : t(std::move(t)) { } using pointer = T*; using const_pointer = const T*; T* get() { return &t; } @@ -90,8 +90,8 @@ namespace vcpkg template<class T> struct ExpectedHolder<T&> { - ExpectedHolder(T& t) : t(&t) {} - ExpectedHolder() : t(nullptr) {} + ExpectedHolder(T& t) : t(&t) { } + ExpectedHolder() : t(nullptr) { } using pointer = T*; using const_pointer = T*; T* get() { return t; } @@ -107,10 +107,10 @@ namespace vcpkg // Constructors are intentionally implicit - ExpectedT(const S& s, ExpectedRightTag = {}) : m_s(s) {} - ExpectedT(S&& s, ExpectedRightTag = {}) : m_s(std::move(s)) {} + ExpectedT(const S& s, ExpectedRightTag = {}) : m_s(s) { } + ExpectedT(S&& s, ExpectedRightTag = {}) : m_s(std::move(s)) { } - ExpectedT(const T& t, ExpectedLeftTag = {}) : m_t(t) {} + ExpectedT(const T& t, ExpectedLeftTag = {}) : m_t(t) { } template<class = std::enable_if<!std::is_reference_v<T>>> ExpectedT(T&& t, ExpectedLeftTag = {}) : m_t(std::move(t)) { @@ -213,7 +213,7 @@ namespace vcpkg } else { - return U{std::move(error()), expected_right_tag}; + return U{std::move(*this).error(), expected_right_tag}; } } diff --git a/toolsrc/include/vcpkg/base/files.h b/toolsrc/include/vcpkg/base/files.h index cb0419221..49a473091 100644 --- a/toolsrc/include/vcpkg/base/files.h +++ b/toolsrc/include/vcpkg/base/files.h @@ -59,6 +59,17 @@ namespace fs perms m_permissions; }; + struct SystemHandle + { + using type = intptr_t; // HANDLE + type system_handle = -1; + + bool is_valid() const + { + return system_handle != -1; + } + }; + #else using stdfs::file_type; @@ -71,6 +82,17 @@ namespace fs using stdfs::file_status::type; }; + struct SystemHandle + { + using type = int; // file descriptor + type system_handle = -1; + + bool is_valid() const + { + return system_handle != -1; + } + }; + #endif inline bool is_symlink(file_status s) noexcept @@ -171,6 +193,9 @@ namespace vcpkg::Files virtual void current_path(const fs::path& path, std::error_code&) = 0; void current_path(const fs::path& path, LineInfo li); + virtual fs::SystemHandle try_take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0; + virtual void unlock_file_lock(fs::SystemHandle handle, std::error_code&) = 0; + virtual std::vector<fs::path> find_from_PATH(const std::string& name) const = 0; }; diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index 69502fedc..ecb96cde1 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -109,11 +109,13 @@ namespace vcpkg::Json double number() const noexcept; StringView string() const noexcept; - const Array& array() const noexcept; - Array& array() noexcept; + const Array& array() const& noexcept; + Array& array() & noexcept; + Array&& array() && noexcept; - const Object& object() const noexcept; - Object& object() noexcept; + const Object& object() const& noexcept; + Object& object() & noexcept; + Object&& object() && noexcept; static Value null(std::nullptr_t) noexcept; static Value boolean(bool) noexcept; @@ -268,11 +270,141 @@ namespace vcpkg::Json underlying_t underlying_; }; - // currently, a hard assertion on file errors + struct ReaderError + { + virtual void add_missing_field(std::string&& type, std::string&& key) = 0; + virtual void add_expected_type(std::string&& key, std::string&& expected_type) = 0; + virtual void add_extra_fields(std::string&& type, std::vector<std::string>&& fields) = 0; + virtual void add_mutually_exclusive_fields(std::string&& type, std::vector<std::string>&& fields) = 0; + + virtual ~ReaderError() = default; + }; + + struct Reader + { + explicit Reader(ReaderError* err) : err(err) { } + + ReaderError& error() const { return *err; } + + private: + ReaderError* err; + + template<class Visitor> + using VisitorType = typename std::remove_reference_t<Visitor>::type; + + template<class Visitor> + Optional<VisitorType<Visitor>> internal_visit(const Value& value, StringView key, Visitor& visitor) + { + switch (value.kind()) + { + using VK = Json::ValueKind; + case VK::Null: return visitor.visit_null(*this, key); + case VK::Boolean: return visitor.visit_boolean(*this, key, value.boolean()); + case VK::Integer: return visitor.visit_integer(*this, key, value.integer()); + case VK::Number: return visitor.visit_number(*this, key, value.number()); + case VK::String: return visitor.visit_string(*this, key, value.string()); + case VK::Array: return visitor.visit_array(*this, key, value.array()); + case VK::Object: return visitor.visit_object(*this, key, value.object()); + } + + vcpkg::Checks::exit_fail(VCPKG_LINE_INFO); + } + + // returns whether the field was found, not whether it was valid + template<class Visitor> + bool internal_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor& visitor) + { + auto value = obj.get(key); + if (!value) + { + return false; + } + + Optional<VisitorType<Visitor>> opt = internal_visit(*value, key, visitor); + + if (auto val = opt.get()) + { + place = std::move(*val); + } + else + { + err->add_expected_type(key.to_string(), visitor.type_name().to_string()); + } + + return true; + } + + public: + template<class Visitor> + void required_object_field( + StringView type, const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor) + { + if (!internal_field(obj, key, place, visitor)) + { + err->add_missing_field(type.to_string(), key.to_string()); + } + } + + template<class Visitor> + void optional_object_field(const Object& obj, StringView key, VisitorType<Visitor>& place, Visitor&& visitor) + { + internal_field(obj, key, place, visitor); + } + + template<class Visitor> + Optional<std::vector<VisitorType<Visitor>>> array_elements(const Array& arr, StringView key, Visitor&& visitor) + { + std::vector<VisitorType<Visitor>> result; + for (const auto& el : arr) + { + auto opt = internal_visit(el, key, visitor); + if (auto p = opt.get()) + { + result.push_back(std::move(*p)); + } + else + { + return nullopt; + } + } + return std::move(result); + } + }; + + // Warning: NEVER use this type except as a CRTP base + template<class Underlying> + struct VisitorCrtpBase + { + // the following function must be defined by the Underlying class + // const char* type_name(); + + // We do this auto dance since function bodies are checked _after_ typedefs in the superclass, + // but function declarations are checked beforehand. Therefore, we can get C++ to use this typedef + // only once the function bodies are checked by returning `auto` and specifying the + // return type in the function body. + auto visit_null(Reader&, StringView) { return Optional<typename Underlying::type>(nullopt); } + auto visit_boolean(Reader&, StringView, bool) { return Optional<typename Underlying::type>(nullopt); } + auto visit_integer(Reader& r, StringView field_name, int64_t i) + { + return static_cast<Underlying&>(*this).visit_number(r, field_name, static_cast<double>(i)); + } + auto visit_number(Reader&, StringView, double) { return Optional<typename Underlying::type>(nullopt); } + auto visit_string(Reader&, StringView, StringView) { return Optional<typename Underlying::type>(nullopt); } + auto visit_array(Reader&, StringView, const Json::Array&) + { + return Optional<typename Underlying::type>(nullopt); + } + auto visit_object(Reader&, StringView, const Json::Object&) + { + return Optional<typename Underlying::type>(nullopt); + } + // we can't make the SMFs protected because of an issue with /permissive mode + }; + ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse_file( const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept; ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse( - StringView text, const fs::path& filepath = "") noexcept; + StringView text, const fs::path& filepath = {}) noexcept; std::string stringify(const Value&, JsonStyle style); std::string stringify(const Object&, JsonStyle style); diff --git a/toolsrc/include/vcpkg/base/strings.h b/toolsrc/include/vcpkg/base/strings.h index 17bef7675..e88d1074f 100644 --- a/toolsrc/include/vcpkg/base/strings.h +++ b/toolsrc/include/vcpkg/base/strings.h @@ -8,6 +8,10 @@ #include <vcpkg/base/stringview.h> #include <vcpkg/base/view.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> + #include <vector> namespace vcpkg::Strings::details @@ -48,6 +52,7 @@ namespace vcpkg::Strings::details } inline void append_internal(std::string& into, const char* v) { into.append(v); } inline void append_internal(std::string& into, const std::string& s) { into.append(s); } + inline void append_internal(std::string& into, StringView s) { into.append(s.begin(), s.end()); } template<class T, class = decltype(std::declval<const T&>().to_string(std::declval<std::string&>()))> void append_internal(std::string& into, const T& t) @@ -60,6 +65,11 @@ namespace vcpkg::Strings::details { to_string(into, t); } + + struct tolower_char + { + char operator()(char c) const { return (c < 'A' || c > 'Z') ? c : c - 'A' + 'a'; } + }; } namespace vcpkg::Strings @@ -117,6 +127,11 @@ namespace vcpkg::Strings bool case_insensitive_ascii_equals(StringView left, StringView right); + template<class It> + void ascii_to_lowercase(It first, It last) + { + std::transform(first, last, first, details::tolower_char{}); + } std::string ascii_to_lowercase(std::string&& s); std::string ascii_to_uppercase(std::string&& s); @@ -134,11 +149,11 @@ namespace vcpkg::Strings } std::string output; - output.append(transformer(*begin)); + append(output, transformer(*begin)); for (auto it = std::next(begin); it != end; ++it) { output.append(delimiter); - output.append(transformer(*it)); + append(output, transformer(*it)); } return output; @@ -147,8 +162,8 @@ namespace vcpkg::Strings template<class Container, class Transformer> std::string join(const char* delimiter, const Container& v, Transformer transformer) { - const auto begin = v.begin(); - const auto end = v.end(); + const auto begin = std::begin(v); + const auto end = std::end(v); return join(delimiter, begin, end, transformer); } @@ -163,7 +178,7 @@ namespace vcpkg::Strings template<class Container> std::string join(const char* delimiter, const Container& v) { - using Element = decltype(*v.begin()); + using Element = decltype(*std::begin(v)); return join(delimiter, v, [](const Element& x) -> const Element& { return x; }); } @@ -173,7 +188,7 @@ namespace vcpkg::Strings void trim_all_and_remove_whitespace_strings(std::vector<std::string>* strings); - std::vector<std::string> split(const std::string& s, const char delimiter); + std::vector<std::string> split(StringView s, const char delimiter); const char* find_first_of(StringView searched, StringView candidates); @@ -193,6 +208,77 @@ namespace vcpkg::Strings return ret; } + // Equivalent to one of the `::strto[T]` functions. Returns `nullopt` if there is an error. + template<class T> + Optional<T> strto(CStringView sv); + + template<> + inline Optional<double> strto<double>(CStringView sv) + { + char* endptr = nullptr; + double res = strtod(sv.c_str(), &endptr); + if (endptr == sv.c_str()) + { + // no digits + return nullopt; + } + // else, we may have HUGE_VAL but we expect the caller to deal with that + return res; + } + + template<> + inline Optional<long> strto<long>(CStringView sv) + { + char* endptr = nullptr; + long res = strtol(sv.c_str(), &endptr, 10); + if (endptr == sv.c_str()) + { + // no digits + return nullopt; + } + if (errno == ERANGE) + { + // out of bounds + return nullopt; + } + + return res; + } + + template<> + inline Optional<long long> strto<long long>(CStringView sv) + { + char* endptr = nullptr; + long long res = strtoll(sv.c_str(), &endptr, 10); + if (endptr == sv.c_str()) + { + // no digits + return nullopt; + } + if (errno == ERANGE) + { + // out of bounds + return nullopt; + } + + return res; + } + + template<> + inline Optional<int> strto<int>(CStringView sv) + { + auto res = strto<long>(sv); + if (auto r = res.get()) + { + if (*r < INT_MIN || *r > INT_MAX) + { + return nullopt; + } + return static_cast<int>(*r); + } + return nullopt; + } + const char* search(StringView haystack, StringView needle); bool contains(StringView haystack, StringView needle); diff --git a/toolsrc/include/vcpkg/base/stringview.h b/toolsrc/include/vcpkg/base/stringview.h index 1bb8fba6b..aee70d697 100644 --- a/toolsrc/include/vcpkg/base/stringview.h +++ b/toolsrc/include/vcpkg/base/stringview.h @@ -2,6 +2,7 @@ #include <vcpkg/base/optional.h> +#include <limits> #include <string> #include <vector> @@ -30,8 +31,8 @@ namespace vcpkg { } - constexpr StringView(const char* ptr, size_t size) : m_ptr(ptr), m_size(size) {} - constexpr StringView(const char* b, const char* e) : m_ptr(b), m_size(static_cast<size_t>(e - b)) {} + constexpr StringView(const char* ptr, size_t size) : m_ptr(ptr), m_size(size) { } + constexpr StringView(const char* b, const char* e) : m_ptr(b), m_size(static_cast<size_t>(e - b)) { } constexpr const char* begin() const { return m_ptr; } constexpr const char* end() const { return m_ptr + m_size; } @@ -42,6 +43,23 @@ namespace vcpkg std::string to_string() const; void to_string(std::string& out) const; + constexpr StringView substr(size_t pos, size_t count = std::numeric_limits<size_t>::max()) const + { + if (pos > m_size) + { + return StringView(); + } + + if (count > m_size - pos) + { + return StringView(m_ptr + pos, m_size - pos); + } + + return StringView(m_ptr + pos, count); + } + + constexpr char byte_at_index(size_t pos) const { return m_ptr[pos]; } + private: const char* m_ptr = 0; size_t m_size = 0; @@ -49,4 +67,8 @@ namespace vcpkg bool operator==(StringView lhs, StringView rhs) noexcept; bool operator!=(StringView lhs, StringView rhs) noexcept; + bool operator<(StringView lhs, StringView rhs) noexcept; + bool operator>(StringView lhs, StringView rhs) noexcept; + bool operator<=(StringView lhs, StringView rhs) noexcept; + bool operator>=(StringView lhs, StringView rhs) noexcept; } diff --git a/toolsrc/include/vcpkg/binaryparagraph.h b/toolsrc/include/vcpkg/binaryparagraph.h index d556a40c8..2d2e4cf20 100644 --- a/toolsrc/include/vcpkg/binaryparagraph.h +++ b/toolsrc/include/vcpkg/binaryparagraph.h @@ -32,15 +32,19 @@ namespace vcpkg PackageSpec spec; std::string version; - std::string description; - std::string maintainer; + int port_version = 0; + std::vector<std::string> description; + std::vector<std::string> maintainers; std::string feature; std::vector<std::string> default_features; - std::vector<std::string> depends; + std::vector<std::string> dependencies; std::string abi; Type type; }; + bool operator==(const BinaryParagraph&, const BinaryParagraph&); + bool operator!=(const BinaryParagraph&, const BinaryParagraph&); + struct BinaryControlFile { BinaryParagraph core_paragraph; diff --git a/toolsrc/include/vcpkg/commands.h b/toolsrc/include/vcpkg/commands.h index f6be93bb2..b73e91fe7 100644 --- a/toolsrc/include/vcpkg/commands.h +++ b/toolsrc/include/vcpkg/commands.h @@ -16,6 +16,12 @@ namespace vcpkg::Commands using CommandTypeB = void (*)(const VcpkgCmdArguments& args, const VcpkgPaths& paths); using CommandTypeC = void (*)(const VcpkgCmdArguments& args, Files::Filesystem& fs); + enum class DryRun : bool + { + No, + Yes, + }; + namespace BuildExternal { void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet); @@ -86,11 +92,6 @@ namespace vcpkg::Commands void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } - namespace Import - { - void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); - } - namespace Integrate { extern const CommandStructure COMMAND_STRUCTURE; @@ -146,9 +147,23 @@ namespace vcpkg::Commands void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } + namespace FormatManifest + { + extern const CommandStructure COMMAND_STRUCTURE; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); + } + namespace SetInstalled { extern const CommandStructure COMMAND_STRUCTURE; + void perform_and_exit_ex(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + const PortFileProvider::PathsPortFileProvider& provider, + IBinaryProvider& binary_provider, + const CMakeVars::CMakeVarProvider& cmake_vars, + const std::vector<FullPackageSpec>& specs, + const Build::BuildPackageOptions& install_plan_options, + DryRun dry_run); void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet); } diff --git a/toolsrc/include/vcpkg/dependencies.h b/toolsrc/include/vcpkg/dependencies.h index 7b1696dc3..5e1c9f657 100644 --- a/toolsrc/include/vcpkg/dependencies.h +++ b/toolsrc/include/vcpkg/dependencies.h @@ -162,5 +162,5 @@ namespace vcpkg::Dependencies void print_plan(const ActionPlan& action_plan, const bool is_recursive = true, - const fs::path& default_ports_dir = ""); + const fs::path& default_ports_dir = {}); } diff --git a/toolsrc/include/vcpkg/logicexpression.h b/toolsrc/include/vcpkg/logicexpression.h deleted file mode 100644 index 3a3d0debe..000000000 --- a/toolsrc/include/vcpkg/logicexpression.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once
-
-#include <string>
-#include <unordered_map>
-#include <vcpkg/base/expected.h>
-
-namespace vcpkg
-{
- struct ExpressionContext
- {
- // map of cmake variables and their values.
- const std::unordered_map<std::string, std::string>& cmake_context;
-
- // The legacy context is a string (typically the name of the triplet).
- // An identifier was considered 'true' if it is a substring of this.
- // It is now used for backwards compatability diagnostic messages and
- // will be eventually removed.
- const std::string& legacy_context;
- };
-
- // Evaluate simple vcpkg logic expressions. An identifier in the expression is considered 'true'
- // if it is a substring of the evaluation_context (typically the name of the triplet)
- ExpectedT<bool, std::string> evaluate_expression(const std::string& expression, const ExpressionContext& context);
-}
\ No newline at end of file diff --git a/toolsrc/include/vcpkg/metrics.h b/toolsrc/include/vcpkg/metrics.h index 832da90ce..89fb8a92f 100644 --- a/toolsrc/include/vcpkg/metrics.h +++ b/toolsrc/include/vcpkg/metrics.h @@ -18,6 +18,7 @@ namespace vcpkg::Metrics void track_metric(const std::string& name, double value); void track_buildtime(const std::string& name, double value); void track_property(const std::string& name, const std::string& value); + void track_feature(const std::string& feature, bool value); bool metrics_enabled(); diff --git a/toolsrc/include/vcpkg/packagespec.h b/toolsrc/include/vcpkg/packagespec.h index 9c90f3fa6..8d055e88a 100644 --- a/toolsrc/include/vcpkg/packagespec.h +++ b/toolsrc/include/vcpkg/packagespec.h @@ -2,6 +2,7 @@ #include <vcpkg/base/expected.h> #include <vcpkg/base/optional.h> +#include <vcpkg/platform-expression.h> #include <vcpkg/triplet.h> namespace vcpkg::Parse @@ -20,7 +21,7 @@ namespace vcpkg struct PackageSpec { PackageSpec() noexcept = default; - PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) {} + PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) { } static std::vector<PackageSpec> to_package_specs(const std::vector<std::string>& ports, Triplet triplet); @@ -53,7 +54,7 @@ namespace vcpkg /// struct FeatureSpec { - FeatureSpec(const PackageSpec& spec, const std::string& feature) : m_spec(spec), m_feature(feature) {} + FeatureSpec(const PackageSpec& spec, const std::string& feature) : m_spec(spec), m_feature(feature) { } const std::string& name() const { return m_spec.name(); } const std::string& feature() const { return m_feature; } @@ -123,10 +124,9 @@ namespace vcpkg struct Dependency { - Features depend; - std::string qualifier; - - static ExpectedS<Dependency> from_string(const std::string& input); + std::string name; + std::vector<std::string> features; + PlatformExpression::Expr platform; }; struct ParsedQualifiedSpecifier @@ -134,7 +134,7 @@ namespace vcpkg std::string name; Optional<std::vector<std::string>> features; Optional<std::string> triplet; - Optional<std::string> qualifier; + Optional<PlatformExpression::Expr> platform; }; Optional<std::string> parse_feature_name(Parse::ParserBase& parser); diff --git a/toolsrc/include/vcpkg/paragraphparser.h b/toolsrc/include/vcpkg/paragraphparser.h index 699838fbd..71d11ddd0 100644 --- a/toolsrc/include/vcpkg/paragraphparser.h +++ b/toolsrc/include/vcpkg/paragraphparser.h @@ -4,6 +4,7 @@ #include <vcpkg/packagespec.h> #include <vcpkg/textrowcol.h> +#include <map> #include <memory> #include <string> #include <unordered_map> @@ -14,9 +15,16 @@ namespace vcpkg::Parse struct ParseControlErrorInfo { std::string name; - std::vector<std::string> missing_fields; - std::vector<std::string> extra_fields; + std::map<std::string, std::vector<std::string>> missing_fields; + std::map<std::string, std::vector<std::string>> extra_fields; + std::map<std::string, std::string> expected_types; + std::map<std::string, std::vector<std::string>> mutually_exclusive_fields; std::string error; + + bool has_error() const + { + return !missing_fields.empty() || !extra_fields.empty() || !expected_types.empty() || !error.empty(); + } }; template<class P> @@ -26,17 +34,23 @@ namespace vcpkg::Parse struct ParagraphParser { - ParagraphParser(Paragraph&& fields) : fields(std::move(fields)) {} + ParagraphParser(Paragraph&& fields) : fields(std::move(fields)) { } + std::string required_field(const std::string& fieldname); void required_field(const std::string& fieldname, std::string& out); - std::string optional_field(const std::string& fieldname); void required_field(const std::string& fieldname, std::pair<std::string&, TextRowCol&> out); + + std::string optional_field(const std::string& fieldname); void optional_field(const std::string& fieldname, std::pair<std::string&, TextRowCol&> out); + + void add_type_error(const std::string& fieldname, const char* type) { expected_types[fieldname] = type; } + std::unique_ptr<ParseControlErrorInfo> error_info(const std::string& name) const; private: Paragraph&& fields; std::vector<std::string> missing_fields; + std::map<std::string, std::string> expected_types; }; ExpectedS<std::vector<std::string>> parse_default_features_list(const std::string& str, diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h index 02e87a76d..8f1c09c5b 100644 --- a/toolsrc/include/vcpkg/paragraphs.h +++ b/toolsrc/include/vcpkg/paragraphs.h @@ -10,11 +10,16 @@ namespace vcpkg::Paragraphs { using Paragraph = Parse::Paragraph; + ExpectedS<Paragraph> parse_single_paragraph(const std::string& str, const std::string& origin); ExpectedS<Paragraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path); ExpectedS<std::vector<Paragraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path); ExpectedS<std::vector<Paragraph>> parse_paragraphs(const std::string& str, const std::string& origin); - Parse::ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& control_path); + bool is_port_directory(const Files::Filesystem& fs, const fs::path& path); + + Parse::ParseExpected<SourceControlFile> try_load_manifest(const Files::Filesystem& fs, const std::string& port_name, const fs::path& path_to_manifest, std::error_code& ec); + + Parse::ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& path); ExpectedS<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec); diff --git a/toolsrc/include/vcpkg/platform-expression.h b/toolsrc/include/vcpkg/platform-expression.h new file mode 100644 index 000000000..d857d75dc --- /dev/null +++ b/toolsrc/include/vcpkg/platform-expression.h @@ -0,0 +1,73 @@ +#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <vcpkg/base/expected.h>
+#include <vcpkg/base/stringview.h>
+
+namespace vcpkg::PlatformExpression
+{
+ // map of cmake variables and their values.
+ using Context = std::unordered_map<std::string, std::string>;
+
+ namespace detail
+ {
+ struct ExprImpl;
+ }
+ struct Expr
+ {
+ static Expr Identifier(StringView id);
+ static Expr Not(Expr&& e);
+ static Expr And(std::vector<Expr>&& exprs);
+ static Expr Or(std::vector<Expr>&& exprs);
+
+ // The empty expression is always true
+ static Expr Empty() { return Expr(); }
+
+ // since ExprImpl is not yet defined, we need to define the ctor and dtor in the C++ file
+ Expr();
+ Expr(const Expr&);
+ Expr(Expr&&);
+ Expr& operator=(const Expr& e);
+ Expr& operator=(Expr&&);
+
+ explicit Expr(std::unique_ptr<detail::ExprImpl>&& e);
+ ~Expr();
+
+ bool evaluate(const Context& context) const;
+ bool is_empty() const { return !static_cast<bool>(underlying_); }
+
+ private:
+ std::unique_ptr<detail::ExprImpl> underlying_;
+ };
+
+ // Note: for backwards compatibility, in CONTROL files,
+ // multiple binary operators are allowed to be next to one another; i.e.
+ // (windows & arm) = (windows && arm) = (windows &&& arm), etc.
+ enum class MultipleBinaryOperators
+ {
+ Deny,
+ Allow,
+ };
+
+ // platform expression parses the following :
+ // <platform-expression>:
+ // <platform-expression.not>
+ // <platform-expression.and>
+ // <platform-expression.or>
+ // <platform-expression.simple>:
+ // ( <platform-expression> )
+ // <platform-expression.identifier>
+ // <platform-expression.identifier>:
+ // A lowercase alpha-numeric string
+ // <platform-expression.not>:
+ // <platform-expression.simple>
+ // ! <platform-expression.simple>
+ // <platform-expression.and>
+ // <platform-expression.not>
+ // <platform-expression.and> & <platform-expression.not>
+ // <platform-expression.or>
+ // <platform-expression.not>
+ // <platform-expression.or> | <platform-expression.not>
+ ExpectedS<Expr> parse_platform_expression(StringView expression, MultipleBinaryOperators multiple_binary_operators);
+}
diff --git a/toolsrc/include/vcpkg/portfileprovider.h b/toolsrc/include/vcpkg/portfileprovider.h index 36cdba589..50abbc8ca 100644 --- a/toolsrc/include/vcpkg/portfileprovider.h +++ b/toolsrc/include/vcpkg/portfileprovider.h @@ -26,7 +26,7 @@ namespace vcpkg::PortFileProvider struct PathsPortFileProvider : Util::ResourceBase, PortFileProvider { explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, - const std::vector<std::string>* ports_dirs_paths); + const std::vector<std::string>& ports_dirs_paths); ExpectedS<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override; std::vector<const SourceControlFileLocation*> load_all_control_files() const override; diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h index 08c306abf..4212258ab 100644 --- a/toolsrc/include/vcpkg/sourceparagraph.h +++ b/toolsrc/include/vcpkg/sourceparagraph.h @@ -1,13 +1,13 @@ #pragma once -#include <string> #include <vcpkg/base/expected.h> +#include <vcpkg/base/json.h> #include <vcpkg/base/span.h> #include <vcpkg/base/system.h> #include <vcpkg/base/system.print.h> +#include <vcpkg/platform-expression.h> #include <vcpkg/packagespec.h> #include <vcpkg/paragraphparser.h> -#include <vector> namespace vcpkg { @@ -28,14 +28,17 @@ namespace vcpkg static Type from_string(const std::string&); }; + bool operator==(const Type&, const Type&); + bool operator!=(const Type&, const Type&); + /// <summary> /// Port metadata of additional feature in a package (part of CONTROL file) /// </summary> struct FeatureParagraph { std::string name; - std::string description; - std::vector<Dependency> depends; + std::vector<std::string> description; + std::vector<Dependency> dependencies; }; /// <summary> @@ -45,13 +48,17 @@ namespace vcpkg { std::string name; std::string version; - std::string description; - std::string maintainer; + int port_version = 0; + std::vector<std::string> description; + std::vector<std::string> maintainers; std::string homepage; - std::vector<Dependency> depends; + std::string documentation; + std::vector<Dependency> dependencies; std::vector<std::string> default_features; + std::string license; // SPDX license expression + Type type; - std::string supports_expression; + PlatformExpression::Expr supports_expression; }; /// <summary> @@ -69,9 +76,13 @@ namespace vcpkg } } + static Parse::ParseExpected<SourceControlFile> parse_manifest_file(const fs::path& path_to_manifest, + const Json::Object& object); + static Parse::ParseExpected<SourceControlFile> parse_control_file( const fs::path& path_to_control, std::vector<Parse::Paragraph>&& control_paragraphs); + // Always non-null in non-error cases std::unique_ptr<SourceParagraph> core_paragraph; std::vector<std::unique_ptr<FeatureParagraph>> feature_paragraphs; diff --git a/toolsrc/include/vcpkg/statusparagraphs.h b/toolsrc/include/vcpkg/statusparagraphs.h index 1fda81316..8fd85b4e0 100644 --- a/toolsrc/include/vcpkg/statusparagraphs.h +++ b/toolsrc/include/vcpkg/statusparagraphs.h @@ -35,8 +35,8 @@ namespace vcpkg /// <param name="triplet">Triplet</param> /// <param name="feature">Feature name</param> /// <returns>Iterator for found spec</returns> - iterator find(const std::string& name, Triplet triplet, const std::string& feature = ""); - const_iterator find(const std::string& name, Triplet triplet, const std::string& feature = "") const; + iterator find(const std::string& name, Triplet triplet, const std::string& feature = {}); + const_iterator find(const std::string& name, Triplet triplet, const std::string& feature = {}) const; std::vector<std::unique_ptr<StatusParagraph>*> find_all(const std::string& name, Triplet triplet); diff --git a/toolsrc/include/vcpkg/vcpkgcmdarguments.h b/toolsrc/include/vcpkg/vcpkgcmdarguments.h index 690245d08..d8dc94a37 100644 --- a/toolsrc/include/vcpkg/vcpkgcmdarguments.h +++ b/toolsrc/include/vcpkg/vcpkgcmdarguments.h @@ -106,32 +106,63 @@ namespace vcpkg static void append_common_options(HelpTableFormatter& target); + constexpr static StringLiteral VCPKG_ROOT_DIR_ENV = "VCPKG_ROOT"; + constexpr static StringLiteral VCPKG_ROOT_DIR_ARG = "vcpkg-root"; std::unique_ptr<std::string> vcpkg_root_dir; + constexpr static StringLiteral MANIFEST_ROOT_DIR_ARG = "x-manifest-root"; + std::unique_ptr<std::string> manifest_root_dir; + constexpr static StringLiteral BUILDTREES_ROOT_DIR_ARG = "x-buildtrees-root"; std::unique_ptr<std::string> buildtrees_root_dir; + constexpr static StringLiteral DOWNLOADS_ROOT_DIR_ENV = "VCPKG_DOWNLOADS"; + constexpr static StringLiteral DOWNLOADS_ROOT_DIR_ARG = "downloads-root"; std::unique_ptr<std::string> downloads_root_dir; + constexpr static StringLiteral INSTALL_ROOT_DIR_ARG = "x-install-root"; std::unique_ptr<std::string> install_root_dir; + constexpr static StringLiteral PACKAGES_ROOT_DIR_ARG = "x-packages-root"; std::unique_ptr<std::string> packages_root_dir; + constexpr static StringLiteral SCRIPTS_ROOT_DIR_ARG = "x-scripts-root"; std::unique_ptr<std::string> scripts_root_dir; + constexpr static StringLiteral DEFAULT_VISUAL_STUDIO_PATH_ENV = "VCPKG_VISUAL_STUDIO_PATH"; std::unique_ptr<std::string> default_visual_studio_path; + constexpr static StringLiteral TRIPLET_ENV = "VCPKG_DEFAULT_TRIPLET"; + constexpr static StringLiteral TRIPLET_ARG = "triplet"; std::unique_ptr<std::string> triplet; - std::unique_ptr<std::vector<std::string>> overlay_ports; - std::unique_ptr<std::vector<std::string>> overlay_triplets; + constexpr static StringLiteral OVERLAY_PORTS_ARG = "overlay-ports"; + std::vector<std::string> overlay_ports; + constexpr static StringLiteral OVERLAY_TRIPLETS_ARG = "overlay-triplets"; + std::vector<std::string> overlay_triplets; - std::vector<std::string> binarysources; + constexpr static StringLiteral BINARY_SOURCES_ARG = "x-binarysource"; + std::vector<std::string> binary_sources; + constexpr static StringLiteral DEBUG_SWITCH = "debug"; Optional<bool> debug = nullopt; + constexpr static StringLiteral SEND_METRICS_SWITCH = "sendmetrics"; Optional<bool> send_metrics = nullopt; // fully disable metrics -- both printing and sending + constexpr static StringLiteral DISABLE_METRICS_ENV = "VCPKG_DISABLE_METRICS"; + constexpr static StringLiteral DISABLE_METRICS_SWITCH = "disable-metrics"; Optional<bool> disable_metrics = nullopt; + constexpr static StringLiteral PRINT_METRICS_SWITCH = "printmetrics"; Optional<bool> print_metrics = nullopt; // feature flags + constexpr static StringLiteral FEATURE_FLAGS_ENV = "VCPKG_FEATURE_FLAGS"; + constexpr static StringLiteral FEATURE_FLAGS_ARG = "feature-flags"; + + constexpr static StringLiteral FEATURE_PACKAGES_SWITCH = "featurepackages"; Optional<bool> feature_packages = nullopt; + constexpr static StringLiteral BINARY_CACHING_FEATURE = "binarycaching"; + constexpr static StringLiteral BINARY_CACHING_SWITCH = "binarycaching"; Optional<bool> binary_caching = nullopt; + constexpr static StringLiteral COMPILER_TRACKING_FEATURE = "compilertracking"; Optional<bool> compiler_tracking = nullopt; + constexpr static StringLiteral MANIFEST_MODE_FEATURE = "manifests"; + Optional<bool> manifest_mode = nullopt; + bool binary_caching_enabled() const { return binary_caching.value_or(false); } bool compiler_tracking_enabled() const { return compiler_tracking.value_or(false); } @@ -142,6 +173,10 @@ namespace vcpkg void imbue_from_environment(); + void check_feature_flag_consistency() const; + + void track_feature_flag_metrics() const; + private: std::unordered_map<std::string, Optional<std::vector<std::string>>> optional_command_arguments; }; diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index c4c420820..90ab3c58d 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -67,11 +67,11 @@ namespace vcpkg std::string name; fs::path location; - TripletFile(const std::string& name, const fs::path& location) : name(name), location(location) {} + TripletFile(const std::string& name, const fs::path& location) : name(name), location(location) { } }; VcpkgPaths(Files::Filesystem& filesystem, const VcpkgCmdArguments& args); - ~VcpkgPaths() noexcept; + ~VcpkgPaths(); fs::path package_dir(const PackageSpec& spec) const; fs::path build_info_file_path(const PackageSpec& spec) const; @@ -84,7 +84,7 @@ namespace vcpkg fs::path original_cwd; fs::path root; - + fs::path manifest_root_dir; fs::path buildtrees; fs::path downloads; fs::path packages; @@ -120,6 +120,9 @@ namespace vcpkg const System::Environment& get_action_env(const Build::AbiInfo& abi_info) const; const std::string& get_triplet_info(const Build::AbiInfo& abi_info) const; + bool manifest_mode_enabled() const { return !manifest_root_dir.empty(); } + + void track_feature_flag_metrics() const; private: std::unique_ptr<details::VcpkgPathsImpl> m_pimpl; |
