aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Schumacher <roschuma@microsoft.com>2020-02-07 11:24:35 -0800
committerGitHub <noreply@github.com>2020-02-07 11:24:35 -0800
commit8db6db5dac70c25b04cd4dd84392484dee822fbe (patch)
tree4734de271f966ff4b9a913b15c1b7b537ecd1a8d
parent2873f07823df192ba55693d200850669eabe332c (diff)
downloadvcpkg-8db6db5dac70c25b04cd4dd84392484dee822fbe.tar.gz
vcpkg-8db6db5dac70c25b04cd4dd84392484dee822fbe.zip
[vcpkg] Further parser improvements (#9895)
* [vcpkg] Consolidate several internal parsers together (packagespecs + logicexpression + control) and enhance error messages * [vcpkg] Migrate Build-Depends parsing to new framework * [vcpkg] Fix tests. Re-enable underscores in feature names due to libwebp[vwebp_sdl] -- todo: rename this feature and remove underscores.
-rw-r--r--toolsrc/include/vcpkg-test/mockcmakevarprovider.h4
-rw-r--r--toolsrc/include/vcpkg-test/util.h4
-rw-r--r--toolsrc/include/vcpkg/base/expected.h105
-rw-r--r--toolsrc/include/vcpkg/base/optional.h41
-rw-r--r--toolsrc/include/vcpkg/binaryparagraph.h6
-rw-r--r--toolsrc/include/vcpkg/build.h8
-rw-r--r--toolsrc/include/vcpkg/cmakevars.h8
-rw-r--r--toolsrc/include/vcpkg/commands.h14
-rw-r--r--toolsrc/include/vcpkg/dependencies.h2
-rw-r--r--toolsrc/include/vcpkg/export.h2
-rw-r--r--toolsrc/include/vcpkg/input.h6
-rw-r--r--toolsrc/include/vcpkg/install.h2
-rw-r--r--toolsrc/include/vcpkg/packagespec.h54
-rw-r--r--toolsrc/include/vcpkg/packagespecparseresult.h35
-rw-r--r--toolsrc/include/vcpkg/paragraphparser.h45
-rw-r--r--toolsrc/include/vcpkg/paragraphs.h10
-rw-r--r--toolsrc/include/vcpkg/parse.h147
-rw-r--r--toolsrc/include/vcpkg/portfileprovider.h8
-rw-r--r--toolsrc/include/vcpkg/remove.h2
-rw-r--r--toolsrc/include/vcpkg/sourceparagraph.h25
-rw-r--r--toolsrc/include/vcpkg/statusparagraphs.h6
-rw-r--r--toolsrc/include/vcpkg/textrowcol.h12
-rw-r--r--toolsrc/include/vcpkg/triplet.h8
-rw-r--r--toolsrc/include/vcpkg/vcpkgpaths.h6
-rw-r--r--toolsrc/src/vcpkg-test/dependencies.cpp23
-rw-r--r--toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp2
-rw-r--r--toolsrc/src/vcpkg-test/paragraph.cpp48
-rw-r--r--toolsrc/src/vcpkg-test/plan.cpp34
-rw-r--r--toolsrc/src/vcpkg-test/specifier.cpp68
-rw-r--r--toolsrc/src/vcpkg-test/statusparagraphs.cpp22
-rw-r--r--toolsrc/src/vcpkg-test/util.cpp11
-rw-r--r--toolsrc/src/vcpkg/binaryparagraph.cpp27
-rw-r--r--toolsrc/src/vcpkg/build.cpp27
-rw-r--r--toolsrc/src/vcpkg/cmakevars.cpp7
-rw-r--r--toolsrc/src/vcpkg/commands.buildexternal.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.cache.cpp3
-rw-r--r--toolsrc/src/vcpkg/commands.ci.cpp6
-rw-r--r--toolsrc/src/vcpkg/commands.dependinfo.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.env.cpp2
-rw-r--r--toolsrc/src/vcpkg/commands.import.cpp7
-rw-r--r--toolsrc/src/vcpkg/commands.upgrade.cpp2
-rw-r--r--toolsrc/src/vcpkg/dependencies.cpp15
-rw-r--r--toolsrc/src/vcpkg/export.cpp5
-rw-r--r--toolsrc/src/vcpkg/input.cpp10
-rw-r--r--toolsrc/src/vcpkg/install.cpp8
-rw-r--r--toolsrc/src/vcpkg/logicexpression.cpp148
-rw-r--r--toolsrc/src/vcpkg/packagespec.cpp274
-rw-r--r--toolsrc/src/vcpkg/packagespecparseresult.cpp23
-rw-r--r--toolsrc/src/vcpkg/paragraphs.cpp181
-rw-r--r--toolsrc/src/vcpkg/parse.cpp192
-rw-r--r--toolsrc/src/vcpkg/portfileprovider.cpp11
-rw-r--r--toolsrc/src/vcpkg/remove.cpp2
-rw-r--r--toolsrc/src/vcpkg/sourceparagraph.cpp91
-rw-r--r--toolsrc/src/vcpkg/statusparagraph.cpp59
-rw-r--r--toolsrc/src/vcpkg/statusparagraphs.cpp7
-rw-r--r--toolsrc/src/vcpkg/triplet.cpp4
-rw-r--r--toolsrc/src/vcpkg/vcpkgpaths.cpp4
-rw-r--r--toolsrc/vcpkglib/vcpkglib.vcxproj9
-rw-r--r--toolsrc/vcpkglib/vcpkglib.vcxproj.filters31
59 files changed, 958 insertions, 969 deletions
diff --git a/toolsrc/include/vcpkg-test/mockcmakevarprovider.h b/toolsrc/include/vcpkg-test/mockcmakevarprovider.h
index 03defdcdd..21207c856 100644
--- a/toolsrc/include/vcpkg-test/mockcmakevarprovider.h
+++ b/toolsrc/include/vcpkg-test/mockcmakevarprovider.h
@@ -6,7 +6,7 @@ namespace vcpkg::Test
{
struct MockCMakeVarProvider : CMakeVars::CMakeVarProvider
{
- void load_generic_triplet_vars(const Triplet& triplet) const override { generic_triplet_vars[triplet] = {}; }
+ void load_generic_triplet_vars(Triplet triplet) const override { generic_triplet_vars[triplet] = {}; }
void load_dep_info_vars(Span<const PackageSpec> specs) const override
{
@@ -23,7 +23,7 @@ namespace vcpkg::Test
}
Optional<const std::unordered_map<std::string, std::string>&> get_generic_triplet_vars(
- const Triplet& triplet) const override;
+ Triplet triplet) const override;
Optional<const std::unordered_map<std::string, std::string>&> get_dep_info_vars(
const PackageSpec& spec) const override;
diff --git a/toolsrc/include/vcpkg-test/util.h b/toolsrc/include/vcpkg-test/util.h
index 088a39b7d..d8ecc51ea 100644
--- a/toolsrc/include/vcpkg-test/util.h
+++ b/toolsrc/include/vcpkg-test/util.h
@@ -40,7 +40,7 @@ namespace vcpkg::Test
{
std::unordered_map<std::string, SourceControlFileLocation> map;
Triplet triplet;
- PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept : triplet(t) {}
+ PackageSpecMap(Triplet t = Triplet::X86_WINDOWS) noexcept : triplet(t) {}
PackageSpec emplace(const char* name,
const char* depends = "",
@@ -50,8 +50,6 @@ namespace vcpkg::Test
PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl);
};
- vcpkg::PackageSpec unsafe_pspec(std::string name, vcpkg::Triplet t = vcpkg::Triplet::X86_WINDOWS);
-
template<class T, class S>
T&& unwrap(vcpkg::ExpectedT<T, S>&& p)
{
diff --git a/toolsrc/include/vcpkg/base/expected.h b/toolsrc/include/vcpkg/base/expected.h
index c273d71e6..2b19bad2a 100644
--- a/toolsrc/include/vcpkg/base/expected.h
+++ b/toolsrc/include/vcpkg/base/expected.h
@@ -75,6 +75,30 @@ namespace vcpkg
constexpr ExpectedLeftTag expected_left_tag;
constexpr ExpectedRightTag expected_right_tag;
+ template<class T>
+ struct ExpectedHolder
+ {
+ ExpectedHolder() = default;
+ 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; }
+ const T* get() const { return &t; }
+ T t;
+ };
+ template<class T>
+ struct ExpectedHolder<T&>
+ {
+ ExpectedHolder(T& t) : t(&t) {}
+ ExpectedHolder() : t(nullptr) {}
+ using pointer = T*;
+ using const_pointer = T*;
+ T* get() { return t; }
+ T* get() const { return t; }
+ T* t;
+ };
+
template<class T, class S>
class ExpectedT
{
@@ -87,7 +111,10 @@ namespace vcpkg
ExpectedT(S&& s, ExpectedRightTag = {}) : m_s(std::move(s)) {}
ExpectedT(const T& t, ExpectedLeftTag = {}) : m_t(t) {}
- ExpectedT(T&& t, ExpectedLeftTag = {}) : m_t(std::move(t)) {}
+ template<class = std::enable_if<!std::is_reference_v<T>>>
+ ExpectedT(T&& t, ExpectedLeftTag = {}) : m_t(std::move(t))
+ {
+ }
ExpectedT(const ExpectedT&) = default;
ExpectedT(ExpectedT&&) = default;
@@ -100,35 +127,94 @@ namespace vcpkg
T&& value_or_exit(const LineInfo& line_info) &&
{
exit_if_error(line_info);
- return std::move(this->m_t);
+ return std::move(*this->m_t.get());
}
const T& value_or_exit(const LineInfo& line_info) const&
{
exit_if_error(line_info);
- return this->m_t;
+ return *this->m_t.get();
}
const S& error() const& { return this->m_s.error(); }
S&& error() && { return std::move(this->m_s.error()); }
- const T* get() const
+ typename ExpectedHolder<T>::const_pointer get() const
{
if (!this->has_value())
{
return nullptr;
}
- return &this->m_t;
+ return this->m_t.get();
}
- T* get()
+ typename ExpectedHolder<T>::pointer get()
{
if (!this->has_value())
{
return nullptr;
}
- return &this->m_t;
+ return this->m_t.get();
+ }
+
+ template<class F>
+ using map_t = decltype(std::declval<F&>()(*std::declval<typename ExpectedHolder<T>::const_pointer>()));
+
+ template<class F, class U = map_t<F>>
+ ExpectedT<U, S> map(F f) const&
+ {
+ if (has_value())
+ {
+ return {f(*m_t.get()), expected_left_tag};
+ }
+ else
+ {
+ return {error(), expected_right_tag};
+ }
+ }
+
+ template<class F>
+ using move_map_t =
+ decltype(std::declval<F&>()(std::move(*std::declval<typename ExpectedHolder<T>::pointer>())));
+
+ template<class F, class U = move_map_t<F>>
+ ExpectedT<U, S> map(F f) &&
+ {
+ if (has_value())
+ {
+ return {f(std::move(*m_t.get())), expected_left_tag};
+ }
+ else
+ {
+ return {std::move(error()), expected_right_tag};
+ }
+ }
+
+ template<class F, class U = map_t<F>>
+ U then(F f) const&
+ {
+ if (has_value())
+ {
+ return f(*m_t.get());
+ }
+ else
+ {
+ return U{error(), expected_right_tag};
+ }
+ }
+
+ template<class F, class U = move_map_t<F>>
+ U then(F f) &&
+ {
+ if (has_value())
+ {
+ return f(std::move(*m_t.get()));
+ }
+ else
+ {
+ return U{std::move(error()), expected_right_tag};
+ }
}
private:
@@ -143,9 +229,12 @@ namespace vcpkg
}
ErrorHolder<S> m_s;
- T m_t;
+ ExpectedHolder<T> m_t;
};
template<class T>
using Expected = ExpectedT<T, std::error_code>;
+
+ template<class T>
+ using ExpectedS = ExpectedT<T, std::string>;
}
diff --git a/toolsrc/include/vcpkg/base/optional.h b/toolsrc/include/vcpkg/base/optional.h
index 2d8c126c6..fc3733ead 100644
--- a/toolsrc/include/vcpkg/base/optional.h
+++ b/toolsrc/include/vcpkg/base/optional.h
@@ -228,12 +228,21 @@ namespace vcpkg
return this->m_base.has_value() ? this->m_base.value() : static_cast<T>(std::forward<U>(default_value));
}
+ T value_or(T&& default_value) const&
+ {
+ return this->m_base.has_value() ? this->m_base.value() : static_cast<T&&>(default_value);
+ }
+
template<class U>
T value_or(U&& default_value) &&
{
return this->m_base.has_value() ? std::move(this->m_base.value())
: static_cast<T>(std::forward<U>(default_value));
}
+ T value_or(T&& default_value) &&
+ {
+ return this->m_base.has_value() ? std::move(this->m_base.value()) : static_cast<T&&>(default_value);
+ }
typename std::add_pointer<const T>::type get() const
{
@@ -242,6 +251,38 @@ namespace vcpkg
typename std::add_pointer<T>::type get() { return this->m_base.has_value() ? &this->m_base.value() : nullptr; }
+ template<class F>
+ using map_t = decltype(std::declval<F&>()(std::declval<const T&>()));
+
+ template<class F, class U = map_t<F>>
+ U then(F f) const&
+ {
+ if (has_value())
+ {
+ return f(this->m_base.value());
+ }
+ else
+ {
+ return nullopt;
+ }
+ }
+
+ template<class F>
+ using move_map_t = decltype(std::declval<F&>()(std::declval<T&&>()));
+
+ template<class F, class U = move_map_t<F>>
+ U then(F f) &&
+ {
+ if (has_value())
+ {
+ return f(std::move(this->m_base.value()));
+ }
+ else
+ {
+ return nullopt;
+ }
+ }
+
private:
details::OptionalStorage<T> m_base;
};
diff --git a/toolsrc/include/vcpkg/binaryparagraph.h b/toolsrc/include/vcpkg/binaryparagraph.h
index 223a1fb86..05c42dee4 100644
--- a/toolsrc/include/vcpkg/binaryparagraph.h
+++ b/toolsrc/include/vcpkg/binaryparagraph.h
@@ -1,7 +1,7 @@
#pragma once
#include <vcpkg/packagespec.h>
-#include <vcpkg/parse.h>
+#include <vcpkg/paragraphparser.h>
#include <vcpkg/sourceparagraph.h>
namespace vcpkg
@@ -14,12 +14,12 @@ namespace vcpkg
BinaryParagraph();
explicit BinaryParagraph(Parse::RawParagraph fields);
BinaryParagraph(const SourceParagraph& spgh,
- const Triplet& triplet,
+ Triplet triplet,
const std::string& abi_tag,
const std::vector<FeatureSpec>& deps);
BinaryParagraph(const SourceParagraph& spgh,
const FeatureParagraph& fpgh,
- const Triplet& triplet,
+ Triplet triplet,
const std::vector<FeatureSpec>& deps);
std::string displayname() const;
diff --git a/toolsrc/include/vcpkg/build.h b/toolsrc/include/vcpkg/build.h
index b7b7475ef..9d555ae25 100644
--- a/toolsrc/include/vcpkg/build.h
+++ b/toolsrc/include/vcpkg/build.h
@@ -26,7 +26,7 @@ namespace vcpkg::Build
const ParsedArguments& options,
const VcpkgPaths& paths);
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
enum class UseHeadVersion
@@ -140,7 +140,7 @@ namespace vcpkg::Build
struct PreBuildInfo
{
PreBuildInfo(const VcpkgPaths& paths,
- const Triplet& triplet,
+ Triplet triplet,
const std::unordered_map<std::string, std::string>& cmakevars);
std::string triplet_abi_tag;
@@ -197,7 +197,7 @@ namespace vcpkg::Build
struct BuildPackageConfig
{
BuildPackageConfig(const SourceControlFileLocation& scfl,
- const Triplet& triplet,
+ Triplet triplet,
const BuildPackageOptions& build_package_options,
const CMakeVars::CMakeVarProvider& var_provider,
const std::unordered_map<std::string, std::vector<FeatureSpec>>& feature_dependencies,
@@ -217,7 +217,7 @@ namespace vcpkg::Build
const SourceControlFileLocation& scfl;
const SourceControlFile& scf;
- const Triplet& triplet;
+ Triplet triplet;
const fs::path& port_dir;
const BuildPackageOptions& build_package_options;
const CMakeVars::CMakeVarProvider& var_provider;
diff --git a/toolsrc/include/vcpkg/cmakevars.h b/toolsrc/include/vcpkg/cmakevars.h
index c634866d0..8d131d45e 100644
--- a/toolsrc/include/vcpkg/cmakevars.h
+++ b/toolsrc/include/vcpkg/cmakevars.h
@@ -11,7 +11,7 @@ namespace vcpkg::CMakeVars
struct CMakeVarProvider
{
virtual Optional<const std::unordered_map<std::string, std::string>&> get_generic_triplet_vars(
- const Triplet& triplet) const = 0;
+ Triplet triplet) const = 0;
virtual Optional<const std::unordered_map<std::string, std::string>&> get_dep_info_vars(
const PackageSpec& spec) const = 0;
@@ -19,7 +19,7 @@ namespace vcpkg::CMakeVars
virtual Optional<const std::unordered_map<std::string, std::string>&> get_tag_vars(
const PackageSpec& spec) const = 0;
- virtual void load_generic_triplet_vars(const Triplet& triplet) const = 0;
+ virtual void load_generic_triplet_vars(Triplet triplet) const = 0;
virtual void load_dep_info_vars(Span<const PackageSpec> specs) const = 0;
@@ -41,7 +41,7 @@ namespace vcpkg::CMakeVars
public:
explicit TripletCMakeVarProvider(const vcpkg::VcpkgPaths& paths) : paths(paths) {}
- void load_generic_triplet_vars(const Triplet& triplet) const override;
+ void load_generic_triplet_vars(Triplet triplet) const override;
void load_dep_info_vars(Span<const PackageSpec> specs) const override;
@@ -49,7 +49,7 @@ namespace vcpkg::CMakeVars
const PortFileProvider::PortFileProvider& port_provider) const override;
Optional<const std::unordered_map<std::string, std::string>&> get_generic_triplet_vars(
- const Triplet& triplet) const override;
+ Triplet triplet) const override;
Optional<const std::unordered_map<std::string, std::string>&> get_dep_info_vars(
const PackageSpec& spec) const override;
diff --git a/toolsrc/include/vcpkg/commands.h b/toolsrc/include/vcpkg/commands.h
index e73077e1d..9d2d0b6c6 100644
--- a/toolsrc/include/vcpkg/commands.h
+++ b/toolsrc/include/vcpkg/commands.h
@@ -12,27 +12,25 @@
namespace vcpkg::Commands
{
- using CommandTypeA = void (*)(const VcpkgCmdArguments& args,
- const VcpkgPaths& paths,
- const Triplet& default_triplet);
+ using CommandTypeA = void (*)(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
using CommandTypeB = void (*)(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
using CommandTypeC = void (*)(const VcpkgCmdArguments& args);
namespace BuildExternal
{
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
namespace CI
{
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
namespace Env
{
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
namespace Create
@@ -44,7 +42,7 @@ namespace vcpkg::Commands
namespace Upgrade
{
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
namespace Edit
@@ -56,7 +54,7 @@ namespace vcpkg::Commands
namespace DependInfo
{
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
namespace Search
diff --git a/toolsrc/include/vcpkg/dependencies.h b/toolsrc/include/vcpkg/dependencies.h
index eb9d42b6d..1f92ee63c 100644
--- a/toolsrc/include/vcpkg/dependencies.h
+++ b/toolsrc/include/vcpkg/dependencies.h
@@ -121,7 +121,7 @@ namespace vcpkg::Dependencies
RequestType request_type;
Optional<const BinaryParagraph&> core_paragraph() const;
- std::vector<PackageSpec> dependencies(const Triplet& triplet) const;
+ std::vector<PackageSpec> dependencies(Triplet triplet) const;
private:
Optional<InstalledPackageView> m_installed_package;
diff --git a/toolsrc/include/vcpkg/export.h b/toolsrc/include/vcpkg/export.h
index eb99b4fb1..3605081e3 100644
--- a/toolsrc/include/vcpkg/export.h
+++ b/toolsrc/include/vcpkg/export.h
@@ -6,7 +6,7 @@ namespace vcpkg::Export
{
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
void export_integration_files(const fs::path& raw_exported_dir_path, const VcpkgPaths& paths);
}
diff --git a/toolsrc/include/vcpkg/input.h b/toolsrc/include/vcpkg/input.h
index ef481bf52..917b5af10 100644
--- a/toolsrc/include/vcpkg/input.h
+++ b/toolsrc/include/vcpkg/input.h
@@ -5,11 +5,11 @@
namespace vcpkg::Input
{
PackageSpec check_and_get_package_spec(std::string&& spec_string,
- const Triplet& default_triplet,
+ Triplet default_triplet,
CStringView example_text);
FullPackageSpec check_and_get_full_package_spec(std::string&& spec_string,
- const Triplet& default_triplet,
+ Triplet default_triplet,
CStringView example_text);
- void check_triplet(const Triplet& t, const VcpkgPaths& paths);
+ void check_triplet(Triplet t, const VcpkgPaths& paths);
}
diff --git a/toolsrc/include/vcpkg/install.h b/toolsrc/include/vcpkg/install.h
index e020c8653..1c42cc102 100644
--- a/toolsrc/include/vcpkg/install.h
+++ b/toolsrc/include/vcpkg/install.h
@@ -83,5 +83,5 @@ namespace vcpkg::Install
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
}
diff --git a/toolsrc/include/vcpkg/packagespec.h b/toolsrc/include/vcpkg/packagespec.h
index 628352cdb..a37dc99b3 100644
--- a/toolsrc/include/vcpkg/packagespec.h
+++ b/toolsrc/include/vcpkg/packagespec.h
@@ -1,20 +1,16 @@
#pragma once
#include <vcpkg/base/expected.h>
-#include <vcpkg/packagespecparseresult.h>
+#include <vcpkg/base/optional.h>
#include <vcpkg/triplet.h>
-namespace vcpkg
+namespace vcpkg::Parse
{
- struct ParsedSpecifier
- {
- std::string name;
- std::vector<std::string> features;
- std::string triplet;
-
- static ExpectedT<ParsedSpecifier, PackageSpecParseResult> from_string(const std::string& input);
- };
+ struct ParserBase;
+}
+namespace vcpkg
+{
///
/// <summary>
/// Full specification of a package. Contains all information to reference
@@ -26,14 +22,11 @@ namespace vcpkg
PackageSpec() noexcept = default;
PackageSpec(std::string name, Triplet triplet) : m_name(std::move(name)), m_triplet(triplet) {}
- static ExpectedT<PackageSpec, PackageSpecParseResult> from_name_and_triplet(const std::string& name,
- const Triplet& triplet);
-
- static std::vector<PackageSpec> to_package_specs(const std::vector<std::string>& ports, const Triplet& triplet);
+ static std::vector<PackageSpec> to_package_specs(const std::vector<std::string>& ports, Triplet triplet);
const std::string& name() const;
- const Triplet& triplet() const;
+ Triplet triplet() const;
std::string dir() const;
@@ -64,16 +57,13 @@ namespace vcpkg
const std::string& name() const { return m_spec.name(); }
const std::string& feature() const { return m_feature; }
- const Triplet& triplet() const { return m_spec.triplet(); }
+ Triplet triplet() const { return m_spec.triplet(); }
const PackageSpec& spec() const { return m_spec; }
std::string to_string() const;
void to_string(std::string& out) const;
- static std::vector<FeatureSpec> from_strings_and_triplet(const std::vector<std::string>& depends,
- const Triplet& t);
-
bool operator<(const FeatureSpec& other) const
{
if (name() < other.name()) return true;
@@ -115,8 +105,7 @@ namespace vcpkg
std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string>& default_features,
const std::vector<std::string>& all_features) const;
- static ExpectedT<FullPackageSpec, PackageSpecParseResult> from_string(const std::string& spec_as_string,
- const Triplet& default_triplet);
+ static ExpectedS<FullPackageSpec> from_string(const std::string& spec_as_string, Triplet default_triplet);
};
///
@@ -129,9 +118,30 @@ namespace vcpkg
std::string name;
std::vector<std::string> features;
- static ExpectedT<Features, PackageSpecParseResult> from_string(const std::string& input);
+ static ExpectedS<Features> from_string(const std::string& input);
+ };
+
+ struct Dependency
+ {
+ Features depend;
+ std::string qualifier;
+
+ static ExpectedS<Dependency> from_string(const std::string& input);
};
+ struct ParsedQualifiedSpecifier
+ {
+ std::string name;
+ Optional<std::vector<std::string>> features;
+ Optional<std::string> triplet;
+ Optional<std::string> qualifier;
+ };
+
+ Optional<std::string> parse_feature_name(Parse::ParserBase& parser);
+ Optional<std::string> parse_package_name(Parse::ParserBase& parser);
+ ExpectedS<ParsedQualifiedSpecifier> parse_qualified_specifier(CStringView input);
+ Optional<ParsedQualifiedSpecifier> parse_qualified_specifier(Parse::ParserBase& parser);
+
bool operator==(const PackageSpec& left, const PackageSpec& right);
bool operator!=(const PackageSpec& left, const PackageSpec& right);
}
diff --git a/toolsrc/include/vcpkg/packagespecparseresult.h b/toolsrc/include/vcpkg/packagespecparseresult.h
deleted file mode 100644
index 4c99c84c7..000000000
--- a/toolsrc/include/vcpkg/packagespecparseresult.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-#include <vcpkg/base/cstringview.h>
-#include <vcpkg/base/expected.h>
-
-namespace vcpkg
-{
- enum class PackageSpecParseResult
- {
- SUCCESS = 0,
- TOO_MANY_COLONS,
- INVALID_CHARACTERS
- };
-
- void to_string(std::string& out, ::vcpkg::PackageSpecParseResult p);
-
- CStringView to_string(PackageSpecParseResult ev) noexcept;
-
- template<>
- struct ErrorHolder<PackageSpecParseResult>
- {
- ErrorHolder() noexcept : m_err(PackageSpecParseResult::SUCCESS) {}
- ErrorHolder(PackageSpecParseResult err) : m_err(err) {}
-
- bool has_error() const { return m_err != PackageSpecParseResult::SUCCESS; }
-
- const PackageSpecParseResult& error() const { return m_err; }
- PackageSpecParseResult& error() { return m_err; }
-
- CStringView to_string() const { return vcpkg::to_string(m_err); }
-
- private:
- PackageSpecParseResult m_err;
- };
-}
diff --git a/toolsrc/include/vcpkg/paragraphparser.h b/toolsrc/include/vcpkg/paragraphparser.h
new file mode 100644
index 000000000..86c3d0228
--- /dev/null
+++ b/toolsrc/include/vcpkg/paragraphparser.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <vcpkg/base/expected.h>
+#include <vcpkg/packagespec.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace vcpkg::Parse
+{
+ struct ParseControlErrorInfo
+ {
+ std::string name;
+ std::vector<std::string> missing_fields;
+ std::vector<std::string> extra_fields;
+ std::string error;
+ };
+
+ template<class P>
+ using ParseExpected = vcpkg::ExpectedT<std::unique_ptr<P>, std::unique_ptr<ParseControlErrorInfo>>;
+
+ using RawParagraph = std::unordered_map<std::string, std::string>;
+
+ struct ParagraphParser
+ {
+ ParagraphParser(RawParagraph&& fields) : fields(std::move(fields)) {}
+
+ void required_field(const std::string& fieldname, std::string& out);
+ std::string optional_field(const std::string& fieldname) const;
+ std::unique_ptr<ParseControlErrorInfo> error_info(const std::string& name) const;
+
+ private:
+ RawParagraph&& fields;
+ std::vector<std::string> missing_fields;
+ };
+
+ ExpectedS<std::vector<std::string>> parse_default_features_list(const std::string& str,
+ CStringView origin = "<unknown>");
+ ExpectedS<std::vector<ParsedQualifiedSpecifier>> parse_qualified_specifier_list(const std::string& str,
+ CStringView origin = "<unknown>");
+ ExpectedS<std::vector<Dependency>> parse_dependencies_list(const std::string& str,
+ CStringView origin = "<unknown>");
+}
diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h
index 7e2410aef..cffe85af7 100644
--- a/toolsrc/include/vcpkg/paragraphs.h
+++ b/toolsrc/include/vcpkg/paragraphs.h
@@ -1,7 +1,7 @@
#pragma once
#include <vcpkg/binaryparagraph.h>
-#include <vcpkg/parse.h>
+#include <vcpkg/paragraphparser.h>
#include <vcpkg/vcpkgpaths.h>
#include <vcpkg/base/expected.h>
@@ -10,13 +10,13 @@ namespace vcpkg::Paragraphs
{
using RawParagraph = Parse::RawParagraph;
- Expected<RawParagraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path);
- Expected<std::vector<RawParagraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path);
- Expected<std::vector<RawParagraph>> parse_paragraphs(const std::string& str);
+ ExpectedS<RawParagraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path);
+ ExpectedS<std::vector<RawParagraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path);
+ ExpectedS<std::vector<RawParagraph>> 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);
- Expected<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec);
+ ExpectedS<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec);
struct LoadResults
{
diff --git a/toolsrc/include/vcpkg/parse.h b/toolsrc/include/vcpkg/parse.h
index 4b33e302e..3214305bf 100644
--- a/toolsrc/include/vcpkg/parse.h
+++ b/toolsrc/include/vcpkg/parse.h
@@ -1,38 +1,147 @@
#pragma once
-#include <vcpkg/base/expected.h>
+#include <vcpkg/base/cstringview.h>
#include <vcpkg/base/optional.h>
+#include <vcpkg/base/stringview.h>
+#include <vcpkg/textrowcol.h>
#include <memory>
-#include <unordered_map>
+#include <string>
namespace vcpkg::Parse
{
- struct ParseControlErrorInfo
+ struct IParseError
{
- std::string name;
- std::vector<std::string> missing_fields;
- std::vector<std::string> extra_fields;
- std::error_code error;
+ virtual ~IParseError() = default;
+ virtual std::string format() const = 0;
};
- template<class P>
- using ParseExpected = ExpectedT<std::unique_ptr<P>, std::unique_ptr<ParseControlErrorInfo>>;
+ struct ParseError : IParseError
+ {
+ ParseError(std::string origin, int row, int column, std::string line, std::string message)
+ : origin(std::move(origin)), row(row), column(column), line(std::move(line)), message(std::move(message))
+ {
+ }
+
+ const std::string origin;
+ const int row;
+ const int column;
+ const std::string line;
+ const std::string message;
- using RawParagraph = std::unordered_map<std::string, std::string>;
+ virtual std::string format() const override;
+ };
- struct ParagraphParser
+ struct ParserBase
{
- ParagraphParser(RawParagraph&& fields) : fields(std::move(fields)) {}
+ struct SourceLoc
+ {
+ const char* it;
+ int row;
+ int column;
+ };
+
+ void init(CStringView text, CStringView origin, TextRowCol init_rowcol = {})
+ {
+ m_text = text;
+ m_origin = origin;
+ m_it = text.c_str();
+ row = init_rowcol.row ? init_rowcol.row : 1;
+ column = init_rowcol.column ? init_rowcol.column : 1;
+ }
+
+ static constexpr bool is_whitespace(char ch) { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; }
+ static constexpr bool is_lower_alpha(char ch) { return ch >= 'a' && ch <= 'z'; }
+ static constexpr bool is_upper_alpha(char ch) { return ch >= 'A' && ch <= 'Z'; }
+ static constexpr bool is_ascii_digit(char ch) { return ch >= '0' && ch <= '9'; }
+ static constexpr bool is_lineend(char ch) { return ch == '\r' || ch == '\n' || ch == '\0'; }
+ static constexpr bool is_alphanum(char ch)
+ {
+ return is_upper_alpha(ch) || is_lower_alpha(ch) || is_ascii_digit(ch);
+ }
+ static constexpr bool is_alphanumdash(char ch) { return is_alphanum(ch) || ch == '-'; }
+
+ StringView skip_whitespace() { return match_zero_or_more(is_whitespace); }
+ StringView skip_tabs_spaces()
+ {
+ return match_zero_or_more([](char ch) { return ch == ' ' || ch == '\t'; });
+ }
+ void skip_to_eof()
+ {
+ while (cur())
+ ++m_it;
+ }
+ void skip_newline()
+ {
+ if (cur() == '\r') next();
+ if (cur() == '\n') next();
+ }
+ void skip_line()
+ {
+ match_until(is_lineend);
+ skip_newline();
+ }
- void required_field(const std::string& fieldname, std::string& out);
- std::string optional_field(const std::string& fieldname) const;
- std::unique_ptr<ParseControlErrorInfo> error_info(const std::string& name) const;
+ template<class Pred>
+ StringView match_zero_or_more(Pred p)
+ {
+ const char* start = m_it;
+ auto ch = cur();
+ while (ch != '\0' && p(ch))
+ ch = next();
+ return {start, m_it};
+ }
+ template<class Pred>
+ StringView match_until(Pred p)
+ {
+ const char* start = m_it;
+ auto ch = cur();
+ while (ch != '\0' && !p(ch))
+ ch = next();
+ return {start, m_it};
+ }
+
+ CStringView text() const { return m_text; }
+ const char* it() const { return m_it; }
+ char cur() const { return *m_it; }
+ SourceLoc cur_loc() const { return {m_it, row, column}; }
+ char next()
+ {
+ char ch = *m_it;
+ // See https://www.gnu.org/prep/standards/standards.html#Errors
+ if (ch == '\t')
+ column = (column + 7) / 8 * 8 + 1; // round to next 8-width tab stop
+ else if (ch == '\n')
+ {
+ row++;
+ column = 1;
+ }
+ else if (ch == '\0')
+ {
+ return '\0';
+ }
+ else
+ {
+ ++column;
+ }
+ return *++m_it;
+ }
+ bool at_eof() const { return *m_it == 0; }
+
+ void add_error(std::string message) { add_error(std::move(message), cur_loc()); }
+ void add_error(std::string message, const SourceLoc& loc);
+
+ const Parse::IParseError* get_error() const { return m_err.get(); }
+ std::unique_ptr<Parse::IParseError> extract_error() { return std::move(m_err); }
private:
- RawParagraph&& fields;
- std::vector<std::string> missing_fields;
- };
+ const char* m_it;
+ int row;
+ int column;
+
+ CStringView m_text;
+ CStringView m_origin;
- std::vector<std::string> parse_comma_list(const std::string& str);
+ std::unique_ptr<IParseError> m_err;
+ };
}
diff --git a/toolsrc/include/vcpkg/portfileprovider.h b/toolsrc/include/vcpkg/portfileprovider.h
index 79f69d9ae..36cdba589 100644
--- a/toolsrc/include/vcpkg/portfileprovider.h
+++ b/toolsrc/include/vcpkg/portfileprovider.h
@@ -1,6 +1,6 @@
#pragma once
-#include <vcpkg/base/optional.h>
+#include <vcpkg/base/expected.h>
#include <vcpkg/base/util.h>
#include <vcpkg/sourceparagraph.h>
#include <vcpkg/vcpkgpaths.h>
@@ -9,14 +9,14 @@ namespace vcpkg::PortFileProvider
{
struct PortFileProvider
{
- virtual Optional<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const = 0;
+ virtual ExpectedS<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const = 0;
virtual std::vector<const SourceControlFileLocation*> load_all_control_files() const = 0;
};
struct MapPortFileProvider : Util::ResourceBase, PortFileProvider
{
explicit MapPortFileProvider(const std::unordered_map<std::string, SourceControlFileLocation>& map);
- Optional<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override;
+ ExpectedS<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override;
std::vector<const SourceControlFileLocation*> load_all_control_files() const override;
private:
@@ -27,7 +27,7 @@ namespace vcpkg::PortFileProvider
{
explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths,
const std::vector<std::string>* ports_dirs_paths);
- Optional<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override;
+ ExpectedS<const SourceControlFileLocation&> get_control_file(const std::string& src_name) const override;
std::vector<const SourceControlFileLocation*> load_all_control_files() const override;
private:
diff --git a/toolsrc/include/vcpkg/remove.h b/toolsrc/include/vcpkg/remove.h
index 36aeda2ad..c43bc73c2 100644
--- a/toolsrc/include/vcpkg/remove.h
+++ b/toolsrc/include/vcpkg/remove.h
@@ -21,6 +21,6 @@ namespace vcpkg::Remove
extern const CommandStructure COMMAND_STRUCTURE;
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet);
void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db);
}
diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h
index 0574afe74..bdb75fc58 100644
--- a/toolsrc/include/vcpkg/sourceparagraph.h
+++ b/toolsrc/include/vcpkg/sourceparagraph.h
@@ -1,37 +1,20 @@
#pragma once
-#include <vcpkg/packagespec.h>
-#include <vcpkg/parse.h>
-
+#include <string>
#include <vcpkg/base/expected.h>
#include <vcpkg/base/span.h>
#include <vcpkg/base/system.h>
-
#include <vcpkg/base/system.print.h>
-
-#include <string>
+#include <vcpkg/packagespec.h>
+#include <vcpkg/paragraphparser.h>
#include <vector>
namespace vcpkg
{
- struct Dependency
- {
- Features depend;
- std::string qualifier;
-
- std::string name() const;
- static Dependency parse_dependency(std::string name, std::string qualifier);
- };
-
std::vector<FullPackageSpec> filter_dependencies(const std::vector<Dependency>& deps,
- const Triplet& t,
+ Triplet t,
const std::unordered_map<std::string, std::string>& cmake_vars);
- // zlib[uwp] becomes Dependency{"zlib", "uwp"}
- std::vector<Dependency> expand_qualified_dependencies(const std::vector<std::string>& depends);
-
- std::string to_string(const Dependency& dep);
-
struct Type
{
enum
diff --git a/toolsrc/include/vcpkg/statusparagraphs.h b/toolsrc/include/vcpkg/statusparagraphs.h
index fa064de7e..7fcf0e916 100644
--- a/toolsrc/include/vcpkg/statusparagraphs.h
+++ b/toolsrc/include/vcpkg/statusparagraphs.h
@@ -35,10 +35,10 @@ 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, const Triplet& triplet, const std::string& feature = "");
- const_iterator find(const std::string& name, const 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, const Triplet& triplet);
+ std::vector<std::unique_ptr<StatusParagraph>*> find_all(const std::string& name, Triplet triplet);
Optional<InstalledPackageView> find_all_installed(const PackageSpec& spec) const;
diff --git a/toolsrc/include/vcpkg/textrowcol.h b/toolsrc/include/vcpkg/textrowcol.h
new file mode 100644
index 000000000..5bbf6a899
--- /dev/null
+++ b/toolsrc/include/vcpkg/textrowcol.h
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace vcpkg::Parse
+{
+ struct TextRowCol
+ {
+ /// '0' indicates uninitialized; '1' is the first row.
+ int row = 0;
+ /// '0' indicates uninitialized; '1' is the first column.
+ int column = 0;
+ };
+}
diff --git a/toolsrc/include/vcpkg/triplet.h b/toolsrc/include/vcpkg/triplet.h
index f33f40fd5..8d8c3e879 100644
--- a/toolsrc/include/vcpkg/triplet.h
+++ b/toolsrc/include/vcpkg/triplet.h
@@ -27,8 +27,8 @@ namespace vcpkg
void to_string(std::string& out) const;
size_t hash_code() const;
- bool operator==(const Triplet& other) const;
- bool operator<(const Triplet& other) const { return canonical_name() < other.canonical_name(); }
+ bool operator==(Triplet other) const { return this->m_instance == other.m_instance; }
+ bool operator<(Triplet other) const { return canonical_name() < other.canonical_name(); }
private:
static const TripletInstance DEFAULT_INSTANCE;
@@ -38,7 +38,7 @@ namespace vcpkg
const TripletInstance* m_instance;
};
- bool operator!=(const Triplet& left, const Triplet& right);
+ inline bool operator!=(Triplet left, Triplet right) { return !(left == right); }
}
namespace std
@@ -46,6 +46,6 @@ namespace std
template<>
struct hash<vcpkg::Triplet>
{
- size_t operator()(const vcpkg::Triplet& t) const { return t.hash_code(); }
+ size_t operator()(vcpkg::Triplet t) const { return t.hash_code(); }
};
}
diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h
index 52d77d283..63d19af2c 100644
--- a/toolsrc/include/vcpkg/vcpkgpaths.h
+++ b/toolsrc/include/vcpkg/vcpkgpaths.h
@@ -52,7 +52,7 @@ 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) {}
};
static Expected<VcpkgPaths> create(const fs::path& vcpkg_root_dir,
@@ -64,10 +64,10 @@ namespace vcpkg
fs::path build_info_file_path(const PackageSpec& spec) const;
fs::path listfile_path(const BinaryParagraph& pgh) const;
- bool is_valid_triplet(const Triplet& t) const;
+ bool is_valid_triplet(Triplet t) const;
const std::vector<std::string> get_available_triplets_names() const;
const std::vector<TripletFile>& get_available_triplets() const;
- const fs::path get_triplet_file_path(const Triplet& triplet) const;
+ const fs::path get_triplet_file_path(Triplet triplet) const;
fs::path root;
fs::path packages;
diff --git a/toolsrc/src/vcpkg-test/dependencies.cpp b/toolsrc/src/vcpkg-test/dependencies.cpp
index 63e7cfee7..c9eb0df35 100644
--- a/toolsrc/src/vcpkg-test/dependencies.cpp
+++ b/toolsrc/src/vcpkg-test/dependencies.cpp
@@ -2,14 +2,17 @@
#include <vcpkg-test/mockcmakevarprovider.h>
#include <vcpkg-test/util.h>
#include <vcpkg/dependencies.h>
+#include <vcpkg/paragraphparser.h>
#include <vcpkg/sourceparagraph.h>
using namespace vcpkg;
-using Parse::parse_comma_list;
+using namespace vcpkg::Parse;
TEST_CASE ("parse depends", "[dependencies]")
{
- auto v = expand_qualified_dependencies(parse_comma_list("liba (windows)"));
+ auto w = parse_dependencies_list("liba (windows)");
+ REQUIRE(w);
+ auto& v = *w.get();
REQUIRE(v.size() == 1);
REQUIRE(v.at(0).depend.name == "liba");
REQUIRE(v.at(0).qualifier == "windows");
@@ -23,7 +26,9 @@ TEST_CASE ("filter depends", "[dependencies]")
const std::unordered_map<std::string, std::string> arm_uwp_cmake_vars{{"VCPKG_TARGET_ARCHITECTURE", "arm"},
{"VCPKG_CMAKE_SYSTEM_NAME", "WindowsStore"}};
- auto deps = expand_qualified_dependencies(parse_comma_list("liba (windows), libb, libc (uwp)"));
+ auto deps_ = parse_dependencies_list("liba (!uwp), libb, libc (uwp)");
+ REQUIRE(deps_);
+ auto& deps = *deps_.get();
auto v = filter_dependencies(deps, Triplet::X64_WINDOWS, x64_win_cmake_vars);
REQUIRE(v.size() == 2);
REQUIRE(v.at(0).package_spec.name() == "liba");
@@ -37,10 +42,10 @@ TEST_CASE ("filter depends", "[dependencies]")
TEST_CASE ("parse feature depends", "[dependencies]")
{
- auto u = parse_comma_list("libwebp[anim, gif2webp, img2webp, info, mux, nearlossless, "
- "simd, cwebp, dwebp], libwebp[vwebp_sdl, extras] (!osx)");
- REQUIRE(u.at(1) == "libwebp[vwebp_sdl, extras] (!osx)");
- auto v = expand_qualified_dependencies(u);
+ auto u_ = parse_dependencies_list("libwebp[anim, gif2webp, img2webp, info, mux, nearlossless, "
+ "simd, cwebp, dwebp], libwebp[vwebp-sdl, extras] (!osx)");
+ REQUIRE(u_);
+ auto& v = *u_.get();
REQUIRE(v.size() == 2);
auto&& a0 = v.at(0);
REQUIRE(a0.depend.name == "libwebp");
@@ -67,9 +72,7 @@ TEST_CASE ("qualified dependency", "[dependencies]")
REQUIRE(plan.install_actions.size() == 2);
REQUIRE(plan.install_actions.at(0).feature_list == std::vector<std::string>{"core"});
- FullPackageSpec linspec_a{PackageSpec::from_name_and_triplet("a", Triplet::from_canonical_name("x64-linux"))
- .value_or_exit(VCPKG_LINE_INFO),
- {}};
+ FullPackageSpec linspec_a{{"a", Triplet::from_canonical_name("x64-linux")}, {}};
var_provider.dep_info_vars[linspec_a.package_spec].emplace("VCPKG_CMAKE_SYSTEM_NAME", "Linux");
auto plan2 = vcpkg::Dependencies::create_feature_install_plan(map_port, var_provider, {linspec_a}, {});
REQUIRE(plan2.install_actions.size() == 2);
diff --git a/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp b/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
index eda1a7a64..655bc33b4 100644
--- a/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
+++ b/toolsrc/src/vcpkg-test/mockcmakevarsprovider.cpp
@@ -3,7 +3,7 @@
namespace vcpkg::Test
{
Optional<const std::unordered_map<std::string, std::string>&> MockCMakeVarProvider::get_generic_triplet_vars(
- const Triplet& triplet) const
+ Triplet triplet) const
{
auto it = generic_triplet_vars.find(triplet);
if (it == generic_triplet_vars.end()) return nullopt;
diff --git a/toolsrc/src/vcpkg-test/paragraph.cpp b/toolsrc/src/vcpkg-test/paragraph.cpp
index 2ee4efe2f..21da80c5b 100644
--- a/toolsrc/src/vcpkg-test/paragraph.cpp
+++ b/toolsrc/src/vcpkg-test/paragraph.cpp
@@ -46,7 +46,7 @@ TEST_CASE ("SourceParagraph construct maximum", "[paragraph]")
REQUIRE(pgh.core_paragraph->maintainer == "m");
REQUIRE(pgh.core_paragraph->description == "d");
REQUIRE(pgh.core_paragraph->depends.size() == 1);
- REQUIRE(pgh.core_paragraph->depends[0].name() == "bd");
+ REQUIRE(pgh.core_paragraph->depends[0].depend.name == "bd");
REQUIRE(pgh.core_paragraph->default_features.size() == 1);
REQUIRE(pgh.core_paragraph->default_features[0] == "df");
}
@@ -64,8 +64,8 @@ TEST_CASE ("SourceParagraph two depends", "[paragraph]")
auto& pgh = **m_pgh.get();
REQUIRE(pgh.core_paragraph->depends.size() == 2);
- REQUIRE(pgh.core_paragraph->depends[0].name() == "z");
- REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl");
+ REQUIRE(pgh.core_paragraph->depends[0].depend.name == "z");
+ REQUIRE(pgh.core_paragraph->depends[1].depend.name == "openssl");
}
TEST_CASE ("SourceParagraph three depends", "[paragraph]")
@@ -81,9 +81,9 @@ TEST_CASE ("SourceParagraph three depends", "[paragraph]")
auto& pgh = **m_pgh.get();
REQUIRE(pgh.core_paragraph->depends.size() == 3);
- REQUIRE(pgh.core_paragraph->depends[0].name() == "z");
- REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl");
- REQUIRE(pgh.core_paragraph->depends[2].name() == "xyz");
+ REQUIRE(pgh.core_paragraph->depends[0].depend.name == "z");
+ REQUIRE(pgh.core_paragraph->depends[1].depend.name == "openssl");
+ REQUIRE(pgh.core_paragraph->depends[2].depend.name == "xyz");
}
TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]")
@@ -93,7 +93,7 @@ TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]")
std::vector<std::unordered_map<std::string, std::string>>{{
{"Source", "zlib"},
{"Version", "1.2.8"},
- {"Build-Depends", "libA (windows), libB (uwp)"},
+ {"Build-Depends", "liba (windows), libb (uwp)"},
}});
REQUIRE(m_pgh.has_value());
auto& pgh = **m_pgh.get();
@@ -103,9 +103,9 @@ TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]")
REQUIRE(pgh.core_paragraph->maintainer == "");
REQUIRE(pgh.core_paragraph->description == "");
REQUIRE(pgh.core_paragraph->depends.size() == 2);
- REQUIRE(pgh.core_paragraph->depends[0].name() == "libA");
+ REQUIRE(pgh.core_paragraph->depends[0].depend.name == "liba");
REQUIRE(pgh.core_paragraph->depends[0].qualifier == "windows");
- REQUIRE(pgh.core_paragraph->depends[1].name() == "libB");
+ REQUIRE(pgh.core_paragraph->depends[1].depend.name == "libb");
REQUIRE(pgh.core_paragraph->depends[1].qualifier == "uwp");
}
@@ -210,14 +210,14 @@ TEST_CASE ("BinaryParagraph default features", "[paragraph]")
TEST_CASE ("parse paragraphs empty", "[paragraph]")
{
const char* str = "";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.empty());
}
TEST_CASE ("parse paragraphs one field", "[paragraph]")
{
const char* str = "f1: v1";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 1);
REQUIRE(pghs[0]["f1"] == "v1");
@@ -227,7 +227,7 @@ TEST_CASE ("parse paragraphs one pgh", "[paragraph]")
{
const char* str = "f1: v1\n"
"f2: v2";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 2);
REQUIRE(pghs[0]["f1"] == "v1");
@@ -241,7 +241,7 @@ TEST_CASE ("parse paragraphs two pgh", "[paragraph]")
"\n"
"f3: v3\n"
"f4: v4";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 2);
REQUIRE(pghs[0].size() == 2);
@@ -259,7 +259,7 @@ TEST_CASE ("parse paragraphs field names", "[paragraph]")
"F:\n"
"0:\n"
"F-2:\n";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 5);
@@ -273,7 +273,7 @@ TEST_CASE ("parse paragraphs multiple blank lines", "[paragraph]")
"\n"
"f3: v3\n"
"f4: v4";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 2);
}
@@ -282,7 +282,7 @@ TEST_CASE ("parse paragraphs empty fields", "[paragraph]")
{
const char* str = "f1:\n"
"f2: ";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 2);
@@ -298,7 +298,7 @@ TEST_CASE ("parse paragraphs multiline fields", "[paragraph]")
"f2:\r\n"
" f2\r\n"
" continue\r\n";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0]["f1"] == "simple\n f1");
@@ -312,7 +312,7 @@ TEST_CASE ("parse paragraphs crlfs", "[paragraph]")
"\r\n"
"f3: v3\r\n"
"f4: v4";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 2);
REQUIRE(pghs[0].size() == 2);
@@ -334,7 +334,7 @@ TEST_CASE ("parse paragraphs comment", "[paragraph]")
"f3: v3\r\n"
"#comment\r\n"
"f4: v4";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 2);
REQUIRE(pghs[0].size() == 2);
@@ -349,7 +349,7 @@ TEST_CASE ("parse comment before single line feed", "[paragraph]")
{
const char* str = "f1: v1\r\n"
"#comment\n";
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(str, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs[0].size() == 1);
REQUIRE(pghs[0]["f1"] == "v1");
}
@@ -363,7 +363,7 @@ TEST_CASE ("BinaryParagraph serialize min", "[paragraph]")
{"Multi-Arch", "same"},
});
std::string ss = Strings::serialize(pgh);
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 5);
@@ -386,7 +386,7 @@ TEST_CASE ("BinaryParagraph serialize max", "[paragraph]")
{"Multi-Arch", "same"},
});
std::string ss = Strings::serialize(pgh);
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0].size() == 8);
@@ -409,7 +409,7 @@ TEST_CASE ("BinaryParagraph serialize multiple deps", "[paragraph]")
{"Depends", "a, b, c"},
});
std::string ss = Strings::serialize(pgh);
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0]["Depends"] == "a, b, c");
@@ -426,7 +426,7 @@ TEST_CASE ("BinaryParagraph serialize abi", "[paragraph]")
{"Abi", "123abc"},
});
std::string ss = Strings::serialize(pgh);
- auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO);
+ auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss, "").value_or_exit(VCPKG_LINE_INFO);
REQUIRE(pghs.size() == 1);
REQUIRE(pghs[0]["Abi"] == "123abc");
diff --git a/toolsrc/src/vcpkg-test/plan.cpp b/toolsrc/src/vcpkg-test/plan.cpp
index 594c9783b..d3d4310e9 100644
--- a/toolsrc/src/vcpkg-test/plan.cpp
+++ b/toolsrc/src/vcpkg-test/plan.cpp
@@ -19,7 +19,6 @@ using Test::make_status_feature_pgh;
using Test::make_status_pgh;
using Test::MockCMakeVarProvider;
using Test::PackageSpecMap;
-using Test::unsafe_pspec;
/// <summary>
/// Assert that the given action an install of given features from given package.
@@ -27,7 +26,7 @@ using Test::unsafe_pspec;
static void features_check(Dependencies::InstallPlanAction& plan,
std::string pkg_name,
std::vector<std::string> expected_features,
- const Triplet& triplet = Triplet::X86_WINDOWS)
+ Triplet triplet = Triplet::X86_WINDOWS)
{
const auto& feature_list = plan.feature_list;
@@ -53,7 +52,7 @@ static void features_check(Dependencies::InstallPlanAction& plan,
/// </summary>
static void remove_plan_check(Dependencies::RemovePlanAction& plan,
std::string pkg_name,
- const Triplet& triplet = Triplet::X86_WINDOWS)
+ Triplet triplet = Triplet::X86_WINDOWS)
{
REQUIRE(plan.spec.triplet().to_string() == triplet.to_string());
REQUIRE(pkg_name == plan.spec.name());
@@ -381,8 +380,7 @@ TEST_CASE ("basic feature test 8", "[plan]")
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("a"));
status_paragraphs.push_back(make_status_pgh("a"));
- status_paragraphs.back()->package.spec =
- PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ status_paragraphs.back()->package.spec = PackageSpec("a", Triplet::X64_WINDOWS);
PackageSpecMap spec_map(Triplet::X64_WINDOWS);
auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}};
@@ -464,8 +462,7 @@ TEST_CASE ("install default features test 2", "[plan]")
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("a"));
- status_paragraphs.back()->package.spec =
- PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ status_paragraphs.back()->package.spec = PackageSpec("a", Triplet::X64_WINDOWS);
// Add a port "a" of which "core" is already installed, but we will
// install the default features "explicitly"
@@ -610,8 +607,7 @@ TEST_CASE ("do not install default features of existing dependency", "[plan]")
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
// "b[core]" is already installed
status_paragraphs.push_back(make_status_pgh("b"));
- status_paragraphs.back()->package.spec =
- PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ status_paragraphs.back()->package.spec = PackageSpec("b", Triplet::X64_WINDOWS);
// Install "a" (without explicit feature specification)
auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS);
@@ -632,8 +628,7 @@ TEST_CASE ("install default features of dependency test 3", "[plan]")
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
status_paragraphs.push_back(make_status_pgh("b"));
- status_paragraphs.back()->package.spec =
- PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ status_paragraphs.back()->package.spec = PackageSpec("b", Triplet::X64_WINDOWS);
// Add a port "a" which depends on the core of "b", which was already
// installed explicitly
@@ -945,7 +940,7 @@ TEST_CASE ("basic remove scheme", "[plan]")
pghs.push_back(make_status_pgh("a"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"a", Triplet::X86_WINDOWS}}, status_db);
REQUIRE(remove_plan.size() == 1);
REQUIRE(remove_plan.at(0).spec.name() == "a");
@@ -958,7 +953,7 @@ TEST_CASE ("recurse remove scheme", "[plan]")
pghs.push_back(make_status_pgh("b", "a"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"a", Triplet::X86_WINDOWS}}, status_db);
REQUIRE(remove_plan.size() == 2);
REQUIRE(remove_plan.at(0).spec.name() == "b");
@@ -973,7 +968,7 @@ TEST_CASE ("features depend remove scheme", "[plan]")
pghs.push_back(make_status_feature_pgh("b", "0", "a"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"a", Triplet::X86_WINDOWS}}, status_db);
REQUIRE(remove_plan.size() == 2);
REQUIRE(remove_plan.at(0).spec.name() == "b");
@@ -989,7 +984,7 @@ TEST_CASE ("features depend remove scheme once removed", "[plan]")
pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("expat")}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"expat", Triplet::X86_WINDOWS}}, status_db);
REQUIRE(remove_plan.size() == 3);
REQUIRE(remove_plan.at(0).spec.name() == "opencv");
@@ -1006,8 +1001,7 @@ TEST_CASE ("features depend remove scheme once removed x64", "[plan]")
pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk", "x64"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan =
- Dependencies::create_remove_plan({unsafe_pspec("expat", Triplet::from_canonical_name("x64"))}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"expat", Triplet::from_canonical_name("x64")}}, status_db);
REQUIRE(remove_plan.size() == 3);
REQUIRE(remove_plan.at(0).spec.name() == "opencv");
@@ -1022,8 +1016,7 @@ TEST_CASE ("features depend core remove scheme", "[plan]")
pghs.push_back(make_status_pgh("cpr", "curl[core]", "", "x64"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan =
- Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"curl", Triplet::from_canonical_name("x64")}}, status_db);
REQUIRE(remove_plan.size() == 2);
REQUIRE(remove_plan.at(0).spec.name() == "cpr");
@@ -1038,8 +1031,7 @@ TEST_CASE ("features depend core remove scheme 2", "[plan]")
pghs.push_back(make_status_feature_pgh("curl", "b", "curl[a]", "x64"));
StatusParagraphs status_db(std::move(pghs));
- auto remove_plan =
- Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db);
+ auto remove_plan = Dependencies::create_remove_plan({{"curl", Triplet::from_canonical_name("x64")}}, status_db);
REQUIRE(remove_plan.size() == 1);
REQUIRE(remove_plan.at(0).spec.name() == "curl");
diff --git a/toolsrc/src/vcpkg-test/specifier.cpp b/toolsrc/src/vcpkg-test/specifier.cpp
index a0a3725e8..2a1398416 100644
--- a/toolsrc/src/vcpkg-test/specifier.cpp
+++ b/toolsrc/src/vcpkg-test/specifier.cpp
@@ -12,8 +12,8 @@ TEST_CASE ("specifier conversion", "[specifier]")
{
constexpr std::size_t SPEC_SIZE = 6;
- auto a_spec = PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
- auto b_spec = PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO);
+ PackageSpec a_spec("a", Triplet::X64_WINDOWS);
+ PackageSpec b_spec("b", Triplet::X64_WINDOWS);
auto fspecs = FullPackageSpec{a_spec, {"0", "1"}}.to_feature_specs({}, {});
auto fspecs2 = FullPackageSpec{b_spec, {"2", "3"}}.to_feature_specs({}, {});
@@ -36,67 +36,59 @@ TEST_CASE ("specifier parsing", "[specifier]")
{
SECTION ("parsed specifier from string")
{
- auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib");
- REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS);
+ auto maybe_spec = vcpkg::parse_qualified_specifier("zlib");
+ REQUIRE(maybe_spec.has_value());
auto& spec = *maybe_spec.get();
REQUIRE(spec.name == "zlib");
- REQUIRE(spec.features.size() == 0);
- REQUIRE(spec.triplet == "");
+ REQUIRE(!spec.features);
+ REQUIRE(!spec.triplet);
}
SECTION ("parsed specifier from string with triplet")
{
- auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib:x64-uwp");
- REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS);
+ auto maybe_spec = vcpkg::parse_qualified_specifier("zlib:x64-uwp");
+ REQUIRE(maybe_spec);
auto& spec = *maybe_spec.get();
REQUIRE(spec.name == "zlib");
- REQUIRE(spec.triplet == "x64-uwp");
+ REQUIRE(spec.triplet.value_or("") == "x64-uwp");
}
SECTION ("parsed specifier from string with colons")
{
- auto ec = vcpkg::ParsedSpecifier::from_string("zlib:x86-uwp:").error();
- REQUIRE(ec == vcpkg::PackageSpecParseResult::TOO_MANY_COLONS);
+ auto s = vcpkg::parse_qualified_specifier("zlib:x86-uwp:");
+ REQUIRE(!s);
}
SECTION ("parsed specifier from string with feature")
{
- auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[feature]:x64-uwp");
- REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS);
+ auto maybe_spec = vcpkg::parse_qualified_specifier("zlib[feature]:x64-uwp");
+ REQUIRE(maybe_spec);
auto& spec = *maybe_spec.get();
REQUIRE(spec.name == "zlib");
- REQUIRE(spec.features.size() == 1);
- REQUIRE(spec.features.at(0) == "feature");
- REQUIRE(spec.triplet == "x64-uwp");
+ REQUIRE(spec.features.value_or(std::vector<std::string>{}) == std::vector<std::string>{"feature"});
+ REQUIRE(spec.triplet.value_or("") == "x64-uwp");
}
SECTION ("parsed specifier from string with many features")
{
- auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[0, 1,2]");
- REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS);
+ auto maybe_spec = vcpkg::parse_qualified_specifier("zlib[0, 1,2]");
+ REQUIRE(maybe_spec);
auto& spec = *maybe_spec.get();
- REQUIRE(spec.name == "zlib");
- REQUIRE(spec.features.size() == 3);
- REQUIRE(spec.features.at(0) == "0");
- REQUIRE(spec.features.at(1) == "1");
- REQUIRE(spec.features.at(2) == "2");
- REQUIRE(spec.triplet == "");
+ REQUIRE(spec.features.value_or(std::vector<std::string>{}) == std::vector<std::string>{"0", "1", "2"});
}
SECTION ("parsed specifier wildcard feature")
{
- auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]");
- REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS);
+ auto maybe_spec = vcpkg::parse_qualified_specifier("zlib[*]");
+ System::print2(maybe_spec.error());
+ REQUIRE(maybe_spec);
auto& spec = *maybe_spec.get();
- REQUIRE(spec.name == "zlib");
- REQUIRE(spec.features.size() == 1);
- REQUIRE(spec.features.at(0) == "*");
- REQUIRE(spec.triplet == "");
+ REQUIRE(spec.features.value_or(std::vector<std::string>{}) == std::vector<std::string>{"*"});
}
SECTION ("expand wildcards")
@@ -109,17 +101,15 @@ TEST_CASE ("specifier parsing", "[specifier]")
Util::Vectors::append(&specs, specs2);
Util::sort(specs);
- auto spectargets = FeatureSpec::from_strings_and_triplet(
- {
- "openssl",
- "zlib",
- "zlib[0]",
- "zlib[1]",
- },
- Triplet::X86_UWP);
+ std::vector<FeatureSpec> spectargets{
+ {{"openssl", Triplet::X86_UWP}, "core"},
+ {{"zlib", Triplet::X86_UWP}, "core"},
+ {{"zlib", Triplet::X86_UWP}, "0"},
+ {{"zlib", Triplet::X86_UWP}, "1"},
+ };
Util::sort(spectargets);
REQUIRE(specs.size() == spectargets.size());
- REQUIRE(Util::all_equal(specs, spectargets));
+ REQUIRE(specs == spectargets);
}
#if defined(_WIN32)
diff --git a/toolsrc/src/vcpkg-test/statusparagraphs.cpp b/toolsrc/src/vcpkg-test/statusparagraphs.cpp
index 88b499118..c755948b5 100644
--- a/toolsrc/src/vcpkg-test/statusparagraphs.cpp
+++ b/toolsrc/src/vcpkg-test/statusparagraphs.cpp
@@ -18,14 +18,15 @@ Architecture: x64-windows
Multi-Arch: same
Description:
Status: install ok installed
-)");
+)",
+ "");
REQUIRE(pghs);
StatusParagraphs status_db(
Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique<StatusParagraph>(std::move(rpgh)); }));
- auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS));
+ auto it = status_db.find_installed({"ffmpeg", Triplet::X64_WINDOWS});
REQUIRE(it != status_db.end());
}
@@ -38,14 +39,15 @@ Architecture: x64-windows
Multi-Arch: same
Description:
Status: purge ok not-installed
-)");
+)",
+ "");
REQUIRE(pghs);
StatusParagraphs status_db(
Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique<StatusParagraph>(std::move(rpgh)); }));
- auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS));
+ auto it = status_db.find_installed({"ffmpeg", Triplet::X64_WINDOWS});
REQUIRE(it == status_db.end());
}
@@ -66,18 +68,19 @@ Architecture: x64-windows
Multi-Arch: same
Description:
Status: purge ok not-installed
-)");
+)",
+ "");
REQUIRE(pghs);
StatusParagraphs status_db(
Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique<StatusParagraph>(std::move(rpgh)); }));
- auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS));
+ auto it = status_db.find_installed({"ffmpeg", Triplet::X64_WINDOWS});
REQUIRE(it != status_db.end());
// Feature "openssl" is not installed and should not be found
- auto it1 = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"});
+ auto it1 = status_db.find_installed({{"ffmpeg", Triplet::X64_WINDOWS}, "openssl"});
REQUIRE(it1 == status_db.end());
}
@@ -98,13 +101,14 @@ Architecture: x64-windows
Multi-Arch: same
Description:
Status: install ok installed
-)");
+)",
+ "");
REQUIRE(pghs);
StatusParagraphs status_db(
Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique<StatusParagraph>(std::move(rpgh)); }));
// Feature "openssl" is installed and should therefore be found
- auto it = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"});
+ auto it = status_db.find_installed({{"ffmpeg", Triplet::X64_WINDOWS}, "openssl"});
REQUIRE(it != status_db.end());
}
diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp
index db310f7a0..ae02e3ab0 100644
--- a/toolsrc/src/vcpkg-test/util.cpp
+++ b/toolsrc/src/vcpkg-test/util.cpp
@@ -104,17 +104,8 @@ namespace vcpkg::Test
PackageSpec PackageSpecMap::emplace(vcpkg::SourceControlFileLocation&& scfl)
{
- auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet);
- REQUIRE(spec.has_value());
map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl));
- return PackageSpec{*spec.get()};
- }
-
- PackageSpec unsafe_pspec(std::string name, Triplet t)
- {
- auto m_ret = PackageSpec::from_name_and_triplet(name, t);
- REQUIRE(m_ret.has_value());
- return m_ret.value_or_exit(VCPKG_LINE_INFO);
+ return {scfl.source_control_file->core_paragraph->name, triplet};
}
static AllowSymlinks internal_can_create_symlinks() noexcept
diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp
index 3404a6a48..e97400150 100644
--- a/toolsrc/src/vcpkg/binaryparagraph.cpp
+++ b/toolsrc/src/vcpkg/binaryparagraph.cpp
@@ -5,7 +5,7 @@
#include <vcpkg/base/util.h>
#include <vcpkg/binaryparagraph.h>
-#include <vcpkg/parse.h>
+#include <vcpkg/paragraphparser.h>
namespace vcpkg
{
@@ -41,8 +41,7 @@ namespace vcpkg
parser.required_field(Fields::PACKAGE, name);
std::string architecture;
parser.required_field(Fields::ARCHITECTURE, architecture);
- this->spec = PackageSpec::from_name_and_triplet(name, Triplet::from_canonical_name(std::move(architecture)))
- .value_or_exit(VCPKG_LINE_INFO);
+ this->spec = PackageSpec(std::move(name), Triplet::from_canonical_name(std::move(architecture)));
}
// one or the other
@@ -57,10 +56,16 @@ namespace vcpkg
std::string multi_arch;
parser.required_field(Fields::MULTI_ARCH, multi_arch);
- this->depends = parse_comma_list(parser.optional_field(Fields::DEPENDS));
+ this->depends = Util::fmap(
+ parse_qualified_specifier_list(parser.optional_field(Fields::DEPENDS)).value_or_exit(VCPKG_LINE_INFO),
+ [](const ParsedQualifiedSpecifier& dep) {
+ // for compatibility with previous vcpkg versions, we discard all irrelevant information
+ return dep.name;
+ });
if (this->feature.empty())
{
- this->default_features = parse_comma_list(parser.optional_field(Fields::DEFAULTFEATURES));
+ this->default_features = parse_default_features_list(parser.optional_field(Fields::DEFAULTFEATURES))
+ .value_or_exit(VCPKG_LINE_INFO);
}
this->type = Type::from_string(parser.optional_field(Fields::TYPE));
@@ -77,7 +82,7 @@ namespace vcpkg
}
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh,
- const Triplet& triplet,
+ Triplet triplet,
const std::string& abi_tag,
const std::vector<FeatureSpec>& deps)
: version(spgh.version)
@@ -86,19 +91,19 @@ namespace vcpkg
, abi(abi_tag)
, type(spgh.type)
{
- this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
- this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.to_string(); });
+ this->spec = PackageSpec(spgh.name, triplet);
+ this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
Util::sort_unique_erase(this->depends);
}
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh,
const FeatureParagraph& fpgh,
- const Triplet& triplet,
+ Triplet triplet,
const std ::vector<FeatureSpec>& deps)
: version(), description(fpgh.description), maintainer(), feature(fpgh.name), type(spgh.type)
{
- this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
- this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.to_string(); });
+ this->spec = PackageSpec(spgh.name, triplet);
+ this->depends = Util::fmap(deps, [](const FeatureSpec& spec) { return spec.spec().name(); });
Util::sort_unique_erase(this->depends);
}
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp
index c65cf9b77..01a22ba90 100644
--- a/toolsrc/src/vcpkg/build.cpp
+++ b/toolsrc/src/vcpkg/build.cpp
@@ -143,7 +143,7 @@ namespace vcpkg::Build::Command
nullptr,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
// Build only takes a single package and all dependencies must already be installed
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
@@ -307,7 +307,7 @@ namespace vcpkg::Build
static std::unique_ptr<BinaryControlFile> create_binary_control_file(
const SourceParagraph& source_paragraph,
- const Triplet& triplet,
+ Triplet triplet,
const BuildInfo& build_info,
const std::string& abi_tag,
const std::vector<FeatureSpec>& core_dependencies)
@@ -353,7 +353,7 @@ namespace vcpkg::Build
static std::vector<System::CMakeVariable> get_cmake_vars(const VcpkgPaths& paths,
const BuildPackageConfig& config,
- const Triplet& triplet,
+ Triplet triplet,
const Toolset& toolset)
{
#if !defined(_WIN32)
@@ -422,7 +422,7 @@ namespace vcpkg::Build
static std::string make_build_cmd(const VcpkgPaths& paths,
const PreBuildInfo& pre_build_info,
const BuildPackageConfig& config,
- const Triplet& triplet)
+ Triplet triplet)
{
const Toolset& toolset = paths.get_toolset(pre_build_info);
const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
@@ -445,9 +445,7 @@ namespace vcpkg::Build
return command;
}
- static std::string get_triplet_abi(const VcpkgPaths& paths,
- const PreBuildInfo& pre_build_info,
- const Triplet& triplet)
+ static std::string get_triplet_abi(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, Triplet triplet)
{
static std::map<fs::path, std::string> s_hash_cache;
@@ -516,7 +514,7 @@ namespace vcpkg::Build
}
#endif
- const Triplet& triplet = spec.triplet();
+ Triplet triplet = spec.triplet();
const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string();
if (Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.community_triplets.u8string()))
@@ -644,7 +642,7 @@ namespace vcpkg::Build
Span<const AbiEntry> dependency_abis)
{
auto& fs = paths.get_filesystem();
- const Triplet& triplet = config.triplet;
+ Triplet triplet = config.triplet;
const std::string& name = config.scf.core_paragraph->name;
std::vector<AbiEntry> abi_tag_entries(dependency_abis.begin(), dependency_abis.end());
@@ -813,7 +811,7 @@ namespace vcpkg::Build
const StatusParagraphs& status_db)
{
auto& fs = paths.get_filesystem();
- const Triplet& triplet = config.triplet;
+ Triplet triplet = config.triplet;
const std::string& name = config.scf.core_paragraph->name;
std::vector<FeatureSpec> missing_fspecs;
@@ -833,7 +831,7 @@ namespace vcpkg::Build
return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(missing_fspecs)};
}
- const PackageSpec spec = PackageSpec::from_name_and_triplet(name, triplet).value_or_exit(VCPKG_LINE_INFO);
+ const PackageSpec spec(name, triplet);
std::vector<AbiEntry> dependency_abis;
for (auto&& pspec : config.package_dependencies)
@@ -1075,13 +1073,14 @@ namespace vcpkg::Build
BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath)
{
- const Expected<Parse::RawParagraph> pghs = Paragraphs::get_single_paragraph(fs, filepath);
- Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package");
+ const ExpectedS<Parse::RawParagraph> pghs = Paragraphs::get_single_paragraph(fs, filepath);
+ Checks::check_exit(
+ VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package: %s", pghs.error());
return inner_create_buildinfo(*pghs.get());
}
PreBuildInfo::PreBuildInfo(const VcpkgPaths& paths,
- const Triplet& triplet,
+ Triplet triplet,
const std::unordered_map<std::string, std::string>& cmakevars)
{
for (auto&& kv : VCPKG_OPTIONS)
diff --git a/toolsrc/src/vcpkg/cmakevars.cpp b/toolsrc/src/vcpkg/cmakevars.cpp
index 6059833e7..42bed5501 100644
--- a/toolsrc/src/vcpkg/cmakevars.cpp
+++ b/toolsrc/src/vcpkg/cmakevars.cpp
@@ -152,10 +152,11 @@ namespace vcpkg::CMakeVars
}
}
- void TripletCMakeVarProvider::load_generic_triplet_vars(const Triplet& triplet) const
+ void TripletCMakeVarProvider::load_generic_triplet_vars(Triplet triplet) const
{
std::vector<std::vector<std::pair<std::string, std::string>>> vars(1);
- FullPackageSpec full_spec = FullPackageSpec::from_string("", triplet).value_or_exit(VCPKG_LINE_INFO);
+ // Hack: PackageSpecs should never have .name==""
+ FullPackageSpec full_spec({"", triplet});
const fs::path file_path =
create_tag_extraction_file(std::array<std::pair<const FullPackageSpec*, std::string>, 1>{
std::pair<const FullPackageSpec*, std::string>{&full_spec, ""}});
@@ -222,7 +223,7 @@ namespace vcpkg::CMakeVars
}
Optional<const std::unordered_map<std::string, std::string>&> TripletCMakeVarProvider::get_generic_triplet_vars(
- const Triplet& triplet) const
+ Triplet triplet) const
{
auto find_itr = generic_triplet_vars.find(triplet);
if (find_itr != generic_triplet_vars.end())
diff --git a/toolsrc/src/vcpkg/commands.buildexternal.cpp b/toolsrc/src/vcpkg/commands.buildexternal.cpp
index 135ef132b..4a69be879 100644
--- a/toolsrc/src/vcpkg/commands.buildexternal.cpp
+++ b/toolsrc/src/vcpkg/commands.buildexternal.cpp
@@ -16,7 +16,7 @@ namespace vcpkg::Commands::BuildExternal
nullptr,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
diff --git a/toolsrc/src/vcpkg/commands.cache.cpp b/toolsrc/src/vcpkg/commands.cache.cpp
index 4c49db004..5fb9d15f4 100644
--- a/toolsrc/src/vcpkg/commands.cache.cpp
+++ b/toolsrc/src/vcpkg/commands.cache.cpp
@@ -14,8 +14,7 @@ namespace vcpkg::Commands::Cache
std::vector<BinaryParagraph> output;
for (auto&& path : paths.get_filesystem().get_files_non_recursive(paths.packages))
{
- const Expected<Parse::RawParagraph> pghs =
- Paragraphs::get_single_paragraph(paths.get_filesystem(), path / "CONTROL");
+ const auto pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), path / "CONTROL");
if (const auto p = pghs.get())
{
const BinaryParagraph binary_paragraph = BinaryParagraph(*p);
diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp
index b8ac97563..301400b8b 100644
--- a/toolsrc/src/vcpkg/commands.ci.cpp
+++ b/toolsrc/src/vcpkg/commands.ci.cpp
@@ -387,7 +387,7 @@ namespace vcpkg::Commands::CI
will_fail.emplace(p->spec);
}
else if (Util::any_of(p->package_dependencies,
- [&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); }))
+ [&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); }))
{
state = "cascade";
ret->known.emplace(p->spec, BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES);
@@ -426,7 +426,7 @@ namespace vcpkg::Commands::CI
return ret;
}
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
if (!GlobalState::g_binary_caching)
{
@@ -483,7 +483,7 @@ namespace vcpkg::Commands::CI
});
std::vector<TripletAndSummary> results;
auto timer = Chrono::ElapsedTimer::create_started();
- for (const Triplet& triplet : triplets)
+ for (Triplet triplet : triplets)
{
Input::check_triplet(triplet, paths);
diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp
index eecc45634..7023547da 100644
--- a/toolsrc/src/vcpkg/commands.dependinfo.cpp
+++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp
@@ -234,7 +234,7 @@ namespace vcpkg::Commands::DependInfo
nullptr,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
const int max_depth = get_max_depth(options);
diff --git a/toolsrc/src/vcpkg/commands.env.cpp b/toolsrc/src/vcpkg/commands.env.cpp
index c54f73e76..b05c1f653 100644
--- a/toolsrc/src/vcpkg/commands.env.cpp
+++ b/toolsrc/src/vcpkg/commands.env.cpp
@@ -33,7 +33,7 @@ namespace vcpkg::Commands::Env
};
// This command should probably optionally take a port
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet triplet)
{
const auto& fs = paths.get_filesystem();
diff --git a/toolsrc/src/vcpkg/commands.import.cpp b/toolsrc/src/vcpkg/commands.import.cpp
index c18d788c5..521892e88 100644
--- a/toolsrc/src/vcpkg/commands.import.cpp
+++ b/toolsrc/src/vcpkg/commands.import.cpp
@@ -108,12 +108,13 @@ namespace vcpkg::Commands::Import
const fs::path include_directory(args.command_arguments[1]);
const fs::path project_directory(args.command_arguments[2]);
- const Expected<Parse::RawParagraph> pghs =
- Paragraphs::get_single_paragraph(paths.get_filesystem(), control_file_path);
+ const auto pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), control_file_path);
Checks::check_exit(VCPKG_LINE_INFO,
pghs.get() != nullptr,
"Invalid control file %s for package",
- control_file_path.generic_u8string());
+ control_file_path.generic_u8string(),
+ "\n",
+ pghs.error());
StatusParagraph spgh;
spgh.package = BinaryParagraph(*pghs.get());
diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp
index e8afabed5..960e9bbb3 100644
--- a/toolsrc/src/vcpkg/commands.upgrade.cpp
+++ b/toolsrc/src/vcpkg/commands.upgrade.cpp
@@ -34,7 +34,7 @@ namespace vcpkg::Commands::Upgrade
nullptr,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp
index 5309501d9..beb92f4b0 100644
--- a/toolsrc/src/vcpkg/dependencies.cpp
+++ b/toolsrc/src/vcpkg/dependencies.cpp
@@ -115,7 +115,7 @@ namespace vcpkg::Dependencies
for (auto&& fspec : fullspec_list)
{
// TODO: this is incorrect and does not handle default features nor "*"
- Util::Vectors::append(&dep_list, fspec.to_feature_specs({"default"}, {}));
+ Util::Vectors::append(&dep_list, fspec.to_feature_specs({"default"}, {"default"}));
}
Util::sort_unique_erase(dep_list);
@@ -130,10 +130,8 @@ namespace vcpkg::Dependencies
{
Util::Vectors::append(
&dep_list,
- FullPackageSpec(PackageSpec::from_name_and_triplet(dep.depend.name, m_spec.triplet())
- .value_or_exit(VCPKG_LINE_INFO),
- dep.depend.features)
- .to_feature_specs({"default"}, {}));
+ FullPackageSpec({dep.depend.name, m_spec.triplet()}, dep.depend.features)
+ .to_feature_specs({"default"}, {"default"}));
}
else
{
@@ -261,14 +259,15 @@ namespace vcpkg::Dependencies
if (it == m_graph.end())
{
- Optional<const SourceControlFileLocation&> maybe_scfl =
+ ExpectedS<const SourceControlFileLocation&> maybe_scfl =
m_port_provider.get_control_file(ipv.spec().name());
if (!maybe_scfl)
Checks::exit_with_message(
VCPKG_LINE_INFO,
- "We could not find a CONTROL file for '%s'. Please run \"vcpkg remove %s\" and re-attempt.",
+ "Error: while loading %s: %s.\nPlease run \"vcpkg remove %s\" and re-attempt.",
ipv.spec().to_string(),
+ maybe_scfl.error(),
ipv.spec().to_string());
return m_graph
@@ -456,7 +455,7 @@ namespace vcpkg::Dependencies
return nullopt;
}
- std::vector<PackageSpec> ExportPlanAction::dependencies(const Triplet&) const
+ std::vector<PackageSpec> ExportPlanAction::dependencies(Triplet) const
{
if (auto p_ip = m_installed_package.get())
return p_ip->dependencies();
diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp
index 0094b712c..736ab6def 100644
--- a/toolsrc/src/vcpkg/export.cpp
+++ b/toolsrc/src/vcpkg/export.cpp
@@ -321,8 +321,7 @@ namespace vcpkg::Export
nullptr,
};
- static ExportArguments handle_export_command_arguments(const VcpkgCmdArguments& args,
- const Triplet& default_triplet)
+ static ExportArguments handle_export_command_arguments(const VcpkgCmdArguments& args, Triplet default_triplet)
{
ExportArguments ret;
@@ -513,7 +512,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
}
}
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
const auto opts = handle_export_command_arguments(args, default_triplet);
for (auto&& spec : opts.specs)
diff --git a/toolsrc/src/vcpkg/input.cpp b/toolsrc/src/vcpkg/input.cpp
index 42f81cbb9..0abe51823 100644
--- a/toolsrc/src/vcpkg/input.cpp
+++ b/toolsrc/src/vcpkg/input.cpp
@@ -10,7 +10,7 @@
namespace vcpkg
{
PackageSpec Input::check_and_get_package_spec(std::string&& spec_string,
- const Triplet& default_triplet,
+ Triplet default_triplet,
CStringView example_text)
{
const std::string as_lowercase = Strings::ascii_to_lowercase(std::move(spec_string));
@@ -21,12 +21,12 @@ namespace vcpkg
}
// Intentionally show the lowercased string
- System::print2(System::Color::error, "Error: ", expected_spec.error(), ": ", as_lowercase, '\n');
+ System::print2(System::Color::error, expected_spec.error());
System::print2(example_text);
Checks::exit_fail(VCPKG_LINE_INFO);
}
- void Input::check_triplet(const Triplet& t, const VcpkgPaths& paths)
+ void Input::check_triplet(Triplet t, const VcpkgPaths& paths)
{
if (!paths.is_valid_triplet(t))
{
@@ -38,7 +38,7 @@ namespace vcpkg
}
FullPackageSpec Input::check_and_get_full_package_spec(std::string&& full_package_spec_as_string,
- const Triplet& default_triplet,
+ Triplet default_triplet,
CStringView example_text)
{
const std::string as_lowercase = Strings::ascii_to_lowercase(std::move(full_package_spec_as_string));
@@ -49,7 +49,7 @@ namespace vcpkg
}
// Intentionally show the lowercased string
- System::print2(System::Color::error, "Error: ", expected_spec.error(), ": ", as_lowercase, '\n');
+ System::print2(System::Color::error, expected_spec.error());
System::print2(example_text);
Checks::exit_fail(VCPKG_LINE_INFO);
}
diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp
index 0af9a33a1..fc76aa765 100644
--- a/toolsrc/src/vcpkg/install.cpp
+++ b/toolsrc/src/vcpkg/install.cpp
@@ -146,7 +146,7 @@ namespace vcpkg::Install
static std::vector<file_pack> extract_files_in_triplet(
const std::vector<StatusParagraphAndAssociatedFiles>& pgh_and_files,
- const Triplet& triplet,
+ Triplet triplet,
const size_t remove_chars = 0)
{
std::vector<file_pack> output;
@@ -184,7 +184,7 @@ namespace vcpkg::Install
}
static SortedVector<file_pack> build_list_of_installed_files(
- const std::vector<StatusParagraphAndAssociatedFiles>& pgh_and_files, const Triplet& triplet)
+ const std::vector<StatusParagraphAndAssociatedFiles>& pgh_and_files, Triplet triplet)
{
const size_t installed_remove_char_count = triplet.canonical_name().size() + 1; // +1 for the slash
std::vector<file_pack> installed_files =
@@ -196,7 +196,7 @@ namespace vcpkg::Install
InstallResult install_package(const VcpkgPaths& paths, const BinaryControlFile& bcf, StatusParagraphs* status_db)
{
const fs::path package_dir = paths.package_dir(bcf.core_paragraph.spec);
- const Triplet& triplet = bcf.core_paragraph.spec.triplet();
+ Triplet triplet = bcf.core_paragraph.spec.triplet();
const std::vector<StatusParagraphAndAssociatedFiles> pgh_and_files = get_installed_files(paths, *status_db);
const SortedVector<std::string> package_files =
@@ -639,7 +639,7 @@ namespace vcpkg::Install
/// Run "install" command.
/// </summary>
///
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
// input sanitization
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
diff --git a/toolsrc/src/vcpkg/logicexpression.cpp b/toolsrc/src/vcpkg/logicexpression.cpp
index 2f646e80a..e91c57310 100644
--- a/toolsrc/src/vcpkg/logicexpression.cpp
+++ b/toolsrc/src/vcpkg/logicexpression.cpp
@@ -3,33 +3,14 @@
#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.print.h>
#include <vcpkg/logicexpression.h>
+#include <vcpkg/parse.h>
#include <string>
#include <vector>
namespace vcpkg
{
- struct ParseError
- {
- ParseError(int column, std::string line, std::string message) : column(column), line(line), message(message) {}
-
- const int column;
- const std::string line;
- const std::string message;
-
- std::string format_error() const
- {
- return Strings::concat("Error: ",
- message,
- "\n"
- " on expression: \"",
- line,
- "\"\n",
- " ",
- std::string(column, ' '),
- "^\n");
- }
- };
+ using vcpkg::Parse::ParseError;
enum class Identifier
{
@@ -64,15 +45,12 @@ namespace vcpkg
//
// | and & have equal precidence and cannot be used together at the same nesting level
// for example a|b&c is not allowd but (a|b)&c and a|(b&c) are allowed.
- class ExpressionParser
+ class ExpressionParser : public Parse::ParserBase
{
public:
- ExpressionParser(const std::string& str, const ExpressionContext& context)
- : raw_text(str)
- , evaluation_context(context)
- , current_iter(raw_text.begin())
- , current_char(get_current_char())
+ ExpressionParser(const std::string& str, const ExpressionContext& context) : evaluation_context(context)
{
+ this->init(str, "CONTROL");
{
auto override_vars = evaluation_context.cmake_context.find("VCPKG_DEP_INFO_OVERRIDE_VARS");
if (override_vars != evaluation_context.cmake_context.end())
@@ -98,81 +76,23 @@ namespace vcpkg
final_result = logic_expression();
- if (current_iter != raw_text.end())
+ if (!at_eof())
{
- add_error("Invalid logic expression");
+ add_error("invalid logic expression, unexpected character");
}
}
bool get_result() const { return final_result; }
- const ParseError* get_error() const { return err.get(); }
-
private:
- const std::string& raw_text;
-
const ExpressionContext& evaluation_context;
std::map<std::string, bool> context_override;
- std::string::const_iterator current_iter;
- char current_char;
-
bool final_result;
- std::unique_ptr<ParseError> err;
-
- char get_current_char() const { return (current_iter != raw_text.end() ? *current_iter : '\0'); }
-
- void add_error(std::string message, int column = -1)
- {
- // avoid castcading errors by only saving the first
- if (!err)
- {
- if (column < 0)
- {
- column = current_column();
- }
- err = std::make_unique<ParseError>(column, raw_text, message);
- }
-
- // Avoid error loops by skipping to the end
- skip_to_end();
- }
-
- int current_column() const { return static_cast<int>(current_iter - raw_text.begin()); }
-
- void skip_to_end()
+ static bool is_identifier_char(char ch)
{
- current_iter = raw_text.end();
- current_char = '\0';
- }
- char current() const { return current_char; }
- char next()
- {
- if (current_char != '\0')
- {
- current_iter++;
- current_char = get_current_char();
- }
- return current();
- }
- void skip_whitespace()
- {
- while (current_char == ' ' || current_char == '\t')
- {
- current_char = next();
- }
- }
- char next_skip_whitespace()
- {
- next();
- skip_whitespace();
- return current_char;
- }
-
- static bool is_alphanum(char ch)
- {
- return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '-');
+ return is_upper_alpha(ch) || is_lower_alpha(ch) || is_ascii_digit(ch) || ch == '-';
}
// Legacy evaluation only searches for substrings. Use this only for diagnostic purposes.
@@ -219,7 +139,7 @@ namespace vcpkg
// If an identifier is on the explicit override list, return the override value
// Otherwise fall back to the built in logic to evaluate
// All unrecognized identifiers are an error
- bool evaluate_identifier_cmake(const std::string name, int column)
+ bool evaluate_identifier_cmake(const std::string name, const SourceLoc& loc)
{
auto id = string2identifier(name);
@@ -229,7 +149,7 @@ namespace vcpkg
// Point out in the diagnostic that they should add to the override list because that is what
// most users should do, however it is also valid to update the built in identifiers to recognize
// the name.
- add_error("Unrecognized identifer name. Add to override list in triplet file.", column);
+ add_error("Unrecognized identifer name. Add to override list in triplet file.", loc);
break;
case Identifier::x64: return true_if_exists_and_equal("VCPKG_TARGET_ARCHITECTURE", "x64");
@@ -251,7 +171,7 @@ namespace vcpkg
return evaluation_context.legacy_context.find(name) != std::string::npos;
}
- bool evaluate_identifier(const std::string name, int column)
+ bool evaluate_identifier(const std::string name, const SourceLoc& loc)
{
if (!context_override.empty())
{
@@ -264,15 +184,14 @@ namespace vcpkg
}
bool legacy = evaluate_identifier_legacy(name);
- bool cmake = evaluate_identifier_cmake(name, column);
+ bool cmake = evaluate_identifier_cmake(name, loc);
if (legacy != cmake)
{
// Legacy evaluation only used the name of the triplet, now we use the actual
// cmake variables. This has the potential to break custom triplets.
// For now just print a message, this will need to change once we start introducing
// new variables that did not exist previously (such as host-*)
- System::print2(
- "Warning: Identifier logic evaluation does not match legacy evaluation:\n ", name, '\n');
+ System::print2("Warning: qualifier has changed meaning recently:\n ", name, '\n');
}
return cmake;
}
@@ -281,22 +200,16 @@ namespace vcpkg
// alpha-numeric string of characters
bool identifier_expression()
{
- auto curr = current();
- std::string name;
- auto starting_column = current_column();
-
- for (curr = current(); is_alphanum(curr); curr = next())
- {
- name += curr;
- }
+ auto start_loc = cur_loc();
+ std::string name = match_zero_or_more(is_identifier_char).to_string();
if (name.empty())
{
- add_error("Invalid logic expression, unexpected character");
+ add_error("unexpected character in logic expression");
return false;
}
- bool result = evaluate_identifier(name, starting_column);
+ bool result = evaluate_identifier(name, start_loc);
skip_whitespace();
return result;
}
@@ -306,9 +219,10 @@ namespace vcpkg
// primary-expression
bool not_expression()
{
- if (current() == '!')
+ if (cur() == '!')
{
- next_skip_whitespace();
+ next();
+ skip_whitespace();
return !primary_expression();
}
@@ -327,11 +241,11 @@ namespace vcpkg
skip_whitespace();
seed = operation(not_expression(), seed);
- } while (current() == oper);
+ } while (cur() == oper);
- if (current() == other)
+ if (cur() == other)
{
- add_error("Mixing & and | is not allowed, Use () to specify order of operations.");
+ add_error("mixing & and | is not allowed, use () to specify order of operations");
}
skip_whitespace();
@@ -348,7 +262,7 @@ namespace vcpkg
{
auto result = not_expression();
- switch (current())
+ switch (cur())
{
case '|':
{
@@ -367,16 +281,18 @@ namespace vcpkg
// identifier
bool primary_expression()
{
- if (current() == '(')
+ if (cur() == '(')
{
- next_skip_whitespace();
+ next();
+ skip_whitespace();
bool result = logic_expression();
- if (current() != ')')
+ if (cur() != ')')
{
add_error("missing closing )");
return result;
}
- next_skip_whitespace();
+ next();
+ skip_whitespace();
return result;
}
@@ -390,7 +306,7 @@ namespace vcpkg
if (auto err = parser.get_error())
{
- return err->format_error();
+ return err->format();
}
return parser.get_result();
diff --git a/toolsrc/src/vcpkg/packagespec.cpp b/toolsrc/src/vcpkg/packagespec.cpp
index ea25f57e1..702f7aad3 100644
--- a/toolsrc/src/vcpkg/packagespec.cpp
+++ b/toolsrc/src/vcpkg/packagespec.cpp
@@ -3,18 +3,11 @@
#include <vcpkg/base/checks.h>
#include <vcpkg/base/util.h>
#include <vcpkg/packagespec.h>
-#include <vcpkg/packagespecparseresult.h>
+#include <vcpkg/paragraphparser.h>
#include <vcpkg/parse.h>
-using vcpkg::Parse::parse_comma_list;
-
namespace vcpkg
{
- static bool is_valid_package_spec_char(char c)
- {
- return (c == '-') || isdigit(c) || (isalpha(c) && islower(c)) || (c == '[') || (c == ']');
- }
-
std::string FeatureSpec::to_string() const
{
std::string ret;
@@ -27,38 +20,6 @@ namespace vcpkg
Strings::append(out, name(), '[', feature(), "]:", triplet());
}
- std::vector<FeatureSpec> FeatureSpec::from_strings_and_triplet(const std::vector<std::string>& depends,
- const Triplet& triplet)
- {
- std::vector<FeatureSpec> f_specs;
- for (auto&& depend : depends)
- {
- auto maybe_spec = ParsedSpecifier::from_string(depend);
- if (auto spec = maybe_spec.get())
- {
- Checks::check_exit(VCPKG_LINE_INFO,
- spec->triplet.empty(),
- "error: triplets cannot currently be specified in this context: %s",
- depend);
- PackageSpec pspec =
- PackageSpec::from_name_and_triplet(spec->name, triplet).value_or_exit(VCPKG_LINE_INFO);
-
- for (auto&& feature : spec->features)
- f_specs.push_back(FeatureSpec{pspec, feature});
-
- if (spec->features.empty()) f_specs.push_back(FeatureSpec{pspec, "core"});
- }
- else
- {
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "error while parsing feature list: %s: %s",
- vcpkg::to_string(maybe_spec.error()),
- depend);
- }
- }
- return f_specs;
- }
-
std::vector<FeatureSpec> FullPackageSpec::to_feature_specs(const std::vector<std::string>& default_features,
const std::vector<std::string>& all_features) const
{
@@ -99,57 +60,26 @@ namespace vcpkg
return feature_specs;
}
- ExpectedT<FullPackageSpec, PackageSpecParseResult> FullPackageSpec::from_string(const std::string& spec_as_string,
- const Triplet& default_triplet)
- {
- auto res = ParsedSpecifier::from_string(spec_as_string);
- if (auto p = res.get())
- {
- FullPackageSpec fspec;
- Triplet t = p->triplet.empty() ? default_triplet : Triplet::from_canonical_name(std::move(p->triplet));
- fspec.package_spec = PackageSpec::from_name_and_triplet(p->name, t).value_or_exit(VCPKG_LINE_INFO);
- fspec.features = std::move(p->features);
- return fspec;
- }
- return res.error();
- }
-
- ExpectedT<PackageSpec, PackageSpecParseResult> PackageSpec::from_name_and_triplet(const std::string& name,
- const Triplet& triplet)
+ ExpectedS<FullPackageSpec> FullPackageSpec::from_string(const std::string& spec_as_string, Triplet default_triplet)
{
- if (Util::find_if_not(name, is_valid_package_spec_char) != name.end())
- {
- return PackageSpecParseResult::INVALID_CHARACTERS;
- }
-
- PackageSpec p;
- p.m_name = name;
- p.m_triplet = triplet;
- return p;
+ return parse_qualified_specifier(spec_as_string)
+ .then([&](ParsedQualifiedSpecifier&& p) -> ExpectedS<FullPackageSpec> {
+ if (p.qualifier) return "Error: qualifier not allowed in this context: " + spec_as_string + "\n";
+ auto triplet = p.triplet ? Triplet::from_canonical_name(std::move(*p.triplet.get())) : default_triplet;
+ return FullPackageSpec({p.name, triplet}, p.features.value_or({}));
+ });
}
- std::vector<PackageSpec> PackageSpec::to_package_specs(const std::vector<std::string>& ports,
- const Triplet& triplet)
+ std::vector<PackageSpec> PackageSpec::to_package_specs(const std::vector<std::string>& ports, Triplet triplet)
{
return Util::fmap(ports, [&](const std::string& spec_as_string) -> PackageSpec {
- auto maybe_spec = PackageSpec::from_name_and_triplet(spec_as_string, triplet);
- if (auto spec = maybe_spec.get())
- {
- return std::move(*spec);
- }
-
- const PackageSpecParseResult error_type = maybe_spec.error();
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Invalid package: %s\n"
- "%s",
- spec_as_string,
- vcpkg::to_string(error_type));
+ return {spec_as_string, triplet};
});
}
const std::string& PackageSpec::name() const { return this->m_name; }
- const Triplet& PackageSpec::triplet() const { return this->m_triplet; }
+ Triplet PackageSpec::triplet() const { return this->m_triplet; }
std::string PackageSpec::dir() const { return Strings::format("%s_%s", this->m_name, this->m_triplet); }
@@ -163,69 +93,155 @@ namespace vcpkg
bool operator!=(const PackageSpec& left, const PackageSpec& right) { return !(left == right); }
- ExpectedT<ParsedSpecifier, PackageSpecParseResult> ParsedSpecifier::from_string(const std::string& input)
+ ExpectedS<Features> Features::from_string(const std::string& name)
+ {
+ return parse_qualified_specifier(name).then([&](ParsedQualifiedSpecifier&& pqs) -> ExpectedS<Features> {
+ if (pqs.triplet) return "Error: triplet not allowed in this context: " + name + "\n";
+ if (pqs.qualifier) return "Error: qualifier not allowed in this context: " + name + "\n";
+ return Features{pqs.name, pqs.features.value_or({})};
+ });
+ }
+
+ static bool is_package_name_char(char ch)
{
- auto pos = input.find(':');
- auto pos_l_bracket = input.find('[');
- auto pos_r_bracket = input.find(']');
+ return Parse::ParserBase::is_lower_alpha(ch) || Parse::ParserBase::is_ascii_digit(ch) || ch == '-';
+ }
+
+ static bool is_feature_name_char(char ch) {
+ // TODO: we do not intend underscores to be valid, however there is currently a feature using them (libwebp[vwebp_sdl]).
+ // TODO: we need to rename this feature, then remove underscores from this list.
+ return is_package_name_char(ch) || ch == '_';
+ }
+
+ ExpectedS<ParsedQualifiedSpecifier> parse_qualified_specifier(CStringView input)
+ {
+ Parse::ParserBase parser;
+ parser.init(input, "<unknown>");
+ auto maybe_pqs = parse_qualified_specifier(parser);
+ if (!parser.at_eof()) parser.add_error("expected eof");
+ if (auto e = parser.get_error()) return e->format();
+ return std::move(maybe_pqs).value_or_exit(VCPKG_LINE_INFO);
+ }
- ParsedSpecifier f;
- if (pos == std::string::npos && pos_l_bracket == std::string::npos)
+ Optional<std::string> parse_feature_name(Parse::ParserBase& parser)
+ {
+ using Parse::ParserBase;
+ auto ret = parser.match_zero_or_more(is_feature_name_char).to_string();
+ auto ch = parser.cur();
+ if (ParserBase::is_upper_alpha(ch) || ch == '_')
{
- f.name = input;
- return f;
+ parser.add_error("invalid character in feature name (must be lowercase, digits, '-')");
+ return nullopt;
}
- else if (pos == std::string::npos)
+ if (ret.empty())
{
- if (pos_r_bracket == std::string::npos || pos_l_bracket >= pos_r_bracket)
- {
- return PackageSpecParseResult::INVALID_CHARACTERS;
- }
- const std::string name = input.substr(0, pos_l_bracket);
- f.name = name;
- f.features = parse_comma_list(input.substr(pos_l_bracket + 1, pos_r_bracket - pos_l_bracket - 1));
- return f;
+ parser.add_error("expected feature name (must be lowercase, digits, '-')");
+ return nullopt;
}
- else if (pos_l_bracket == std::string::npos && pos_r_bracket == std::string::npos)
+ return ret;
+ }
+ Optional<std::string> parse_package_name(Parse::ParserBase& parser)
+ {
+ using Parse::ParserBase;
+ auto ret = parser.match_zero_or_more(is_package_name_char).to_string();
+ auto ch = parser.cur();
+ if (ParserBase::is_upper_alpha(ch) || ch == '_')
+ {
+ parser.add_error("invalid character in package name (must be lowercase, digits, '-')");
+ return nullopt;
+ }
+ if (ret.empty())
{
- const std::string name = input.substr(0, pos);
- f.triplet = input.substr(pos + 1);
- f.name = name;
+ parser.add_error("expected package name (must be lowercase, digits, '-')");
+ return nullopt;
}
+ return ret;
+ }
+
+ Optional<ParsedQualifiedSpecifier> parse_qualified_specifier(Parse::ParserBase& parser)
+ {
+ using Parse::ParserBase;
+ ParsedQualifiedSpecifier ret;
+ auto name = parse_package_name(parser);
+ if (auto n = name.get())
+ ret.name = std::move(*n);
else
+ return nullopt;
+ auto ch = parser.cur();
+ if (ch == '[')
{
- if (pos_r_bracket == std::string::npos || pos_l_bracket >= pos_r_bracket)
+ std::vector<std::string> features;
+ do
{
- return PackageSpecParseResult::INVALID_CHARACTERS;
- }
- const std::string name = input.substr(0, pos_l_bracket);
- f.features = parse_comma_list(input.substr(pos_l_bracket + 1, pos_r_bracket - pos_l_bracket - 1));
- f.triplet = input.substr(pos + 1);
- f.name = name;
+ parser.next();
+ parser.skip_tabs_spaces();
+ if (parser.cur() == '*')
+ {
+ features.push_back("*");
+ parser.next();
+ }
+ else
+ {
+ auto feature = parse_feature_name(parser);
+ if (auto f = feature.get())
+ features.push_back(std::move(*f));
+ else
+ return nullopt;
+ }
+ auto skipped_space = parser.skip_tabs_spaces();
+ ch = parser.cur();
+ if (ch == ']')
+ {
+ ch = parser.next();
+ break;
+ }
+ else if (ch == ',')
+ {
+ continue;
+ }
+ else
+ {
+ if (skipped_space.size() > 0 || Parse::ParserBase::is_lineend(parser.cur()))
+ parser.add_error("expected ',' or ']' in feature list");
+ else
+ parser.add_error("invalid character in feature name (must be lowercase, digits, '-', or '*')");
+ return nullopt;
+ }
+ } while (true);
+ ret.features = std::move(features);
}
-
- auto pos2 = input.find(':', pos + 1);
- if (pos2 != std::string::npos)
+ if (ch == ':')
{
- return PackageSpecParseResult::TOO_MANY_COLONS;
+ parser.next();
+ ret.triplet = parser.match_zero_or_more(is_package_name_char).to_string();
+ if (ret.triplet.get()->empty())
+ {
+ parser.add_error("expected triplet name (must be lowercase, digits, '-')");
+ return nullopt;
+ }
}
- return f;
- }
-
- ExpectedT<Features, PackageSpecParseResult> Features::from_string(const std::string& name)
- {
- auto maybe_spec = ParsedSpecifier::from_string(name);
- if (auto spec = maybe_spec.get())
+ parser.skip_tabs_spaces();
+ ch = parser.cur();
+ if (ch == '(')
{
- Checks::check_exit(
- VCPKG_LINE_INFO, spec->triplet.empty(), "error: triplet not allowed in specifier: %s", name);
-
- Features f;
- f.name = spec->name;
- f.features = spec->features;
- return f;
+ auto loc = parser.cur_loc();
+ int depth = 1;
+ while (depth > 0 && (ch = parser.next()) != 0)
+ {
+ if (ch == '(') ++depth;
+ if (ch == ')') --depth;
+ }
+ if (depth > 0)
+ {
+ parser.add_error("unmatched open braces in qualifier", loc);
+ return nullopt;
+ }
+ ret.qualifier = StringView(loc.it + 1, parser.it()).to_string();
+ parser.next();
}
-
- return maybe_spec.error();
+ // This makes the behavior of the parser more consistent -- otherwise, it will skip tabs and spaces only if
+ // there isn't a qualifier.
+ parser.skip_tabs_spaces();
+ return ret;
}
}
diff --git a/toolsrc/src/vcpkg/packagespecparseresult.cpp b/toolsrc/src/vcpkg/packagespecparseresult.cpp
deleted file mode 100644
index ef078ea28..000000000
--- a/toolsrc/src/vcpkg/packagespecparseresult.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "pch.h"
-
-#include <vcpkg/packagespecparseresult.h>
-
-#include <vcpkg/base/checks.h>
-
-namespace vcpkg
-{
- CStringView to_string(PackageSpecParseResult ev) noexcept
- {
- switch (ev)
- {
- case PackageSpecParseResult::SUCCESS: return "OK";
- case PackageSpecParseResult::TOO_MANY_COLONS: return "Too many colons";
- case PackageSpecParseResult::INVALID_CHARACTERS:
- return "Contains invalid characters. Only alphanumeric lowercase ASCII characters and dashes are "
- "allowed";
- default: Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
-
- void to_string(std::string& out, PackageSpecParseResult p) { out.append(vcpkg::to_string(p).c_str()); }
-}
diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp
index 797d681cd..8f1b72172 100644
--- a/toolsrc/src/vcpkg/paragraphs.cpp
+++ b/toolsrc/src/vcpkg/paragraphs.cpp
@@ -4,209 +4,136 @@
#include <vcpkg/base/system.debug.h>
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/util.h>
+#include <vcpkg/binaryparagraph.h>
#include <vcpkg/paragraphparseresult.h>
#include <vcpkg/paragraphs.h>
+#include <vcpkg/parse.h>
using namespace vcpkg::Parse;
+using namespace vcpkg;
namespace vcpkg::Paragraphs
{
- struct Parser
+ struct PghParser : private Parse::ParserBase
{
- 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_comment(char& ch)
- {
- while (ch != '\r' && ch != '\n' && ch != '\0')
- next(ch);
- if (ch == '\r') next(ch);
- if (ch == '\n') next(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_comment(char ch) { return (ch == '#'); }
-
- static bool is_lineend(char ch) { return ch == '\r' || ch == '\n' || ch == 0; }
-
- void get_fieldvalue(char& ch, std::string& fieldvalue)
+ void get_fieldvalue(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) || is_comment(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;
- }
+ Strings::append(fieldvalue, match_until(is_lineend));
+ skip_newline();
- // 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');
+ if (cur() != ' ') return;
+ auto spacing = skip_tabs_spaces();
+ if (is_lineend(cur())) return add_error("unexpected end of line, to span a blank line use \" .\"");
+ Strings::append(fieldvalue, "\n", spacing);
} while (true);
}
- void get_fieldname(char& ch, std::string& fieldname)
+ void get_fieldname(std::string& fieldname)
{
- auto begin_fieldname = cur;
- while (is_alphanum(ch) || ch == '-')
- next(ch);
- Checks::check_exit(VCPKG_LINE_INFO, ch == ':', "Expected ':'");
- fieldname = std::string(begin_fieldname, cur);
-
- // skip ': '
- next(ch);
- skip_spaces(ch);
+ fieldname = match_zero_or_more(is_alphanumdash).to_string();
+ if (fieldname.empty()) return add_error("expected fieldname");
}
- void get_paragraph(char& ch, RawParagraph& fields)
+ void get_paragraph(RawParagraph& fields)
{
fields.clear();
std::string fieldname;
std::string fieldvalue;
do
{
- if (is_comment(ch))
+ if (cur() == '#')
{
- skip_comment(ch);
+ skip_line();
continue;
}
- get_fieldname(ch, fieldname);
-
- auto it = fields.find(fieldname);
- Checks::check_exit(VCPKG_LINE_INFO, it == fields.end(), "Duplicate field");
+ auto loc = cur_loc();
+ get_fieldname(fieldname);
+ if (cur() != ':') return add_error("expected ':' after field name");
+ if (Util::Sets::contains(fields, fieldname)) return add_error("duplicate field", loc);
+ next();
+ skip_tabs_spaces();
- get_fieldvalue(ch, fieldvalue);
+ get_fieldvalue(fieldvalue);
fields.emplace(fieldname, fieldvalue);
- } while (!is_lineend(ch));
+ } while (!is_lineend(cur()));
}
public:
- std::vector<RawParagraph> get_paragraphs()
+ ExpectedS<std::vector<RawParagraph>> get_paragraphs(CStringView text, CStringView origin)
{
std::vector<RawParagraph> paragraphs;
- char ch;
- peek(ch);
+ init(text, origin);
- while (ch != 0)
+ skip_whitespace();
+ while (!at_eof())
{
- if (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t')
- {
- next(ch);
- continue;
- }
-
paragraphs.emplace_back();
- get_paragraph(ch, paragraphs.back());
+ get_paragraph(paragraphs.back());
+ match_zero_or_more(is_lineend);
}
+ if (get_error()) return get_error()->format();
return paragraphs;
}
};
- static Expected<RawParagraph> parse_single_paragraph(const std::string& str)
+ static ExpectedS<RawParagraph> parse_single_paragraph(const std::string& str, const std::string& origin)
{
- const std::vector<RawParagraph> p = Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs();
+ PghParser parser;
+ auto pghs = parser.get_paragraphs(str, origin);
- if (p.size() == 1)
+ if (auto p = pghs.get())
{
- return p.at(0);
+ if (p->size() != 1) return std::error_code(ParagraphParseResult::EXPECTED_ONE_PARAGRAPH).message();
+ return std::move(p->front());
+ }
+ else
+ {
+ return pghs.error();
}
-
- return std::error_code(ParagraphParseResult::EXPECTED_ONE_PARAGRAPH);
}
- Expected<RawParagraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path)
+ ExpectedS<RawParagraph> get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path)
{
const Expected<std::string> contents = fs.read_contents(control_path);
if (auto spgh = contents.get())
{
- return parse_single_paragraph(*spgh);
+ return parse_single_paragraph(*spgh, control_path.u8string());
}
- return contents.error();
+ return contents.error().message();
}
- Expected<std::vector<RawParagraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path)
+ ExpectedS<std::vector<RawParagraph>> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path)
{
const Expected<std::string> contents = fs.read_contents(control_path);
if (auto spgh = contents.get())
{
- return parse_paragraphs(*spgh);
+ return parse_paragraphs(*spgh, control_path.u8string());
}
- return contents.error();
+ return contents.error().message();
}
- Expected<std::vector<RawParagraph>> parse_paragraphs(const std::string& str)
+ ExpectedS<std::vector<RawParagraph>> parse_paragraphs(const std::string& str, const std::string& origin)
{
- return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs();
+ PghParser parser;
+ return parser.get_paragraphs(str, origin);
}
ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& path)
{
const auto path_to_control = path / "CONTROL";
- Expected<std::vector<RawParagraph>> pghs = get_paragraphs(fs, path_to_control);
+ ExpectedS<std::vector<RawParagraph>> pghs = get_paragraphs(fs, path_to_control);
if (auto vector_pghs = pghs.get())
{
return SourceControlFile::parse_control_file(path_to_control, std::move(*vector_pghs));
@@ -217,9 +144,9 @@ namespace vcpkg::Paragraphs
return error_info;
}
- Expected<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec)
+ ExpectedS<BinaryControlFile> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec)
{
- Expected<std::vector<RawParagraph>> pghs =
+ ExpectedS<std::vector<RawParagraph>> pghs =
get_paragraphs(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL");
if (auto p = pghs.get())
diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp
index 6015d9927..0bc748794 100644
--- a/toolsrc/src/vcpkg/parse.cpp
+++ b/toolsrc/src/vcpkg/parse.cpp
@@ -1,12 +1,60 @@
#include "pch.h"
-#include <vcpkg/parse.h>
-
+#include <utility>
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/util.h>
+#include <vcpkg/packagespec.h>
+#include <vcpkg/paragraphparser.h>
+#include <vcpkg/parse.h>
+
+using namespace vcpkg;
namespace vcpkg::Parse
{
+ std::string ParseError::format() const
+ {
+ return Strings::concat("Error: ",
+ origin,
+ ":",
+ row,
+ ":",
+ column,
+ ": ",
+ message,
+ "\n"
+ " on expression: \"",
+ line,
+ "\"\n",
+ " ",
+ std::string(column - 1, ' '),
+ "^\n");
+ }
+
+ void ParserBase::add_error(std::string message, const ParserBase::SourceLoc& loc)
+ {
+ // avoid cascading errors by only saving the first
+ if (!m_err)
+ {
+ // find beginning of line
+ auto linestart = loc.it;
+ while (linestart != m_text.c_str())
+ {
+ if (linestart[-1] == '\n') break;
+ --linestart;
+ }
+
+ // find end of line
+ auto lineend = loc.it;
+ while (*lineend != '\n' && *lineend != '\r' && *lineend != '\0')
+ ++lineend;
+ m_err.reset(
+ new ParseError(m_origin.c_str(), loc.row, loc.column, {linestart, lineend}, std::move(message)));
+ }
+
+ // Avoid error loops by skipping to the end
+ skip_to_eof();
+ }
+
static Optional<std::string> remove_field(RawParagraph* fields, const std::string& fieldname)
{
auto it = fields->find(fieldname);
@@ -45,105 +93,65 @@ namespace vcpkg::Parse
return nullptr;
}
- static bool is_whitespace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; }
-
- std::vector<std::string> parse_comma_list(const std::string& str)
+ template<class T, class F>
+ static Optional<std::vector<T>> parse_list_until_eof(StringLiteral plural_item_name, Parse::ParserBase& parser, F f)
{
- if (str.empty())
- {
- return {};
- }
-
- std::vector<std::string> out;
-
- auto iter = str.cbegin();
-
+ std::vector<T> ret;
+ parser.skip_whitespace();
+ if (parser.at_eof()) return std::vector<T>{};
do
{
- // Trim leading whitespace of each element
- while (iter != str.cend() && is_whitespace(*iter))
- {
- ++iter;
- }
-
- // Allow commas inside of [].
- bool bracket_nesting = false;
-
- auto element_begin = iter;
- auto element_end = iter;
- while (iter != str.cend() && (*iter != ',' || bracket_nesting))
- {
- char value = *iter;
-
- // do not support nested []
- if (value == '[')
- {
- if (bracket_nesting)
- {
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Lists do not support nested brackets, Did you forget a ']'?\n"
- "> '%s'\n"
- "> %s^\n",
- str,
- std::string(static_cast<int>(iter - str.cbegin()), ' '));
- }
- bracket_nesting = true;
- }
- else if (value == ']')
- {
- if (!bracket_nesting)
- {
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Found unmatched ']'. Did you forget a '['?\n"
- "> '%s'\n"
- "> %s^\n",
- str,
- std::string(static_cast<int>(iter - str.cbegin()), ' '));
- }
- bracket_nesting = false;
- }
-
- ++iter;
-
- // Trim ending whitespace
- if (!is_whitespace(value))
- {
- // Update element_end after iter is incremented so it will be one past.
- element_end = iter;
- }
- }
-
- if (element_begin == element_end)
+ auto item = f(parser);
+ if (!item) return nullopt;
+ ret.push_back(std::move(item).value_or_exit(VCPKG_LINE_INFO));
+ parser.skip_whitespace();
+ if (parser.at_eof()) return {std::move(ret)};
+ if (parser.cur() != ',')
{
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Empty element in list\n"
- "> '%s'\n"
- "> %s^\n",
- str,
- std::string(static_cast<int>(element_begin - str.cbegin()), ' '));
+ parser.add_error(Strings::concat("expected ',' or end of text in ", plural_item_name, " list"));
+ return nullopt;
}
- out.push_back({element_begin, element_end});
-
- if (iter != str.cend())
- {
- Checks::check_exit(VCPKG_LINE_INFO, *iter == ',', "Internal parsing error - expected comma");
+ parser.next();
+ parser.skip_whitespace();
+ } while (true);
+ }
- // Not at the end, must be at a comma that needs to be stepped over
- ++iter;
+ ExpectedS<std::vector<std::string>> parse_default_features_list(const std::string& str, CStringView origin)
+ {
+ Parse::ParserBase parser;
+ parser.init(str, origin);
+ auto opt = parse_list_until_eof<std::string>("default features", parser, &parse_feature_name);
+ if (!opt) return {parser.get_error()->format(), expected_right_tag};
+ return {std::move(opt).value_or_exit(VCPKG_LINE_INFO), expected_left_tag};
+ }
+ ExpectedS<std::vector<ParsedQualifiedSpecifier>> parse_qualified_specifier_list(const std::string& str,
+ CStringView origin)
+ {
+ Parse::ParserBase parser;
+ parser.init(str, origin);
+ auto opt = parse_list_until_eof<ParsedQualifiedSpecifier>(
+ "dependencies", parser, [](ParserBase& parser) { return parse_qualified_specifier(parser); });
+ if (!opt) return {parser.get_error()->format(), expected_right_tag};
- if (iter == str.end())
+ return {std::move(opt).value_or_exit(VCPKG_LINE_INFO), expected_left_tag};
+ }
+ ExpectedS<std::vector<Dependency>> parse_dependencies_list(const std::string& str, CStringView origin)
+ {
+ Parse::ParserBase parser;
+ parser.init(str, origin);
+ auto opt = parse_list_until_eof<Dependency>("dependencies", parser, [](ParserBase& parser) {
+ auto loc = parser.cur_loc();
+ return parse_qualified_specifier(parser).then([&](ParsedQualifiedSpecifier&& pqs) -> Optional<Dependency> {
+ if (pqs.triplet)
{
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Empty element in list\n"
- "> '%s'\n"
- "> %s^\n",
- str,
- std::string(str.length(), ' '));
+ parser.add_error("triplet specifier not allowed in this context", loc);
+ return nullopt;
}
- }
-
- } while (iter != str.cend());
+ return Dependency{{pqs.name, pqs.features.value_or({})}, pqs.qualifier.value_or({})};
+ });
+ });
+ if (!opt) return {parser.get_error()->format(), expected_right_tag};
- return out;
+ return {std::move(opt).value_or_exit(VCPKG_LINE_INFO), expected_left_tag};
}
}
diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp
index 04ab918df..e43fa862a 100644
--- a/toolsrc/src/vcpkg/portfileprovider.cpp
+++ b/toolsrc/src/vcpkg/portfileprovider.cpp
@@ -11,10 +11,10 @@ namespace vcpkg::PortFileProvider
{
}
- Optional<const SourceControlFileLocation&> MapPortFileProvider::get_control_file(const std::string& spec) const
+ ExpectedS<const SourceControlFileLocation&> MapPortFileProvider::get_control_file(const std::string& spec) const
{
auto scf = ports.find(spec);
- if (scf == ports.end()) return nullopt;
+ if (scf == ports.end()) return std::string("does not exist in map");
return scf->second;
}
@@ -53,7 +53,7 @@ namespace vcpkg::PortFileProvider
ports_dirs.emplace_back(paths.ports);
}
- Optional<const SourceControlFileLocation&> PathsPortFileProvider::get_control_file(const std::string& spec) const
+ ExpectedS<const SourceControlFileLocation&> PathsPortFileProvider::get_control_file(const std::string& spec) const
{
auto cache_it = cache.find(spec);
if (cache_it != cache.end())
@@ -84,8 +84,7 @@ namespace vcpkg::PortFileProvider
VCPKG_LINE_INFO, "Error: Failed to load port from %s", spec, ports_dir.u8string());
}
}
-
- if (filesystem.exists(ports_dir / spec / "CONTROL"))
+ else if (filesystem.exists(ports_dir / spec / "CONTROL"))
{
auto found_scf = Paragraphs::try_load_port(filesystem, ports_dir / spec);
if (auto scf = found_scf.get())
@@ -112,7 +111,7 @@ namespace vcpkg::PortFileProvider
}
}
- return nullopt;
+ return std::string("Port definition not found");
}
std::vector<const SourceControlFileLocation*> PathsPortFileProvider::load_all_control_files() const
diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp
index 1bcfe58a0..e1a03b808 100644
--- a/toolsrc/src/vcpkg/remove.cpp
+++ b/toolsrc/src/vcpkg/remove.cpp
@@ -214,7 +214,7 @@ namespace vcpkg::Remove
&valid_arguments,
};
- void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
+ void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet)
{
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp
index 26681e107..e4d9ffc63 100644
--- a/toolsrc/src/vcpkg/sourceparagraph.cpp
+++ b/toolsrc/src/vcpkg/sourceparagraph.cpp
@@ -52,14 +52,10 @@ namespace vcpkg
for (auto&& error_info : error_info_list)
{
Checks::check_exit(VCPKG_LINE_INFO, error_info != nullptr);
- if (error_info->error)
+ if (!error_info->error.empty())
{
- System::print2(System::Color::error,
- "Error: while loading ",
- error_info->name,
- ": ",
- error_info->error.message(),
- '\n');
+ System::print2(
+ System::Color::error, "Error: while loading ", error_info->name, ":\n", error_info->error, '\n');
}
}
@@ -131,9 +127,11 @@ namespace vcpkg
spgh->description = parser.optional_field(SourceParagraphFields::DESCRIPTION);
spgh->maintainer = parser.optional_field(SourceParagraphFields::MAINTAINER);
spgh->homepage = parser.optional_field(SourceParagraphFields::HOMEPAGE);
- spgh->depends = expand_qualified_dependencies(
- parse_comma_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS)));
- spgh->default_features = parse_comma_list(parser.optional_field(SourceParagraphFields::DEFAULTFEATURES));
+ spgh->depends = parse_dependencies_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS))
+ .value_or_exit(VCPKG_LINE_INFO);
+ spgh->default_features =
+ parse_default_features_list(parser.optional_field(SourceParagraphFields::DEFAULTFEATURES))
+ .value_or_exit(VCPKG_LINE_INFO);
spgh->supports_expression = parser.optional_field(SourceParagraphFields::SUPPORTS);
spgh->type = Type::from_string(parser.optional_field(SourceParagraphFields::TYPE));
auto err = parser.error_info(spgh->name.empty() ? path_to_control.u8string() : spgh->name);
@@ -153,8 +151,8 @@ namespace vcpkg
parser.required_field(SourceParagraphFields::FEATURE, fpgh->name);
parser.required_field(SourceParagraphFields::DESCRIPTION, fpgh->description);
- fpgh->depends = expand_qualified_dependencies(
- parse_comma_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS)));
+ fpgh->depends = parse_dependencies_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS))
+ .value_or_exit(VCPKG_LINE_INFO);
auto err = parser.error_info(fpgh->name.empty() ? path_to_control.u8string() : fpgh->name);
if (err)
@@ -217,69 +215,8 @@ namespace vcpkg
return nullopt;
}
- Dependency Dependency::parse_dependency(std::string name, std::string qualifier)
- {
- Dependency dep;
- dep.qualifier = qualifier;
- if (auto maybe_features = Features::from_string(name))
- dep.depend = *maybe_features.get();
- else
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "error while parsing dependency: %s: %s", to_string(maybe_features.error()), name);
- return dep;
- }
-
- std::string Dependency::name() const
- {
- if (this->depend.features.empty()) return this->depend.name;
-
- const std::string features = Strings::join(",", this->depend.features);
- return Strings::format("%s[%s]", this->depend.name, features);
- }
-
- std::vector<Dependency> expand_qualified_dependencies(const std::vector<std::string>& depends)
- {
- return Util::fmap(depends, [&](const std::string& depend_string) -> Dependency {
- // First, try to find beginning and end of features list
- auto end_of_features = depend_string.find(']');
- if (end_of_features != std::string::npos)
- {
- ++end_of_features;
- }
- else
- {
- end_of_features = depend_string.find(' ');
- if (end_of_features == std::string::npos) end_of_features = depend_string.size();
- }
-
- auto begin_of_qualifier = depend_string.find('(', end_of_features);
- if (begin_of_qualifier == std::string::npos)
- {
- return Dependency::parse_dependency(depend_string.substr(0, end_of_features), "");
- }
- else
- {
- int depth = 1;
- auto i = begin_of_qualifier + 1;
- for (; i != depend_string.size(); ++i)
- {
- auto ch = depend_string[i];
- if (ch == '(')
- ++depth;
- else if (ch == ')')
- --depth;
-
- if (depth == 0) break;
- }
- return Dependency::parse_dependency(
- depend_string.substr(0, end_of_features),
- depend_string.substr(begin_of_qualifier + 1, i - begin_of_qualifier - 1));
- }
- });
- }
-
std::vector<FullPackageSpec> filter_dependencies(const std::vector<vcpkg::Dependency>& deps,
- const Triplet& t,
+ Triplet t,
const std::unordered_map<std::string, std::string>& cmake_vars)
{
std::vector<FullPackageSpec> ret;
@@ -289,13 +226,9 @@ namespace vcpkg
if (qualifier.empty() ||
evaluate_expression(qualifier, {cmake_vars, t.canonical_name()}).value_or_exit(VCPKG_LINE_INFO))
{
- ret.emplace_back(FullPackageSpec(
- PackageSpec::from_name_and_triplet(dep.depend.name, t).value_or_exit(VCPKG_LINE_INFO),
- dep.depend.features));
+ ret.emplace_back(FullPackageSpec({dep.depend.name, t}, dep.depend.features));
}
}
return ret;
}
-
- std::string to_string(const Dependency& dep) { return dep.name(); }
}
diff --git a/toolsrc/src/vcpkg/statusparagraph.cpp b/toolsrc/src/vcpkg/statusparagraph.cpp
index c0ecca3a0..144d079ec 100644
--- a/toolsrc/src/vcpkg/statusparagraph.cpp
+++ b/toolsrc/src/vcpkg/statusparagraph.cpp
@@ -88,27 +88,14 @@ namespace vcpkg
std::unordered_map<std::string, std::vector<FeatureSpec>> InstalledPackageView::feature_dependencies() const
{
- auto extract_deps = [&](const std::string& dep) {
- FullPackageSpec dependency =
- FullPackageSpec::from_string(dep, spec().triplet()).value_or_exit(VCPKG_LINE_INFO);
- std::vector<FeatureSpec> fspecs;
-
- for (std::string& feature : dependency.features)
- {
- fspecs.emplace_back(dependency.package_spec, std::move(feature));
- }
-
- return fspecs;
- };
+ auto extract_deps = [&](const std::string& name) { return FeatureSpec{{name, spec().triplet()}, "core"}; };
std::unordered_map<std::string, std::vector<FeatureSpec>> deps;
- for (const StatusParagraph* const& feature : features)
- {
- deps.emplace(feature->package.feature, Util::fmap_flatten(feature->package.depends, extract_deps));
- }
+ deps.emplace("core", Util::fmap(core->package.depends, extract_deps));
- deps.emplace("core", Util::fmap_flatten(core->package.depends, extract_deps));
+ for (const StatusParagraph* const& feature : features)
+ deps.emplace(feature->package.feature, Util::fmap(feature->package.depends, extract_deps));
return deps;
}
@@ -117,40 +104,18 @@ namespace vcpkg
{
// accumulate all features in installed dependencies
// Todo: make this unneeded by collapsing all package dependencies into the core package
- auto deps = Util::fmap_flatten(features, [](const StatusParagraph* pgh) -> std::vector<std::string> const& {
- return pgh->package.depends;
- });
+ std::vector<std::string> deps;
+ for (auto&& feature : features)
+ for (auto&& dep : feature->package.depends)
+ deps.push_back(dep);
// Add the core paragraph dependencies to the list
- deps.insert(deps.end(), core->package.depends.begin(), core->package.depends.end());
-
- auto&& l_spec = spec();
+ for (auto&& dep : core->package.depends)
+ deps.push_back(dep);
- // <hack>
- // This is a hack to work around existing installations that put featurespecs into binary packages
- // (example: curl[core])
- for (auto&& dep : deps)
- {
- dep.erase(std::find(dep.begin(), dep.end(), '['), dep.end());
- }
- Util::erase_remove_if(deps, [&](auto&& e) { return e == l_spec.name(); });
- // </hack>
+ Util::erase_remove_if(deps, [&](const std::string& pspec) { return pspec == spec().name(); });
Util::sort_unique_erase(deps);
- return Util::fmap(deps, [&](const std::string& dep) -> PackageSpec {
- auto maybe_dependency_spec = PackageSpec::from_name_and_triplet(dep, l_spec.triplet());
- if (auto dependency_spec = maybe_dependency_spec.get())
- {
- return std::move(*dependency_spec);
- }
-
- const PackageSpecParseResult error_type = maybe_dependency_spec.error();
- Checks::exit_with_message(VCPKG_LINE_INFO,
- "Invalid dependency [%s] in package [%s]\n"
- "%s",
- dep,
- l_spec.name(),
- vcpkg::to_string(error_type));
- });
+ return PackageSpec::to_package_specs(deps, spec().triplet());
}
}
diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp
index 2fa9df7df..2621c43e3 100644
--- a/toolsrc/src/vcpkg/statusparagraphs.cpp
+++ b/toolsrc/src/vcpkg/statusparagraphs.cpp
@@ -11,8 +11,7 @@ namespace vcpkg
{
}
- std::vector<std::unique_ptr<StatusParagraph>*> StatusParagraphs::find_all(const std::string& name,
- const Triplet& triplet)
+ std::vector<std::unique_ptr<StatusParagraph>*> StatusParagraphs::find_all(const std::string& name, Triplet triplet)
{
std::vector<std::unique_ptr<StatusParagraph>*> spghs;
for (auto&& p : *this)
@@ -52,7 +51,7 @@ namespace vcpkg
}
StatusParagraphs::iterator StatusParagraphs::find(const std::string& name,
- const Triplet& triplet,
+ Triplet triplet,
const std::string& feature)
{
if (feature == "core")
@@ -67,7 +66,7 @@ namespace vcpkg
}
StatusParagraphs::const_iterator StatusParagraphs::find(const std::string& name,
- const Triplet& triplet,
+ Triplet triplet,
const std::string& feature) const
{
if (feature == "core")
diff --git a/toolsrc/src/vcpkg/triplet.cpp b/toolsrc/src/vcpkg/triplet.cpp
index 1abfa0b39..4bc684d0b 100644
--- a/toolsrc/src/vcpkg/triplet.cpp
+++ b/toolsrc/src/vcpkg/triplet.cpp
@@ -39,10 +39,6 @@ namespace vcpkg
const Triplet Triplet::ARM_WINDOWS = from_canonical_name("arm-windows");
const Triplet Triplet::ARM64_WINDOWS = from_canonical_name("arm64-windows");
- bool Triplet::operator==(const Triplet& other) const { return this->m_instance == other.m_instance; }
-
- bool operator!=(const Triplet& left, const Triplet& right) { return !(left == right); }
-
Triplet Triplet::from_canonical_name(std::string&& triplet_as_string)
{
std::string s(Strings::ascii_to_lowercase(std::move(triplet_as_string)));
diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp
index 692cf1634..98be491e3 100644
--- a/toolsrc/src/vcpkg/vcpkgpaths.cpp
+++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp
@@ -129,7 +129,7 @@ namespace vcpkg
return this->vcpkg_dir_info / (pgh.fullstem() + ".list");
}
- bool VcpkgPaths::is_valid_triplet(const Triplet& t) const
+ bool VcpkgPaths::is_valid_triplet(Triplet t) const
{
const auto it = Util::find_if(this->get_available_triplets(), [&](auto&& available_triplet) {
return t.canonical_name() == available_triplet.name;
@@ -162,7 +162,7 @@ namespace vcpkg
});
}
- const fs::path VcpkgPaths::get_triplet_file_path(const Triplet& triplet) const
+ const fs::path VcpkgPaths::get_triplet_file_path(Triplet triplet) const
{
return m_triplets_cache.get_lazy(
triplet, [&]() -> auto {
diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj b/toolsrc/vcpkglib/vcpkglib.vcxproj
index 5119c5833..e033625a0 100644
--- a/toolsrc/vcpkglib/vcpkglib.vcxproj
+++ b/toolsrc/vcpkglib/vcpkglib.vcxproj
@@ -171,26 +171,32 @@
<ClInclude Include="..\include\vcpkg\base\zstringview.h" />
<ClInclude Include="..\include\vcpkg\binaryparagraph.h" />
<ClInclude Include="..\include\vcpkg\build.h" />
+ <ClInclude Include="..\include\vcpkg\cmakevars.h" />
<ClInclude Include="..\include\vcpkg\commands.h" />
<ClInclude Include="..\include\vcpkg\dependencies.h" />
+ <ClInclude Include="..\include\vcpkg\export.chocolatey.h" />
<ClInclude Include="..\include\vcpkg\export.h" />
<ClInclude Include="..\include\vcpkg\export.ifw.h" />
<ClInclude Include="..\include\vcpkg\globalstate.h" />
<ClInclude Include="..\include\vcpkg\help.h" />
<ClInclude Include="..\include\vcpkg\input.h" />
<ClInclude Include="..\include\vcpkg\install.h" />
+ <ClInclude Include="..\include\vcpkg\logicexpression.h" />
<ClInclude Include="..\include\vcpkg\metrics.h" />
<ClInclude Include="..\include\vcpkg\packagespec.h" />
- <ClInclude Include="..\include\vcpkg\packagespecparseresult.h" />
+ <ClInclude Include="..\include\vcpkg\paragraphparser.h" />
<ClInclude Include="..\include\vcpkg\paragraphparseresult.h" />
<ClInclude Include="..\include\vcpkg\paragraphs.h" />
<ClInclude Include="..\include\vcpkg\parse.h" />
+ <ClInclude Include="..\include\vcpkg\portfileprovider.h" />
<ClInclude Include="..\include\vcpkg\postbuildlint.h" />
<ClInclude Include="..\include\vcpkg\postbuildlint.buildtype.h" />
+ <ClInclude Include="..\include\vcpkg\pragmas.h" />
<ClInclude Include="..\include\vcpkg\remove.h" />
<ClInclude Include="..\include\vcpkg\sourceparagraph.h" />
<ClInclude Include="..\include\vcpkg\statusparagraph.h" />
<ClInclude Include="..\include\vcpkg\statusparagraphs.h" />
+ <ClInclude Include="..\include\vcpkg\textrowcol.h" />
<ClInclude Include="..\include\vcpkg\tools.h" />
<ClInclude Include="..\include\vcpkg\triplet.h" />
<ClInclude Include="..\include\vcpkg\update.h" />
@@ -255,7 +261,6 @@
<ClCompile Include="..\src\vcpkg\logicexpression.cpp" />
<ClCompile Include="..\src\vcpkg\metrics.cpp" />
<ClCompile Include="..\src\vcpkg\packagespec.cpp" />
- <ClCompile Include="..\src\vcpkg\packagespecparseresult.cpp" />
<ClCompile Include="..\src\vcpkg\paragraphparseresult.cpp" />
<ClCompile Include="..\src\vcpkg\paragraphs.cpp" />
<ClCompile Include="..\src\vcpkg\parse.cpp" />
diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters
index 043a9a22f..d7adfcdfd 100644
--- a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters
+++ b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters
@@ -120,9 +120,6 @@
<ClCompile Include="..\src\vcpkg\packagespec.cpp">
<Filter>Source Files\vcpkg</Filter>
</ClCompile>
- <ClCompile Include="..\src\vcpkg\packagespecparseresult.cpp">
- <Filter>Source Files\vcpkg</Filter>
- </ClCompile>
<ClCompile Include="..\src\vcpkg\paragraphparseresult.cpp">
<Filter>Source Files\vcpkg</Filter>
</ClCompile>
@@ -226,10 +223,10 @@
<Filter>Source Files\vcpkg</Filter>
</ClCompile>
<ClCompile Include="..\src\vcpkg\cmakevars.cpp">
- <Filter>Source Files</Filter>
+ <Filter>Source Files\vcpkg</Filter>
</ClCompile>
<ClCompile Include="..\src\vcpkg\portfileprovider.cpp">
- <Filter>Source Files</Filter>
+ <Filter>Source Files\vcpkg</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@@ -320,9 +317,6 @@
<ClInclude Include="..\include\vcpkg\packagespec.h">
<Filter>Header Files\vcpkg</Filter>
</ClInclude>
- <ClInclude Include="..\include\vcpkg\packagespecparseresult.h">
- <Filter>Header Files\vcpkg</Filter>
- </ClInclude>
<ClInclude Include="..\include\vcpkg\paragraphparseresult.h">
<Filter>Header Files\vcpkg</Filter>
</ClInclude>
@@ -416,5 +410,26 @@
<ClInclude Include="..\include\vcpkg\base\zstringview.h">
<Filter>Header Files\vcpkg\base</Filter>
</ClInclude>
+ <ClInclude Include="..\include\vcpkg\cmakevars.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\export.chocolatey.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\logicexpression.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\paragraphparser.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\portfileprovider.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\pragmas.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\vcpkg\textrowcol.h">
+ <Filter>Header Files\vcpkg</Filter>
+ </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file