aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src
diff options
context:
space:
mode:
authorras0219 <533828+ras0219@users.noreply.github.com>2020-08-12 12:35:26 -0700
committerGitHub <noreply@github.com>2020-08-12 12:35:26 -0700
commitc771e7bd07c3137d43cdca96efcb954439133532 (patch)
tree191b7d6e9a28072c1ffa592c8008664ff462c6c2 /toolsrc/src
parentf3b96f339c3179f8f1c46b412d192e0c8a84eb5e (diff)
downloadvcpkg-c771e7bd07c3137d43cdca96efcb954439133532.tar.gz
vcpkg-c771e7bd07c3137d43cdca96efcb954439133532.zip
[vcpkg] Fix resolution of default features when using Manifest mode (#12829)
* [vcpkg] Fix resolution of default features when using Manifest mode During manifest mode, the dependencies in the manifest should be treated as explicitly specified -- curl[core] should not install curl's default features. * [vcpkg] Improve error message when failed to parse manifest file Co-authored-by: Robert Schumacher <roschuma@microsoft.com>
Diffstat (limited to 'toolsrc/src')
-rw-r--r--toolsrc/src/vcpkg-test/dependencies.cpp64
-rw-r--r--toolsrc/src/vcpkg/dependencies.cpp74
-rw-r--r--toolsrc/src/vcpkg/install.cpp36
-rw-r--r--toolsrc/src/vcpkg/portfileprovider.cpp53
4 files changed, 154 insertions, 73 deletions
diff --git a/toolsrc/src/vcpkg-test/dependencies.cpp b/toolsrc/src/vcpkg-test/dependencies.cpp
index 6bd9dfc42..1951a6128 100644
--- a/toolsrc/src/vcpkg-test/dependencies.cpp
+++ b/toolsrc/src/vcpkg-test/dependencies.cpp
@@ -85,3 +85,67 @@ TEST_CASE ("qualified dependency", "[dependencies]")
REQUIRE(plan2.install_actions.size() == 2);
REQUIRE(plan2.install_actions.at(0).feature_list == std::vector<std::string>{"b1", "core"});
}
+
+TEST_CASE ("resolve_deps_as_top_level", "[dependencies]")
+{
+ using namespace Test;
+ PackageSpecMap spec_map;
+ FullPackageSpec spec_a{spec_map.emplace("a", "b, b[b1] (linux)"), {}};
+ FullPackageSpec spec_b{spec_map.emplace("b", "", {{"b1", ""}}), {}};
+ FullPackageSpec spec_c{spec_map.emplace("c", "b", {{"c1", "b[b1]"}, {"c2", "c[c1], a"}}, {"c1"}), {"core"}};
+ FullPackageSpec spec_d{spec_map.emplace("d", "c[core]"), {}};
+
+ PortFileProvider::MapPortFileProvider map_port{spec_map.map};
+ MockCMakeVarProvider var_provider;
+ Triplet t_linux = Triplet::from_canonical_name("x64-linux");
+ var_provider.dep_info_vars[{"a", t_linux}].emplace("VCPKG_CMAKE_SYSTEM_NAME", "Linux");
+ {
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("a").source_control_file, Triplet::X86_WINDOWS, {}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == spec_b);
+ }
+ {
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("a").source_control_file, t_linux, {}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == FullPackageSpec({"b", t_linux}, {"b1"}));
+ }
+ {
+ // without defaults
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("c").source_control_file, Triplet::X86_WINDOWS, {}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == spec_b);
+ }
+ FullPackageSpec spec_b_with_b1{spec_b.package_spec, {"b1"}};
+ {
+ // with defaults of c (c1)
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("c").source_control_file, Triplet::X86_WINDOWS, {"default"}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == spec_b_with_b1);
+ }
+ {
+ // with c1
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("c").source_control_file, Triplet::X86_WINDOWS, {"c1"}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == spec_b_with_b1);
+ }
+ {
+ // with c2 implying c1
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("c").source_control_file, Triplet::X86_WINDOWS, {"c2"}, var_provider);
+ REQUIRE(deps.size() == 2);
+ REQUIRE(deps.at(0) == spec_a);
+ REQUIRE(deps.at(1) == spec_b_with_b1);
+ }
+ {
+ // d -> c[core]
+ auto deps = vcpkg::Dependencies::resolve_deps_as_top_level(
+ *spec_map.map.at("d").source_control_file, Triplet::X86_WINDOWS, {}, var_provider);
+ REQUIRE(deps.size() == 1);
+ REQUIRE(deps.at(0) == spec_c);
+ }
+}
diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp
index 7774424de..f7671ceef 100644
--- a/toolsrc/src/vcpkg/dependencies.cpp
+++ b/toolsrc/src/vcpkg/dependencies.cpp
@@ -592,6 +592,70 @@ namespace vcpkg::Dependencies
m_graph->get(spec).request_type = RequestType::USER_REQUESTED;
}
+ // `features` should have "default" instead of missing "core"
+ std::vector<FullPackageSpec> resolve_deps_as_top_level(const SourceControlFile& scf,
+ Triplet triplet,
+ std::vector<std::string> features,
+ CMakeVars::CMakeVarProvider& var_provider)
+ {
+ PackageSpec spec{scf.core_paragraph->name, triplet};
+ std::map<std::string, std::vector<std::string>> specs_to_features;
+
+ Optional<const PlatformExpression::Context&> ctx_storage = var_provider.get_dep_info_vars(spec);
+ auto ctx = [&]() -> const PlatformExpression::Context& {
+ if (!ctx_storage)
+ {
+ var_provider.load_dep_info_vars({{spec}});
+ ctx_storage = var_provider.get_dep_info_vars(spec);
+ }
+ return ctx_storage.value_or_exit(VCPKG_LINE_INFO);
+ };
+
+ auto handle_deps = [&](View<Dependency> deps) {
+ for (auto&& dep : deps)
+ {
+ if (dep.platform.is_empty() || dep.platform.evaluate(ctx()))
+ {
+ if (dep.name == spec.name())
+ Util::Vectors::append(&features, dep.features);
+ else
+ Util::Vectors::append(&specs_to_features[dep.name], dep.features);
+ }
+ }
+ };
+
+ handle_deps(scf.core_paragraph->dependencies);
+ enum class State
+ {
+ NotVisited = 0,
+ Visited,
+ };
+ std::map<std::string, State> feature_state;
+ while (!features.empty())
+ {
+ auto feature = std::move(features.back());
+ features.pop_back();
+
+ if (feature_state[feature] == State::Visited) continue;
+ feature_state[feature] = State::Visited;
+ if (feature == "default")
+ {
+ Util::Vectors::append(&features, scf.core_paragraph->default_features);
+ }
+ else
+ {
+ auto it =
+ Util::find_if(scf.feature_paragraphs, [&feature](const std::unique_ptr<FeatureParagraph>& ptr) {
+ return ptr->name == feature;
+ });
+ if (it != scf.feature_paragraphs.end()) handle_deps(it->get()->dependencies);
+ }
+ }
+ return Util::fmap(specs_to_features, [triplet](std::pair<const std::string, std::vector<std::string>>& p) {
+ return FullPackageSpec({p.first, triplet}, Util::sort_unique_erase(std::move(p.second)));
+ });
+ }
+
ActionPlan create_feature_install_plan(const PortFileProvider::PortFileProvider& port_provider,
const CMakeVars::CMakeVarProvider& var_provider,
const std::vector<FullPackageSpec>& specs,
@@ -627,16 +691,6 @@ namespace vcpkg::Dependencies
auto res = pgraph.serialize(options);
- const auto is_manifest_spec = [](const auto& action) {
- return action.spec.name() == PackageSpec::MANIFEST_NAME;
- };
-
- Util::erase_remove_if(res.install_actions, is_manifest_spec);
-
- Checks::check_exit(VCPKG_LINE_INFO,
- !std::any_of(res.remove_actions.begin(), res.remove_actions.end(), is_manifest_spec),
- "\"default\" should never be installed");
-
return res;
}
diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp
index ba0285e20..e381b90a3 100644
--- a/toolsrc/src/vcpkg/install.cpp
+++ b/toolsrc/src/vcpkg/install.cpp
@@ -767,24 +767,40 @@ namespace vcpkg::Install
pkgsconfig = fs::u8path(it_pkgsconfig->second);
}
- std::vector<std::string> features;
-
- if (Util::Sets::contains(options.switches, OPTION_MANIFEST_NO_DEFAULT_FEATURES))
+ std::error_code ec;
+ auto manifest_path = paths.manifest_root_dir / fs::u8path("vcpkg.json");
+ auto maybe_manifest_scf = Paragraphs::try_load_manifest(fs, "manifest", manifest_path, ec);
+ if (ec)
{
- features.emplace_back("core");
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Failed to read manifest %s: %s", manifest_path.u8string(), ec.message());
}
+ else if (!maybe_manifest_scf)
+ {
+ print_error_message(maybe_manifest_scf.error());
+ Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to read manifest %s.", manifest_path.u8string());
+ }
+ auto& manifest_scf = *maybe_manifest_scf.value_or_exit(VCPKG_LINE_INFO);
+ std::vector<std::string> features;
auto manifest_feature_it = options.multisettings.find(OPTION_MANIFEST_FEATURE);
if (manifest_feature_it != options.multisettings.end())
{
- for (const auto& feature : manifest_feature_it->second)
- {
- features.push_back(feature);
- }
+ features.insert(features.end(), manifest_feature_it->second.begin(), manifest_feature_it->second.end());
+ }
+ auto core_it = Util::find(features, "core");
+ if (core_it == features.end())
+ {
+ if (!Util::Sets::contains(options.switches, OPTION_MANIFEST_NO_DEFAULT_FEATURES))
+ features.push_back("default");
+ }
+ else
+ {
+ // remove "core" because resolve_deps_as_top_level uses default-inversion
+ features.erase(core_it);
}
+ auto specs = resolve_deps_as_top_level(manifest_scf, default_triplet, features, var_provider);
- std::vector<FullPackageSpec> specs;
- specs.emplace_back(PackageSpec{PackageSpec::MANIFEST_NAME, default_triplet}, std::move(features));
auto install_plan = Dependencies::create_feature_install_plan(provider, var_provider, specs, {});
for (InstallPlanAction& action : install_plan.install_actions)
diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp
index a5806eb83..1376ad3bc 100644
--- a/toolsrc/src/vcpkg/portfileprovider.cpp
+++ b/toolsrc/src/vcpkg/portfileprovider.cpp
@@ -27,10 +27,6 @@ namespace vcpkg::PortFileProvider
const std::vector<std::string>& ports_dirs_paths)
: filesystem(paths.get_filesystem())
{
- if (paths.manifest_mode_enabled())
- {
- manifest = paths.manifest_root_dir / fs::u8path("vcpkg.json");
- }
auto& fs = paths.get_filesystem();
for (auto&& overlay_path : ports_dirs_paths)
{
@@ -62,38 +58,6 @@ namespace vcpkg::PortFileProvider
ports_dirs.emplace_back(paths.ports);
}
- const SourceControlFileLocation* PathsPortFileProvider::load_manifest_file() const
- {
- if (!manifest.empty())
- {
- std::error_code ec;
- auto maybe_scf = Paragraphs::try_load_manifest(filesystem, "manifest", manifest, ec);
- if (ec)
- {
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Failed to read manifest file %s: %s", manifest.u8string(), ec.message());
- }
-
- if (auto scf = maybe_scf.get())
- {
- auto it = cache.emplace(std::piecewise_construct,
- std::forward_as_tuple(PackageSpec::MANIFEST_NAME),
- std::forward_as_tuple(std::move(*scf), manifest.parent_path()));
- return &it.first->second;
- }
- else
- {
- vcpkg::print_error_message(maybe_scf.error());
- Checks::exit_with_message(
- VCPKG_LINE_INFO, "Error: Failed to load manifest file %s.", manifest.u8string());
- }
- }
- else
- {
- return nullptr;
- }
- }
-
ExpectedS<const SourceControlFileLocation&> PathsPortFileProvider::get_control_file(const std::string& spec) const
{
auto cache_it = cache.find(spec);
@@ -102,18 +66,6 @@ namespace vcpkg::PortFileProvider
return cache_it->second;
}
- if (spec == PackageSpec::MANIFEST_NAME)
- {
- if (auto p = load_manifest_file())
- {
- return *p;
- }
- else
- {
- Checks::unreachable(VCPKG_LINE_INFO);
- }
- }
-
for (auto&& ports_dir : ports_dirs)
{
// Try loading individual port
@@ -177,11 +129,6 @@ namespace vcpkg::PortFileProvider
cache.clear();
std::vector<const SourceControlFileLocation*> ret;
- if (auto p = load_manifest_file())
- {
- ret.push_back(p);
- }
-
for (auto&& ports_dir : ports_dirs)
{
// Try loading individual port