mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-11-24 03:00:19 +08:00
[vcpkg-upgrade] Initial commit of upgrade command.
This commit is contained in:
parent
bbb431c5a9
commit
803347a0c5
@ -23,4 +23,18 @@ std::unique_ptr<vcpkg::StatusParagraph> make_status_pgh(const char* name,
|
||||
std::unique_ptr<vcpkg::StatusParagraph> make_status_feature_pgh(const char* name,
|
||||
const char* feature,
|
||||
const char* depends = "",
|
||||
const char* triplet = "x86-windows");
|
||||
const char* triplet = "x86-windows");
|
||||
|
||||
template<class T, class S>
|
||||
T&& unwrap(vcpkg::ExpectedT<T, S>&& p)
|
||||
{
|
||||
Assert::IsTrue(p.has_value());
|
||||
return std::move(*p.get());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T&& unwrap(vcpkg::Optional<T>&& opt)
|
||||
{
|
||||
Assert::IsTrue(opt.has_value());
|
||||
return std::move(*opt.get());
|
||||
}
|
||||
|
@ -39,6 +39,12 @@ namespace vcpkg::Commands
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
|
||||
namespace Upgrade
|
||||
{
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
|
||||
}
|
||||
|
||||
namespace Edit
|
||||
{
|
||||
extern const CommandStructure COMMAND_STRUCTURE;
|
||||
|
@ -92,11 +92,11 @@ namespace vcpkg::Dependencies
|
||||
|
||||
struct AnyAction
|
||||
{
|
||||
AnyAction(InstallPlanAction&& iplan) : install_plan(std::move(iplan)) {}
|
||||
AnyAction(RemovePlanAction&& rplan) : remove_plan(std::move(rplan)) {}
|
||||
AnyAction(InstallPlanAction&& iplan) : install_action(std::move(iplan)) {}
|
||||
AnyAction(RemovePlanAction&& rplan) : remove_action(std::move(rplan)) {}
|
||||
|
||||
Optional<InstallPlanAction> install_plan;
|
||||
Optional<RemovePlanAction> remove_plan;
|
||||
Optional<InstallPlanAction> install_action;
|
||||
Optional<RemovePlanAction> remove_action;
|
||||
|
||||
const PackageSpec& spec() const;
|
||||
};
|
||||
@ -123,22 +123,44 @@ namespace vcpkg::Dependencies
|
||||
|
||||
struct PortFileProvider
|
||||
{
|
||||
virtual const SourceControlFile& get_control_file(const std::string& spec) const = 0;
|
||||
virtual Optional<const SourceControlFile&> get_control_file(const std::string& src_name) const = 0;
|
||||
};
|
||||
|
||||
struct MapPortFile : Util::ResourceBase, PortFileProvider
|
||||
struct MapPortFileProvider : Util::ResourceBase, PortFileProvider
|
||||
{
|
||||
explicit MapPortFileProvider(const std::unordered_map<std::string, SourceControlFile>& map);
|
||||
Optional<const SourceControlFile&> get_control_file(const std::string& src_name) const override;
|
||||
|
||||
private:
|
||||
const std::unordered_map<std::string, SourceControlFile>& ports;
|
||||
explicit MapPortFile(const std::unordered_map<std::string, SourceControlFile>& map);
|
||||
const SourceControlFile& get_control_file(const std::string& spec) const override;
|
||||
};
|
||||
|
||||
struct PathsPortFile : Util::ResourceBase, PortFileProvider
|
||||
struct PathsPortFileProvider : Util::ResourceBase, PortFileProvider
|
||||
{
|
||||
explicit PathsPortFileProvider(const VcpkgPaths& paths);
|
||||
Optional<const SourceControlFile&> get_control_file(const std::string& src_name) const override;
|
||||
|
||||
private:
|
||||
const VcpkgPaths& ports;
|
||||
mutable std::unordered_map<std::string, SourceControlFile> cache;
|
||||
explicit PathsPortFile(const VcpkgPaths& paths);
|
||||
const SourceControlFile& get_control_file(const std::string& spec) const override;
|
||||
};
|
||||
|
||||
struct ClusterGraph;
|
||||
struct GraphPlan;
|
||||
|
||||
struct PackageGraph
|
||||
{
|
||||
PackageGraph(const PortFileProvider& provider, const StatusParagraphs& status_db);
|
||||
~PackageGraph();
|
||||
|
||||
void install(const FeatureSpec& spec);
|
||||
void upgrade(const PackageSpec& spec);
|
||||
|
||||
std::vector<AnyAction> serialize() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<GraphPlan> m_graph_plan;
|
||||
std::unique_ptr<ClusterGraph> m_graph;
|
||||
};
|
||||
|
||||
std::vector<InstallPlanAction> create_install_plan(const PortFileProvider& port_file_provider,
|
||||
@ -155,4 +177,10 @@ namespace vcpkg::Dependencies
|
||||
std::vector<AnyAction> create_feature_install_plan(const std::unordered_map<std::string, SourceControlFile>& map,
|
||||
const std::vector<FeatureSpec>& specs,
|
||||
const StatusParagraphs& status_db);
|
||||
|
||||
std::vector<AnyAction> create_feature_install_plan(const PortFileProvider& port_file_provider,
|
||||
const std::vector<FeatureSpec>& specs,
|
||||
const StatusParagraphs& status_db);
|
||||
|
||||
void print_plan(const std::vector<AnyAction>& action_plan, const bool is_recursive = true);
|
||||
}
|
||||
|
@ -32,7 +32,4 @@ namespace vcpkg::Paragraphs
|
||||
|
||||
std::vector<std::unique_ptr<SourceControlFile>> load_all_ports(const Files::Filesystem& fs,
|
||||
const fs::path& ports_dir);
|
||||
|
||||
std::map<std::string, VersionT> load_all_port_names_and_versions(const Files::Filesystem& fs,
|
||||
const fs::path& ports_dir);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <vcpkg/dependencies.h>
|
||||
#include <vcpkg/packagespec.h>
|
||||
#include <vcpkg/statusparagraphs.h>
|
||||
#include <vcpkg/vcpkgcmdarguments.h>
|
||||
@ -16,7 +17,8 @@ namespace vcpkg::Update
|
||||
VersionDiff version_diff;
|
||||
};
|
||||
|
||||
std::vector<OutdatedPackage> find_outdated_packages(const std::map<std::string, VersionT>& src_names_to_versions,
|
||||
std::vector<OutdatedPackage> find_outdated_packages(const Dependencies::PortFileProvider& provider,
|
||||
const StatusParagraphs& status_db);
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths);
|
||||
}
|
||||
}
|
||||
|
79
toolsrc/src/commands.upgrade.cpp
Normal file
79
toolsrc/src/commands.upgrade.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/dependencies.h>
|
||||
#include <vcpkg/help.h>
|
||||
#include <vcpkg/install.h>
|
||||
#include <vcpkg/statusparagraphs.h>
|
||||
#include <vcpkg/update.h>
|
||||
#include <vcpkg/vcpkglib.h>
|
||||
|
||||
namespace vcpkg::Commands::Upgrade
|
||||
{
|
||||
using Install::KeepGoing;
|
||||
using Install::to_keep_going;
|
||||
|
||||
static const std::string OPTION_NO_DRY_RUN = "--no-dry-run";
|
||||
static const std::string OPTION_KEEP_GOING = "--keep-going";
|
||||
|
||||
static const std::array<CommandSwitch, 2> INSTALL_SWITCHES = {{
|
||||
{OPTION_NO_DRY_RUN, "Actually upgrade"},
|
||||
{OPTION_KEEP_GOING, "Continue installing packages on failure"},
|
||||
}};
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
Help::create_example_string("upgrade --no-dry-run"),
|
||||
0,
|
||||
0,
|
||||
{INSTALL_SWITCHES, {}},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet&)
|
||||
{
|
||||
// input sanitization
|
||||
const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE);
|
||||
|
||||
const bool no_dry_run = Util::Sets::contains(options.switches, OPTION_NO_DRY_RUN);
|
||||
const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING));
|
||||
|
||||
// create the plan
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
Dependencies::PathsPortFileProvider provider(paths);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
auto outdated_packages = Update::find_outdated_packages(provider, status_db);
|
||||
for (auto&& outdated_package : outdated_packages)
|
||||
graph.upgrade(outdated_package.spec);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
if (plan.empty())
|
||||
{
|
||||
System::println("All packages are up-to-date.");
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
Dependencies::print_plan(plan, true);
|
||||
|
||||
if (!no_dry_run)
|
||||
{
|
||||
System::println(System::Color::warning,
|
||||
"If you are sure you want to rebuild the above packages, run this command with the "
|
||||
"--no-dry-run option.");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
const Install::InstallSummary summary = Install::perform(plan, keep_going, paths, status_db);
|
||||
|
||||
System::println("\nTotal elapsed time: %s\n", summary.total_elapsed_time);
|
||||
|
||||
if (keep_going == KeepGoing::YES)
|
||||
{
|
||||
summary.print();
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ namespace UnitTest1
|
||||
std::vector<std::string> vec,
|
||||
const Triplet& triplet = Triplet::X86_WINDOWS)
|
||||
{
|
||||
const auto& plan = install_action->install_plan.value_or_exit(VCPKG_LINE_INFO);
|
||||
const auto& plan = install_action->install_action.value_or_exit(VCPKG_LINE_INFO);
|
||||
const auto& feature_list = plan.feature_list;
|
||||
|
||||
Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str());
|
||||
@ -61,7 +61,7 @@ namespace UnitTest1
|
||||
std::string pkg_name,
|
||||
const Triplet& triplet = Triplet::X86_WINDOWS)
|
||||
{
|
||||
const auto& plan = remove_action->remove_plan.value_or_exit(VCPKG_LINE_INFO);
|
||||
const auto& plan = remove_action->remove_action.value_or_exit(VCPKG_LINE_INFO);
|
||||
Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str());
|
||||
Assert::AreEqual(pkg_name.c_str(), plan.spec.name().c_str());
|
||||
}
|
||||
@ -98,7 +98,7 @@ namespace UnitTest1
|
||||
auto spec_b = spec_map.emplace("b", "c");
|
||||
auto spec_c = spec_map.emplace("c");
|
||||
|
||||
Dependencies::MapPortFile map_port(spec_map.map);
|
||||
Dependencies::MapPortFileProvider map_port(spec_map.map);
|
||||
auto install_plan =
|
||||
Dependencies::create_install_plan(map_port, {spec_a}, StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
@ -122,7 +122,7 @@ namespace UnitTest1
|
||||
auto spec_g = spec_map.emplace("g");
|
||||
auto spec_h = spec_map.emplace("h");
|
||||
|
||||
Dependencies::MapPortFile map_port(spec_map.map);
|
||||
Dependencies::MapPortFileProvider map_port(spec_map.map);
|
||||
auto install_plan = Dependencies::create_install_plan(
|
||||
map_port, {spec_a, spec_b, spec_c}, StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
@ -162,7 +162,7 @@ namespace UnitTest1
|
||||
StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
Assert::AreEqual(size_t(1), install_plan.size());
|
||||
auto p = install_plan[0].install_plan.get();
|
||||
auto p = install_plan[0].install_action.get();
|
||||
Assert::IsNotNull(p);
|
||||
Assert::AreEqual("a", p->spec.name().c_str());
|
||||
Assert::AreEqual(Dependencies::InstallPlanType::ALREADY_INSTALLED, p->plan_type);
|
||||
@ -183,13 +183,13 @@ namespace UnitTest1
|
||||
StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
Assert::AreEqual(size_t(2), install_plan.size());
|
||||
auto p = install_plan[0].install_plan.get();
|
||||
auto p = install_plan[0].install_action.get();
|
||||
Assert::IsNotNull(p);
|
||||
Assert::AreEqual("b", p->spec.name().c_str());
|
||||
Assert::AreEqual(Dependencies::InstallPlanType::BUILD_AND_INSTALL, p->plan_type);
|
||||
Assert::AreEqual(Dependencies::RequestType::AUTO_SELECTED, p->request_type);
|
||||
|
||||
auto p2 = install_plan[1].install_plan.get();
|
||||
auto p2 = install_plan[1].install_action.get();
|
||||
Assert::IsNotNull(p2);
|
||||
Assert::AreEqual("a", p2->spec.name().c_str());
|
||||
Assert::AreEqual(Dependencies::InstallPlanType::BUILD_AND_INSTALL, p2->plan_type);
|
||||
@ -215,7 +215,7 @@ namespace UnitTest1
|
||||
auto spec_j = spec_map.emplace("j", "k");
|
||||
auto spec_k = spec_map.emplace("k");
|
||||
|
||||
Dependencies::MapPortFile map_port(spec_map.map);
|
||||
Dependencies::MapPortFileProvider map_port(spec_map.map);
|
||||
auto install_plan =
|
||||
Dependencies::create_install_plan(map_port, {spec_a}, StatusParagraphs(std::move(status_paragraphs)));
|
||||
|
||||
@ -521,4 +521,138 @@ namespace UnitTest1
|
||||
Assert::AreEqual("expat", remove_plan[2].spec.name().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
class UpgradePlanTests : public TestClass<UpgradePlanTests>
|
||||
{
|
||||
TEST_METHOD(basic_upgrade_scheme)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
pghs.push_back(make_status_pgh("a"));
|
||||
StatusParagraphs status_db(std::move(pghs));
|
||||
|
||||
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
|
||||
auto spec_a = spec_map.emplace("a");
|
||||
|
||||
Dependencies::MapPortFileProvider provider(spec_map.map);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
graph.upgrade(spec_a);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
Assert::AreEqual(size_t(2), plan.size());
|
||||
Assert::AreEqual("a", plan[0].spec().name().c_str());
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
Assert::AreEqual("a", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].install_action.has_value());
|
||||
}
|
||||
|
||||
TEST_METHOD(basic_upgrade_scheme_with_recurse)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
pghs.push_back(make_status_pgh("a"));
|
||||
pghs.push_back(make_status_pgh("b", "a"));
|
||||
StatusParagraphs status_db(std::move(pghs));
|
||||
|
||||
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
|
||||
auto spec_a = spec_map.emplace("a");
|
||||
spec_map.emplace("b", "a");
|
||||
|
||||
Dependencies::MapPortFileProvider provider(spec_map.map);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
graph.upgrade(spec_a);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
Assert::AreEqual(size_t(4), plan.size());
|
||||
Assert::AreEqual("b", plan[0].spec().name().c_str());
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
|
||||
Assert::AreEqual("a", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].remove_action.has_value());
|
||||
|
||||
Assert::AreEqual("a", plan[2].spec().name().c_str());
|
||||
Assert::IsTrue(plan[2].install_action.has_value());
|
||||
|
||||
Assert::AreEqual("b", plan[3].spec().name().c_str());
|
||||
Assert::IsTrue(plan[3].install_action.has_value());
|
||||
}
|
||||
|
||||
TEST_METHOD(basic_upgrade_scheme_with_bystander)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
pghs.push_back(make_status_pgh("a"));
|
||||
pghs.push_back(make_status_pgh("b"));
|
||||
StatusParagraphs status_db(std::move(pghs));
|
||||
|
||||
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
|
||||
auto spec_a = spec_map.emplace("a");
|
||||
spec_map.emplace("b", "a");
|
||||
|
||||
Dependencies::MapPortFileProvider provider(spec_map.map);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
graph.upgrade(spec_a);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
Assert::AreEqual(size_t(2), plan.size());
|
||||
Assert::AreEqual("a", plan[0].spec().name().c_str());
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
Assert::AreEqual("a", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].install_action.has_value());
|
||||
}
|
||||
|
||||
TEST_METHOD(basic_upgrade_scheme_with_new_dep)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
pghs.push_back(make_status_pgh("a"));
|
||||
StatusParagraphs status_db(std::move(pghs));
|
||||
|
||||
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
|
||||
auto spec_a = spec_map.emplace("a", "b");
|
||||
spec_map.emplace("b");
|
||||
|
||||
Dependencies::MapPortFileProvider provider(spec_map.map);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
graph.upgrade(spec_a);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
Assert::AreEqual(size_t(3), plan.size());
|
||||
Assert::AreEqual("a", plan[0].spec().name().c_str());
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
Assert::AreEqual("b", plan[1].spec().name().c_str());
|
||||
Assert::IsTrue(plan[1].install_action.has_value());
|
||||
Assert::AreEqual("a", plan[2].spec().name().c_str());
|
||||
Assert::IsTrue(plan[2].install_action.has_value());
|
||||
}
|
||||
|
||||
TEST_METHOD(basic_upgrade_scheme_with_features)
|
||||
{
|
||||
std::vector<std::unique_ptr<StatusParagraph>> pghs;
|
||||
pghs.push_back(make_status_pgh("a"));
|
||||
pghs.push_back(make_status_feature_pgh("a", "a1"));
|
||||
StatusParagraphs status_db(std::move(pghs));
|
||||
|
||||
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
|
||||
auto spec_a = spec_map.emplace("a", "", {{"a1", ""}});
|
||||
|
||||
Dependencies::MapPortFileProvider provider(spec_map.map);
|
||||
Dependencies::PackageGraph graph(provider, status_db);
|
||||
|
||||
graph.upgrade(spec_a);
|
||||
|
||||
auto plan = graph.serialize();
|
||||
|
||||
Assert::AreEqual(size_t(2), plan.size());
|
||||
|
||||
Assert::AreEqual("a", plan[0].spec().name().c_str());
|
||||
Assert::IsTrue(plan[0].remove_action.has_value());
|
||||
|
||||
features_check(&plan[1], "a", {"core", "a1"});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ using namespace vcpkg::Update;
|
||||
|
||||
namespace UnitTest1
|
||||
{
|
||||
using Pgh = std::vector<std::unordered_map<std::string, std::string>>;
|
||||
|
||||
class UpdateTests : public TestClass<UpdateTests>
|
||||
{
|
||||
TEST_METHOD(find_outdated_packages_basic)
|
||||
@ -19,10 +21,12 @@ namespace UnitTest1
|
||||
|
||||
StatusParagraphs status_db(std::move(status_paragraphs));
|
||||
|
||||
std::map<std::string, VersionT> port_versions;
|
||||
port_versions["a"] = VersionT("0");
|
||||
std::unordered_map<std::string, SourceControlFile> map;
|
||||
auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}}));
|
||||
map.emplace("a", std::move(*scf));
|
||||
Dependencies::MapPortFileProvider provider(map);
|
||||
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(port_versions, status_db),
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(provider, status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
|
||||
Assert::AreEqual(size_t(1), pkgs.size());
|
||||
@ -41,10 +45,12 @@ namespace UnitTest1
|
||||
|
||||
StatusParagraphs status_db(std::move(status_paragraphs));
|
||||
|
||||
std::map<std::string, VersionT> port_versions;
|
||||
port_versions["a"] = VersionT("0");
|
||||
std::unordered_map<std::string, SourceControlFile> map;
|
||||
auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}}));
|
||||
map.emplace("a", std::move(*scf));
|
||||
Dependencies::MapPortFileProvider provider(map);
|
||||
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(port_versions, status_db),
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(provider, status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
|
||||
Assert::AreEqual(size_t(1), pkgs.size());
|
||||
@ -65,10 +71,12 @@ namespace UnitTest1
|
||||
|
||||
StatusParagraphs status_db(std::move(status_paragraphs));
|
||||
|
||||
std::map<std::string, VersionT> port_versions;
|
||||
port_versions["a"] = VersionT("0");
|
||||
std::unordered_map<std::string, SourceControlFile> map;
|
||||
auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}}));
|
||||
map.emplace("a", std::move(*scf));
|
||||
Dependencies::MapPortFileProvider provider(map);
|
||||
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(port_versions, status_db),
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(provider, status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
|
||||
Assert::AreEqual(size_t(1), pkgs.size());
|
||||
@ -84,10 +92,12 @@ namespace UnitTest1
|
||||
|
||||
StatusParagraphs status_db(std::move(status_paragraphs));
|
||||
|
||||
std::map<std::string, VersionT> port_versions;
|
||||
port_versions["a"] = VersionT("2");
|
||||
std::unordered_map<std::string, SourceControlFile> map;
|
||||
auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}}));
|
||||
map.emplace("a", std::move(*scf));
|
||||
Dependencies::MapPortFileProvider provider(map);
|
||||
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(port_versions, status_db),
|
||||
auto pkgs = SortedVector<OutdatedPackage>(Update::find_outdated_packages(provider, status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
|
||||
Assert::AreEqual(size_t(0), pkgs.size());
|
||||
|
@ -27,7 +27,7 @@ namespace vcpkg::Commands::CI
|
||||
const std::vector<PackageSpec> specs = PackageSpec::to_package_specs(ports, triplet);
|
||||
|
||||
StatusParagraphs status_db = database_load_check(paths);
|
||||
const auto& paths_port_file = Dependencies::PathsPortFile(paths);
|
||||
const auto& paths_port_file = Dependencies::PathsPortFileProvider(paths);
|
||||
std::vector<InstallPlanAction> install_plan =
|
||||
Dependencies::create_install_plan(paths_port_file, specs, status_db);
|
||||
|
||||
|
@ -13,9 +13,10 @@ namespace vcpkg::Commands
|
||||
Span<const PackageNameAndFunction<CommandTypeA>> get_available_commands_type_a()
|
||||
{
|
||||
static std::vector<PackageNameAndFunction<CommandTypeA>> t = {
|
||||
PackageNameAndFunction<CommandTypeA>{"install", &Install::perform_and_exit},
|
||||
{"install", &Install::perform_and_exit},
|
||||
{"ci", &CI::perform_and_exit},
|
||||
{"remove", &Remove::perform_and_exit},
|
||||
{"upgrade", &Upgrade::perform_and_exit},
|
||||
{"build", &Build::Command::perform_and_exit},
|
||||
{"env", &Env::perform_and_exit},
|
||||
{"build-external", &BuildExternal::perform_and_exit},
|
||||
|
@ -98,8 +98,11 @@ namespace vcpkg::Commands::PortsDiff
|
||||
".vcpkg-root",
|
||||
git_exe.u8string());
|
||||
System::cmd_execute_clean(cmd);
|
||||
const std::map<std::string, VersionT> names_and_versions = Paragraphs::load_all_port_names_and_versions(
|
||||
paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
|
||||
const auto all_ports =
|
||||
Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
|
||||
std::map<std::string, VersionT> names_and_versions;
|
||||
for (auto&& port : all_ports)
|
||||
names_and_versions.emplace(port->core_paragraph->name, port->core_paragraph->version);
|
||||
fs.remove_all(temp_checkout_path, ec);
|
||||
return names_and_versions;
|
||||
}
|
||||
|
@ -65,26 +65,19 @@ namespace vcpkg::Dependencies
|
||||
|
||||
struct ClusterGraph : Util::MoveOnlyBase
|
||||
{
|
||||
explicit ClusterGraph(std::unordered_map<std::string, const SourceControlFile*>&& ports)
|
||||
: m_ports(std::move(ports))
|
||||
{
|
||||
}
|
||||
explicit ClusterGraph(const PortFileProvider& provider) : m_provider(provider) {}
|
||||
|
||||
Cluster& get(const PackageSpec& spec)
|
||||
{
|
||||
auto it = m_graph.find(spec);
|
||||
if (it == m_graph.end())
|
||||
{
|
||||
// Load on-demand from m_ports
|
||||
auto it_ports = m_ports.find(spec.name());
|
||||
if (it_ports != m_ports.end())
|
||||
{
|
||||
auto& clust = m_graph[spec];
|
||||
clust.spec = spec;
|
||||
cluster_from_scf(*it_ports->second, clust);
|
||||
return clust;
|
||||
}
|
||||
return m_graph[spec];
|
||||
// Load on-demand from m_provider
|
||||
auto maybe_scf = m_provider.get_control_file(spec.name());
|
||||
auto& clust = m_graph[spec];
|
||||
clust.spec = spec;
|
||||
if (auto p_scf = maybe_scf.get()) cluster_from_scf(*p_scf, clust);
|
||||
return clust;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
@ -107,7 +100,7 @@ namespace vcpkg::Dependencies
|
||||
}
|
||||
|
||||
std::unordered_map<PackageSpec, Cluster> m_graph;
|
||||
std::unordered_map<std::string, const SourceControlFile*> m_ports;
|
||||
const PortFileProvider& m_provider;
|
||||
};
|
||||
|
||||
std::vector<PackageSpec> AnyParagraph::dependencies(const Triplet& triplet) const
|
||||
@ -226,12 +219,12 @@ namespace vcpkg::Dependencies
|
||||
|
||||
const PackageSpec& AnyAction::spec() const
|
||||
{
|
||||
if (const auto p = install_plan.get())
|
||||
if (const auto p = install_action.get())
|
||||
{
|
||||
return p->spec;
|
||||
}
|
||||
|
||||
if (const auto p = remove_plan.get())
|
||||
if (const auto p = remove_action.get())
|
||||
{
|
||||
return p->spec;
|
||||
}
|
||||
@ -269,21 +262,20 @@ namespace vcpkg::Dependencies
|
||||
return left->spec.name() < right->spec.name();
|
||||
}
|
||||
|
||||
MapPortFile::MapPortFile(const std::unordered_map<std::string, SourceControlFile>& map) : ports(map) {}
|
||||
MapPortFileProvider::MapPortFileProvider(const std::unordered_map<std::string, SourceControlFile>& map) : ports(map)
|
||||
{
|
||||
}
|
||||
|
||||
const SourceControlFile& MapPortFile::get_control_file(const std::string& spec) const
|
||||
Optional<const SourceControlFile&> MapPortFileProvider::get_control_file(const std::string& spec) const
|
||||
{
|
||||
auto scf = ports.find(spec);
|
||||
if (scf == ports.end())
|
||||
{
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
if (scf == ports.end()) return nullopt;
|
||||
return scf->second;
|
||||
}
|
||||
|
||||
PathsPortFile::PathsPortFile(const VcpkgPaths& paths) : ports(paths) {}
|
||||
PathsPortFileProvider::PathsPortFileProvider(const VcpkgPaths& paths) : ports(paths) {}
|
||||
|
||||
const SourceControlFile& PathsPortFile::get_control_file(const std::string& spec) const
|
||||
Optional<const SourceControlFile&> PathsPortFileProvider::get_control_file(const std::string& spec) const
|
||||
{
|
||||
auto cache_it = cache.find(spec);
|
||||
if (cache_it != cache.end())
|
||||
@ -298,56 +290,34 @@ namespace vcpkg::Dependencies
|
||||
auto it = cache.emplace(spec, std::move(*scf->get()));
|
||||
return it.first->second;
|
||||
}
|
||||
print_error_message(source_control_file.error());
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::vector<InstallPlanAction> create_install_plan(const PortFileProvider& port_file_provider,
|
||||
const std::vector<PackageSpec>& specs,
|
||||
const StatusParagraphs& status_db)
|
||||
{
|
||||
struct InstallAdjacencyProvider final : Graphs::AdjacencyProvider<PackageSpec, InstallPlanAction>
|
||||
auto fspecs = Util::fmap(specs, [](const PackageSpec& spec) { return FeatureSpec(spec, ""); });
|
||||
auto plan = create_feature_install_plan(port_file_provider, fspecs, status_db);
|
||||
|
||||
std::vector<InstallPlanAction> ret;
|
||||
ret.reserve(plan.size());
|
||||
|
||||
for (auto&& action : plan)
|
||||
{
|
||||
const PortFileProvider& port_file_provider;
|
||||
const StatusParagraphs& status_db;
|
||||
const std::unordered_set<PackageSpec>& specs_as_set;
|
||||
|
||||
InstallAdjacencyProvider(const PortFileProvider& port_file_provider,
|
||||
const StatusParagraphs& s,
|
||||
const std::unordered_set<PackageSpec>& specs_as_set)
|
||||
: port_file_provider(port_file_provider), status_db(s), specs_as_set(specs_as_set)
|
||||
if (auto p_install = action.install_action.get())
|
||||
{
|
||||
ret.push_back(std::move(*p_install));
|
||||
}
|
||||
|
||||
std::vector<PackageSpec> adjacency_list(const InstallPlanAction& plan) const override
|
||||
else
|
||||
{
|
||||
if (plan.any_paragraph.status_paragraph.get()) return std::vector<PackageSpec>{};
|
||||
return plan.any_paragraph.dependencies(plan.spec.triplet());
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||
"The installation plan requires feature packages support. Please re-run the "
|
||||
"command with --featurepackages.");
|
||||
}
|
||||
}
|
||||
|
||||
InstallPlanAction load_vertex_data(const PackageSpec& spec) const override
|
||||
{
|
||||
const RequestType request_type = specs_as_set.find(spec) != specs_as_set.end()
|
||||
? RequestType::USER_REQUESTED
|
||||
: RequestType::AUTO_SELECTED;
|
||||
auto it = status_db.find_installed(spec);
|
||||
if (it != status_db.end()) return InstallPlanAction{spec, {*it->get(), nullopt, nullopt}, request_type};
|
||||
return InstallPlanAction{
|
||||
spec,
|
||||
{nullopt, nullopt, *port_file_provider.get_control_file(spec.name()).core_paragraph},
|
||||
request_type};
|
||||
}
|
||||
};
|
||||
|
||||
const std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend());
|
||||
std::vector<InstallPlanAction> toposort =
|
||||
Graphs::topological_sort(specs, InstallAdjacencyProvider{port_file_provider, status_db, specs_as_set});
|
||||
Util::erase_remove_if(toposort, [](const InstallPlanAction& plan) {
|
||||
return plan.request_type == RequestType::AUTO_SELECTED &&
|
||||
plan.plan_type == InstallPlanType::ALREADY_INSTALLED;
|
||||
});
|
||||
|
||||
return toposort;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<RemovePlanAction> create_remove_plan(const std::vector<PackageSpec>& specs,
|
||||
@ -461,11 +431,12 @@ namespace vcpkg::Dependencies
|
||||
SUCCESS,
|
||||
};
|
||||
|
||||
MarkPlusResult mark_plus(const std::string& feature,
|
||||
Cluster& cluster,
|
||||
ClusterGraph& pkg_to_cluster,
|
||||
GraphPlan& graph_plan);
|
||||
void mark_minus(Cluster& cluster, ClusterGraph& pkg_to_cluster, GraphPlan& graph_plan);
|
||||
static MarkPlusResult mark_plus(const std::string& feature,
|
||||
Cluster& cluster,
|
||||
ClusterGraph& pkg_to_cluster,
|
||||
GraphPlan& graph_plan);
|
||||
|
||||
static void mark_minus(Cluster& cluster, ClusterGraph& pkg_to_cluster, GraphPlan& graph_plan);
|
||||
|
||||
MarkPlusResult mark_plus(const std::string& feature, Cluster& cluster, ClusterGraph& graph, GraphPlan& graph_plan)
|
||||
{
|
||||
@ -557,110 +528,80 @@ namespace vcpkg::Dependencies
|
||||
}
|
||||
}
|
||||
|
||||
static ClusterGraph create_feature_install_graph(const std::unordered_map<std::string, SourceControlFile>& map,
|
||||
const StatusParagraphs& status_db)
|
||||
std::vector<AnyAction> create_feature_install_plan(const PortFileProvider& provider,
|
||||
const std::vector<FeatureSpec>& specs,
|
||||
const StatusParagraphs& status_db)
|
||||
{
|
||||
std::unordered_map<std::string, const SourceControlFile*> ptr_map;
|
||||
for (auto&& p : map)
|
||||
ptr_map.emplace(p.first, &p.second);
|
||||
ClusterGraph graph(std::move(ptr_map));
|
||||
PackageGraph pgraph(provider, status_db);
|
||||
for (auto&& spec : specs)
|
||||
pgraph.install(spec);
|
||||
|
||||
auto installed_ports = get_installed_ports(status_db);
|
||||
|
||||
for (auto&& status_paragraph : installed_ports)
|
||||
{
|
||||
Cluster& cluster = graph.get(status_paragraph->package.spec);
|
||||
|
||||
cluster.transient_uninstalled = false;
|
||||
|
||||
cluster.status_paragraphs.emplace_back(status_paragraph);
|
||||
|
||||
auto& status_paragraph_feature = status_paragraph->package.feature;
|
||||
// In this case, empty string indicates the "core" paragraph for a package.
|
||||
if (status_paragraph_feature.empty())
|
||||
{
|
||||
cluster.original_features.insert("core");
|
||||
}
|
||||
else
|
||||
{
|
||||
cluster.original_features.insert(status_paragraph_feature);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& status_paragraph : installed_ports)
|
||||
{
|
||||
auto& spec = status_paragraph->package.spec;
|
||||
auto& status_paragraph_feature = status_paragraph->package.feature;
|
||||
auto reverse_edges = FeatureSpec::from_strings_and_triplet(status_paragraph->package.depends,
|
||||
status_paragraph->package.spec.triplet());
|
||||
|
||||
for (auto&& dependency : reverse_edges)
|
||||
{
|
||||
auto& dep_cluster = graph.get(dependency.spec());
|
||||
|
||||
auto depends_name = dependency.feature();
|
||||
if (depends_name.empty()) depends_name = "core";
|
||||
|
||||
auto& target_node = dep_cluster.edges[depends_name];
|
||||
target_node.remove_edges.emplace_back(FeatureSpec{spec, status_paragraph_feature});
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
return pgraph.serialize();
|
||||
}
|
||||
|
||||
std::vector<AnyAction> create_feature_install_plan(const std::unordered_map<std::string, SourceControlFile>& map,
|
||||
const std::vector<FeatureSpec>& specs,
|
||||
const StatusParagraphs& status_db)
|
||||
{
|
||||
ClusterGraph graph = create_feature_install_graph(map, status_db);
|
||||
MapPortFileProvider provider(map);
|
||||
return create_feature_install_plan(provider, specs, status_db);
|
||||
}
|
||||
|
||||
GraphPlan graph_plan;
|
||||
for (auto&& spec : specs)
|
||||
void PackageGraph::install(const FeatureSpec& spec)
|
||||
{
|
||||
Cluster& spec_cluster = m_graph->get(spec.spec());
|
||||
spec_cluster.request_type = RequestType::USER_REQUESTED;
|
||||
if (spec.feature() == "*")
|
||||
{
|
||||
Cluster& spec_cluster = graph.get(spec.spec());
|
||||
spec_cluster.request_type = RequestType::USER_REQUESTED;
|
||||
if (spec.feature() == "*")
|
||||
if (auto p_scf = spec_cluster.source_control_file.value_or(nullptr))
|
||||
{
|
||||
if (auto p_scf = spec_cluster.source_control_file.value_or(nullptr))
|
||||
for (auto&& feature : p_scf->feature_paragraphs)
|
||||
{
|
||||
for (auto&& feature : p_scf->feature_paragraphs)
|
||||
{
|
||||
auto res = mark_plus(feature->name, spec_cluster, graph, graph_plan);
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
res == MarkPlusResult::SUCCESS,
|
||||
"Error: Unable to locate feature %s",
|
||||
spec);
|
||||
}
|
||||
|
||||
auto res = mark_plus("core", spec_cluster, graph, graph_plan);
|
||||
auto res = mark_plus(feature->name, spec_cluster, *m_graph, *m_graph_plan);
|
||||
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: Unable to handle '*' because can't find CONTROL for %s", spec.spec());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = mark_plus(spec.feature(), spec_cluster, graph, graph_plan);
|
||||
|
||||
auto res = mark_plus("core", spec_cluster, *m_graph, *m_graph_plan);
|
||||
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: Unable to handle '*' because can't find CONTROL for %s", spec.spec());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = mark_plus(spec.feature(), spec_cluster, *m_graph, *m_graph_plan);
|
||||
|
||||
graph_plan.install_graph.add_vertex(ClusterPtr{&spec_cluster});
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
|
||||
}
|
||||
|
||||
Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_remove_graph(graph_plan.remove_graph.adjacency_list());
|
||||
auto remove_vertex_list = graph_plan.remove_graph.vertex_list();
|
||||
m_graph_plan->install_graph.add_vertex(ClusterPtr{&spec_cluster});
|
||||
}
|
||||
|
||||
void PackageGraph::upgrade(const PackageSpec& spec)
|
||||
{
|
||||
Cluster& spec_cluster = m_graph->get(spec);
|
||||
spec_cluster.request_type = RequestType::USER_REQUESTED;
|
||||
|
||||
mark_minus(spec_cluster, *m_graph, *m_graph_plan);
|
||||
}
|
||||
|
||||
std::vector<AnyAction> PackageGraph::serialize() const
|
||||
{
|
||||
Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_remove_graph(m_graph_plan->remove_graph.adjacency_list());
|
||||
auto remove_vertex_list = m_graph_plan->remove_graph.vertex_list();
|
||||
auto remove_toposort = Graphs::topological_sort(remove_vertex_list, adjacency_remove_graph);
|
||||
|
||||
Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_install_graph(graph_plan.install_graph.adjacency_list());
|
||||
auto insert_vertex_list = graph_plan.install_graph.vertex_list();
|
||||
Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_install_graph(
|
||||
m_graph_plan->install_graph.adjacency_list());
|
||||
auto insert_vertex_list = m_graph_plan->install_graph.vertex_list();
|
||||
auto insert_toposort = Graphs::topological_sort(insert_vertex_list, adjacency_install_graph);
|
||||
|
||||
std::vector<AnyAction> plan;
|
||||
@ -705,4 +646,162 @@ namespace vcpkg::Dependencies
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ClusterGraph> create_feature_install_graph(const PortFileProvider& map,
|
||||
const StatusParagraphs& status_db)
|
||||
{
|
||||
std::unique_ptr<ClusterGraph> graph = std::make_unique<ClusterGraph>(map);
|
||||
|
||||
auto installed_ports = get_installed_ports(status_db);
|
||||
|
||||
for (auto&& status_paragraph : installed_ports)
|
||||
{
|
||||
Cluster& cluster = graph->get(status_paragraph->package.spec);
|
||||
|
||||
cluster.transient_uninstalled = false;
|
||||
|
||||
cluster.status_paragraphs.emplace_back(status_paragraph);
|
||||
|
||||
auto& status_paragraph_feature = status_paragraph->package.feature;
|
||||
// In this case, empty string indicates the "core" paragraph for a package.
|
||||
if (status_paragraph_feature.empty())
|
||||
{
|
||||
cluster.original_features.insert("core");
|
||||
}
|
||||
else
|
||||
{
|
||||
cluster.original_features.insert(status_paragraph_feature);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the graph with "remove edges", which are the reverse of the Build-Depends edges.
|
||||
for (auto&& status_paragraph : installed_ports)
|
||||
{
|
||||
auto& spec = status_paragraph->package.spec;
|
||||
auto& status_paragraph_feature = status_paragraph->package.feature;
|
||||
auto reverse_edges = FeatureSpec::from_strings_and_triplet(status_paragraph->package.depends,
|
||||
status_paragraph->package.spec.triplet());
|
||||
|
||||
for (auto&& dependency : reverse_edges)
|
||||
{
|
||||
auto& dep_cluster = graph->get(dependency.spec());
|
||||
|
||||
auto depends_name = dependency.feature();
|
||||
if (depends_name.empty()) depends_name = "core";
|
||||
|
||||
auto& target_node = dep_cluster.edges[depends_name];
|
||||
target_node.remove_edges.emplace_back(FeatureSpec{spec, status_paragraph_feature});
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
PackageGraph::PackageGraph(const PortFileProvider& provider, const StatusParagraphs& status_db)
|
||||
: m_graph(create_feature_install_graph(provider, status_db)), m_graph_plan(std::make_unique<GraphPlan>())
|
||||
{
|
||||
}
|
||||
|
||||
PackageGraph::~PackageGraph() {}
|
||||
|
||||
void print_plan(const std::vector<AnyAction>& action_plan, const bool is_recursive)
|
||||
{
|
||||
std::vector<const RemovePlanAction*> remove_plans;
|
||||
std::vector<const InstallPlanAction*> rebuilt_plans;
|
||||
std::vector<const InstallPlanAction*> only_install_plans;
|
||||
std::vector<const InstallPlanAction*> new_plans;
|
||||
std::vector<const InstallPlanAction*> already_installed_plans;
|
||||
std::vector<const InstallPlanAction*> excluded;
|
||||
|
||||
const bool has_non_user_requested_packages = Util::find_if(action_plan, [](const AnyAction& package) -> bool {
|
||||
if (auto iplan = package.install_action.get())
|
||||
return iplan->request_type != RequestType::USER_REQUESTED;
|
||||
else
|
||||
return false;
|
||||
}) != action_plan.cend();
|
||||
|
||||
for (auto&& action : action_plan)
|
||||
{
|
||||
if (auto install_action = action.install_action.get())
|
||||
{
|
||||
// remove plans are guaranteed to come before install plans, so we know the plan will be contained if at
|
||||
// all.
|
||||
auto it = Util::find_if(
|
||||
remove_plans, [&](const RemovePlanAction* plan) { return plan->spec == install_action->spec; });
|
||||
if (it != remove_plans.end())
|
||||
{
|
||||
rebuilt_plans.emplace_back(install_action);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (install_action->plan_type)
|
||||
{
|
||||
case InstallPlanType::INSTALL: only_install_plans.emplace_back(install_action); break;
|
||||
case InstallPlanType::ALREADY_INSTALLED:
|
||||
if (install_action->request_type == RequestType::USER_REQUESTED)
|
||||
already_installed_plans.emplace_back(install_action);
|
||||
break;
|
||||
case InstallPlanType::BUILD_AND_INSTALL: new_plans.emplace_back(install_action); break;
|
||||
case InstallPlanType::EXCLUDED: excluded.emplace_back(install_action); break;
|
||||
default: Checks::unreachable(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto remove_action = action.remove_action.get())
|
||||
{
|
||||
remove_plans.emplace_back(remove_action);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(remove_plans.begin(), remove_plans.end(), &RemovePlanAction::compare_by_name);
|
||||
std::sort(rebuilt_plans.begin(), rebuilt_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(only_install_plans.begin(), only_install_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(new_plans.begin(), new_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(already_installed_plans.begin(), already_installed_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(excluded.begin(), excluded.end(), &InstallPlanAction::compare_by_name);
|
||||
|
||||
static auto actions_to_output_string = [](const std::vector<const InstallPlanAction*>& v) {
|
||||
return Strings::join("\n", v, [](const InstallPlanAction* p) {
|
||||
return to_output_string(p->request_type, p->displayname(), p->build_options);
|
||||
});
|
||||
};
|
||||
|
||||
if (excluded.size() > 0)
|
||||
{
|
||||
System::println("The following packages are excluded:\n%s", actions_to_output_string(excluded));
|
||||
}
|
||||
|
||||
if (already_installed_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages are already installed:\n%s",
|
||||
actions_to_output_string(already_installed_plans));
|
||||
}
|
||||
|
||||
if (rebuilt_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be rebuilt:\n%s", actions_to_output_string(rebuilt_plans));
|
||||
}
|
||||
|
||||
if (new_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be built and installed:\n%s",
|
||||
actions_to_output_string(new_plans));
|
||||
}
|
||||
|
||||
if (only_install_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be directly installed:\n%s",
|
||||
actions_to_output_string(only_install_plans));
|
||||
}
|
||||
|
||||
if (has_non_user_requested_packages)
|
||||
System::println("Additional packages (*) will be modified to complete this operation.");
|
||||
|
||||
if (remove_plans.size() > 0 && !is_recursive)
|
||||
{
|
||||
System::println(System::Color::warning,
|
||||
"If you are sure you want to rebuild the above packages, run the command with the "
|
||||
"--recurse option");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ namespace vcpkg::Help
|
||||
" vcpkg remove --outdated Uninstall all out-of-date packages\n"
|
||||
" vcpkg list List installed packages\n"
|
||||
" vcpkg update Display list of packages for updating\n"
|
||||
" vcpkg upgrade Rebuild all outdated packages\n"
|
||||
" vcpkg hash <file> [alg] Hash a file by specific algorithm, default SHA512\n"
|
||||
" vcpkg help topics Display the list of help topics\n"
|
||||
" vcpkg help <topic> Display help for a specific topic\n"
|
||||
|
@ -348,108 +348,6 @@ namespace vcpkg::Install
|
||||
Checks::unreachable(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
static void print_plan(const std::vector<AnyAction>& action_plan, const bool is_recursive)
|
||||
{
|
||||
std::vector<const RemovePlanAction*> remove_plans;
|
||||
std::vector<const InstallPlanAction*> rebuilt_plans;
|
||||
std::vector<const InstallPlanAction*> only_install_plans;
|
||||
std::vector<const InstallPlanAction*> new_plans;
|
||||
std::vector<const InstallPlanAction*> already_installed_plans;
|
||||
std::vector<const InstallPlanAction*> excluded;
|
||||
|
||||
const bool has_non_user_requested_packages = Util::find_if(action_plan, [](const AnyAction& package) -> bool {
|
||||
if (auto iplan = package.install_plan.get())
|
||||
return iplan->request_type != RequestType::USER_REQUESTED;
|
||||
else
|
||||
return false;
|
||||
}) != action_plan.cend();
|
||||
|
||||
for (auto&& action : action_plan)
|
||||
{
|
||||
if (auto install_action = action.install_plan.get())
|
||||
{
|
||||
// remove plans are guaranteed to come before install plans, so we know the plan will be contained if at
|
||||
// all.
|
||||
auto it = Util::find_if(
|
||||
remove_plans, [&](const RemovePlanAction* plan) { return plan->spec == install_action->spec; });
|
||||
if (it != remove_plans.end())
|
||||
{
|
||||
rebuilt_plans.emplace_back(install_action);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (install_action->plan_type)
|
||||
{
|
||||
case InstallPlanType::INSTALL: only_install_plans.emplace_back(install_action); break;
|
||||
case InstallPlanType::ALREADY_INSTALLED:
|
||||
if (install_action->request_type == RequestType::USER_REQUESTED)
|
||||
already_installed_plans.emplace_back(install_action);
|
||||
break;
|
||||
case InstallPlanType::BUILD_AND_INSTALL: new_plans.emplace_back(install_action); break;
|
||||
case InstallPlanType::EXCLUDED: excluded.emplace_back(install_action); break;
|
||||
default: Checks::unreachable(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto remove_action = action.remove_plan.get())
|
||||
{
|
||||
remove_plans.emplace_back(remove_action);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(remove_plans.begin(), remove_plans.end(), &RemovePlanAction::compare_by_name);
|
||||
std::sort(rebuilt_plans.begin(), rebuilt_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(only_install_plans.begin(), only_install_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(new_plans.begin(), new_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(already_installed_plans.begin(), already_installed_plans.end(), &InstallPlanAction::compare_by_name);
|
||||
std::sort(excluded.begin(), excluded.end(), &InstallPlanAction::compare_by_name);
|
||||
|
||||
static auto actions_to_output_string = [](const std::vector<const InstallPlanAction*>& v) {
|
||||
return Strings::join("\n", v, [](const InstallPlanAction* p) {
|
||||
return to_output_string(p->request_type, p->displayname(), p->build_options);
|
||||
});
|
||||
};
|
||||
|
||||
if (excluded.size() > 0)
|
||||
{
|
||||
System::println("The following packages are excluded:\n%s", actions_to_output_string(excluded));
|
||||
}
|
||||
|
||||
if (already_installed_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages are already installed:\n%s",
|
||||
actions_to_output_string(already_installed_plans));
|
||||
}
|
||||
|
||||
if (rebuilt_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be rebuilt:\n%s", actions_to_output_string(rebuilt_plans));
|
||||
}
|
||||
|
||||
if (new_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be built and installed:\n%s",
|
||||
actions_to_output_string(new_plans));
|
||||
}
|
||||
|
||||
if (only_install_plans.size() > 0)
|
||||
{
|
||||
System::println("The following packages will be directly installed:\n%s",
|
||||
actions_to_output_string(only_install_plans));
|
||||
}
|
||||
|
||||
if (has_non_user_requested_packages)
|
||||
System::println("Additional packages (*) will be installed to complete this operation.");
|
||||
|
||||
if (remove_plans.size() > 0 && !is_recursive)
|
||||
{
|
||||
System::println(System::Color::warning,
|
||||
"If you are sure you want to rebuild the above packages, run the command with the "
|
||||
"--recurse option");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void InstallSummary::print() const
|
||||
{
|
||||
System::println("RESULTS");
|
||||
@ -499,7 +397,7 @@ namespace vcpkg::Install
|
||||
|
||||
results.emplace_back(spec, &action);
|
||||
|
||||
if (const auto install_action = action.install_plan.get())
|
||||
if (const auto install_action = action.install_action.get())
|
||||
{
|
||||
auto result = perform_install_plan_action(paths, *install_action, status_db);
|
||||
|
||||
@ -511,7 +409,7 @@ namespace vcpkg::Install
|
||||
|
||||
results.back().build_result = std::move(result);
|
||||
}
|
||||
else if (const auto remove_action = action.remove_plan.get())
|
||||
else if (const auto remove_action = action.remove_action.get())
|
||||
{
|
||||
Checks::check_exit(VCPKG_LINE_INFO, GlobalState::feature_packages);
|
||||
Remove::perform_remove_plan_action(paths, *remove_action, Remove::Purge::YES, status_db);
|
||||
@ -690,7 +588,7 @@ namespace vcpkg::Install
|
||||
}
|
||||
else
|
||||
{
|
||||
Dependencies::PathsPortFile paths_port_file(paths);
|
||||
Dependencies::PathsPortFileProvider paths_port_file(paths);
|
||||
auto install_plan = Dependencies::create_install_plan(
|
||||
paths_port_file, Util::fmap(specs, [](auto&& spec) { return spec.package_spec; }), status_db);
|
||||
|
||||
@ -700,7 +598,7 @@ namespace vcpkg::Install
|
||||
|
||||
for (auto&& action : action_plan)
|
||||
{
|
||||
if (auto p_install = action.install_plan.get())
|
||||
if (auto p_install = action.install_action.get())
|
||||
{
|
||||
p_install->build_options = install_plan_options;
|
||||
if (p_install->request_type != RequestType::USER_REQUESTED)
|
||||
@ -713,16 +611,16 @@ namespace vcpkg::Install
|
||||
|
||||
// log the plan
|
||||
const std::string specs_string = Strings::join(",", action_plan, [](const AnyAction& action) {
|
||||
if (auto iaction = action.install_plan.get())
|
||||
if (auto iaction = action.install_action.get())
|
||||
return iaction->spec.to_string();
|
||||
else if (auto raction = action.remove_plan.get())
|
||||
else if (auto raction = action.remove_action.get())
|
||||
return "R$" + raction->spec.to_string();
|
||||
Checks::unreachable(VCPKG_LINE_INFO);
|
||||
});
|
||||
|
||||
Metrics::g_metrics.lock()->track_property("installplan", specs_string);
|
||||
|
||||
print_plan(action_plan, is_recursive);
|
||||
Dependencies::print_plan(action_plan, is_recursive);
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
@ -752,7 +650,7 @@ namespace vcpkg::Install
|
||||
for (auto&& result : summary.results)
|
||||
{
|
||||
if (!result.action) continue;
|
||||
if (auto p_install_action = result.action->install_plan.get())
|
||||
if (auto p_install_action = result.action->install_action.get())
|
||||
{
|
||||
if (p_install_action->request_type != RequestType::USER_REQUESTED) continue;
|
||||
auto bpgh = result.get_binary_paragraph();
|
||||
@ -773,7 +671,7 @@ namespace vcpkg::Install
|
||||
{
|
||||
if (build_result.binary_control_file) return &build_result.binary_control_file->core_paragraph;
|
||||
if (action)
|
||||
if (auto p_install_plan = action->install_plan.get())
|
||||
if (auto p_install_plan = action->install_action.get())
|
||||
{
|
||||
if (auto p_bcf = p_install_plan->any_paragraph.binary_control_file.get())
|
||||
return &p_bcf->core_paragraph;
|
||||
|
@ -289,16 +289,4 @@ namespace vcpkg::Paragraphs
|
||||
}
|
||||
return std::move(results.paragraphs);
|
||||
}
|
||||
|
||||
std::map<std::string, VersionT> load_all_port_names_and_versions(const Files::Filesystem& fs,
|
||||
const fs::path& ports_dir)
|
||||
{
|
||||
auto all_ports = load_all_ports(fs, ports_dir);
|
||||
|
||||
std::map<std::string, VersionT> names_and_versions;
|
||||
for (auto&& port : all_ports)
|
||||
names_and_versions.emplace(port->core_paragraph->name, port->core_paragraph->version);
|
||||
|
||||
return names_and_versions;
|
||||
}
|
||||
}
|
||||
|
@ -207,10 +207,11 @@ namespace vcpkg::Remove
|
||||
System::println(System::Color::error, "Error: 'remove' accepts either libraries or '--outdated'");
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
specs = Util::fmap(
|
||||
Update::find_outdated_packages(
|
||||
Paragraphs::load_all_port_names_and_versions(paths.get_filesystem(), paths.ports), status_db),
|
||||
[](auto&& outdated) { return outdated.spec; });
|
||||
|
||||
Dependencies::PathsPortFileProvider provider(paths);
|
||||
|
||||
specs = Util::fmap(Update::find_outdated_packages(provider, status_db),
|
||||
[](auto&& outdated) { return outdated.spec; });
|
||||
|
||||
if (specs.empty())
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace vcpkg::Update
|
||||
return left.spec.name() < right.spec.name();
|
||||
}
|
||||
|
||||
std::vector<OutdatedPackage> find_outdated_packages(const std::map<std::string, VersionT>& src_names_to_versions,
|
||||
std::vector<OutdatedPackage> find_outdated_packages(const Dependencies::PortFileProvider& provider,
|
||||
const StatusParagraphs& status_db)
|
||||
{
|
||||
const std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_db);
|
||||
@ -24,19 +24,23 @@ namespace vcpkg::Update
|
||||
{
|
||||
if (!pgh->package.feature.empty())
|
||||
{
|
||||
// Skip feature packages; only consider master packages for needing updates.
|
||||
// Skip feature paragraphs; only consider master paragraphs for needing updates.
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto it = src_names_to_versions.find(pgh->package.spec.name());
|
||||
if (it == src_names_to_versions.end())
|
||||
auto maybe_scf = provider.get_control_file(pgh->package.spec.name());
|
||||
if (auto p_scf = maybe_scf.get())
|
||||
{
|
||||
// Package was not installed from portfile
|
||||
continue;
|
||||
auto&& port_version = p_scf->core_paragraph->version;
|
||||
auto&& installed_version = pgh->package.version;
|
||||
if (installed_version != port_version)
|
||||
{
|
||||
output.push_back({pgh->package.spec, VersionDiff(installed_version, port_version)});
|
||||
}
|
||||
}
|
||||
if (it->second != pgh->package.version)
|
||||
else
|
||||
{
|
||||
output.push_back({pgh->package.spec, VersionDiff(pgh->package.version, it->second)});
|
||||
// No portfile available
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,10 +62,10 @@ namespace vcpkg::Update
|
||||
|
||||
const StatusParagraphs status_db = database_load_check(paths);
|
||||
|
||||
const auto outdated_packages = SortedVector<OutdatedPackage>(
|
||||
find_outdated_packages(Paragraphs::load_all_port_names_and_versions(paths.get_filesystem(), paths.ports),
|
||||
status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
Dependencies::PathsPortFileProvider provider(paths);
|
||||
|
||||
const auto outdated_packages = SortedVector<OutdatedPackage>(find_outdated_packages(provider, status_db),
|
||||
&OutdatedPackage::compare_by_name);
|
||||
|
||||
if (outdated_packages.empty())
|
||||
{
|
||||
@ -69,19 +73,17 @@ namespace vcpkg::Update
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string install_line;
|
||||
System::println("The following packages differ from their port versions:");
|
||||
for (auto&& package : outdated_packages)
|
||||
{
|
||||
install_line += package.spec.to_string();
|
||||
install_line += " ";
|
||||
System::println(" %-32s %s", package.spec, package.version_diff.to_string());
|
||||
}
|
||||
System::println("\n"
|
||||
"To update these packages, run\n"
|
||||
" .\\vcpkg remove --outdated\n"
|
||||
" .\\vcpkg install " +
|
||||
install_line);
|
||||
"To update these packages and all dependencies, run\n"
|
||||
" .\\vcpkg upgrade\n"
|
||||
"\n"
|
||||
"To only remove outdated packages, run\n"
|
||||
" .\\vcpkg remove --outdated\n");
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
|
@ -185,6 +185,7 @@
|
||||
<ClInclude Include="..\include\vcpkg\versiont.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\commands.upgrade.cpp" />
|
||||
<ClCompile Include="..\src\pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
|
@ -195,6 +195,9 @@
|
||||
<ClCompile Include="..\src\vcpkg\userconfig.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\commands.upgrade.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\pch.h">
|
||||
|
Loading…
Reference in New Issue
Block a user