aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/include
diff options
context:
space:
mode:
authornicole mazzuca <mazzucan@outlook.com>2020-06-30 10:40:18 -0700
committerGitHub <noreply@github.com>2020-06-30 10:40:18 -0700
commit1d8f0acc9c3085d18152a3f639077a28109196b6 (patch)
tree1daa4780e0d5f51844217dc61dbf275433153abf /toolsrc/include
parent67ab6130b64cce6701c5a95ca3b9bdc4d949cb8a (diff)
downloadvcpkg-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.h20
-rw-r--r--toolsrc/include/vcpkg/base/files.h25
-rw-r--r--toolsrc/include/vcpkg/base/json.h144
-rw-r--r--toolsrc/include/vcpkg/base/strings.h98
-rw-r--r--toolsrc/include/vcpkg/base/stringview.h26
-rw-r--r--toolsrc/include/vcpkg/binaryparagraph.h10
-rw-r--r--toolsrc/include/vcpkg/commands.h25
-rw-r--r--toolsrc/include/vcpkg/dependencies.h2
-rw-r--r--toolsrc/include/vcpkg/logicexpression.h24
-rw-r--r--toolsrc/include/vcpkg/metrics.h1
-rw-r--r--toolsrc/include/vcpkg/packagespec.h14
-rw-r--r--toolsrc/include/vcpkg/paragraphparser.h22
-rw-r--r--toolsrc/include/vcpkg/paragraphs.h7
-rw-r--r--toolsrc/include/vcpkg/platform-expression.h73
-rw-r--r--toolsrc/include/vcpkg/portfileprovider.h2
-rw-r--r--toolsrc/include/vcpkg/sourceparagraph.h27
-rw-r--r--toolsrc/include/vcpkg/statusparagraphs.h4
-rw-r--r--toolsrc/include/vcpkg/vcpkgcmdarguments.h41
-rw-r--r--toolsrc/include/vcpkg/vcpkgpaths.h9
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;