diff options
| author | Alexander Karatarakis <alkarata@microsoft.com> | 2017-04-10 12:57:49 -0700 |
|---|---|---|
| committer | Alexander Karatarakis <alkarata@microsoft.com> | 2017-04-21 18:06:51 -0700 |
| commit | 92cf32d59a5b3a1fd68bce4edf5c5d576e637678 (patch) | |
| tree | 7ac33576ea94f3bfaa234a5cbc82d7feba31eb50 | |
| parent | 47322f74bdefea394fdd07989a9535c35caeb8a3 (diff) | |
| download | vcpkg-92cf32d59a5b3a1fd68bce4edf5c5d576e637678.tar.gz vcpkg-92cf32d59a5b3a1fd68bce4edf5c5d576e637678.zip | |
Add skeleton code for `vcpkg export`
| -rw-r--r-- | toolsrc/include/vcpkg_Commands.h | 5 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg_Dependencies.h | 26 | ||||
| -rw-r--r-- | toolsrc/src/commands_available_commands.cpp | 5 | ||||
| -rw-r--r-- | toolsrc/src/commands_export.cpp | 93 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Dependencies.cpp | 70 | ||||
| -rw-r--r-- | toolsrc/vcpkglib/vcpkglib.vcxproj | 1 | ||||
| -rw-r--r-- | toolsrc/vcpkglib/vcpkglib.vcxproj.filters | 3 |
7 files changed, 201 insertions, 2 deletions
diff --git a/toolsrc/include/vcpkg_Commands.h b/toolsrc/include/vcpkg_Commands.h index 9760b5a35..68689bf1e 100644 --- a/toolsrc/include/vcpkg_Commands.h +++ b/toolsrc/include/vcpkg_Commands.h @@ -65,6 +65,11 @@ namespace vcpkg::Commands void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); } + namespace Export + { + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); + } + namespace CI { void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); diff --git a/toolsrc/include/vcpkg_Dependencies.h b/toolsrc/include/vcpkg_Dependencies.h index 247113573..ec3759a64 100644 --- a/toolsrc/include/vcpkg_Dependencies.h +++ b/toolsrc/include/vcpkg_Dependencies.h @@ -73,7 +73,33 @@ namespace vcpkg::Dependencies RequestType request_type; }; + enum class ExportPlanType + { + UNKNOWN, + PORT_AVAILABLE_BUT_NOT_BUILT, + ALREADY_BUILT + }; + + struct ExportPlanAction + { + static bool compare_by_name(const ExportPlanAction* left, const ExportPlanAction* right); + + ExportPlanAction(); + ExportPlanAction(const PackageSpec& spec, const AnyParagraph& any_paragraph, const RequestType& request_type); + ExportPlanAction(const ExportPlanAction&) = delete; + ExportPlanAction(ExportPlanAction&&) = default; + ExportPlanAction& operator=(const ExportPlanAction&) = delete; + ExportPlanAction& operator=(ExportPlanAction&&) = default; + + PackageSpec spec; + AnyParagraph any_paragraph; + ExportPlanType plan_type; + RequestType request_type; + }; + std::vector<InstallPlanAction> create_install_plan(const VcpkgPaths& paths, const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db); std::vector<RemovePlanAction> create_remove_plan(const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db); + + std::vector<ExportPlanAction> create_export_plan(const VcpkgPaths& paths, const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db); } diff --git a/toolsrc/src/commands_available_commands.cpp b/toolsrc/src/commands_available_commands.cpp index e4c5135c7..4fdccff1d 100644 --- a/toolsrc/src/commands_available_commands.cpp +++ b/toolsrc/src/commands_available_commands.cpp @@ -11,7 +11,8 @@ namespace vcpkg::Commands { "remove", &Remove::perform_and_exit }, { "build", &Build::perform_and_exit }, { "env", &Env::perform_and_exit }, - { "build-external", &BuildExternal::perform_and_exit } + { "build-external", &BuildExternal::perform_and_exit }, + { "export", &Export::perform_and_exit }, }; return t; } @@ -31,7 +32,7 @@ namespace vcpkg::Commands { "create", &Create::perform_and_exit }, { "import", &Import::perform_and_exit }, { "cache", &Cache::perform_and_exit }, - { "portsdiff", &PortsDiff::perform_and_exit } + { "portsdiff", &PortsDiff::perform_and_exit }, }; return t; } diff --git a/toolsrc/src/commands_export.cpp b/toolsrc/src/commands_export.cpp new file mode 100644 index 000000000..cde4ae0dc --- /dev/null +++ b/toolsrc/src/commands_export.cpp @@ -0,0 +1,93 @@ +#include "pch.h" +#include "vcpkg_Commands.h" +#include "vcpkglib.h" +#include "vcpkg_System.h" +#include "vcpkg_Dependencies.h" +#include "vcpkg_Input.h" +#include "vcpkg_Util.h" +#include "Paragraphs.h" + +namespace vcpkg::Commands::Export +{ + using Dependencies::ExportPlanAction; + using Dependencies::RequestType; + using Dependencies::ExportPlanType; + + static void print_plan(const std::vector<ExportPlanAction>& plan) + { + static constexpr std::array<ExportPlanType, 2> order = { ExportPlanType::ALREADY_BUILT, ExportPlanType::PORT_AVAILABLE_BUT_NOT_BUILT }; + + std::map<ExportPlanType, std::vector<const ExportPlanAction*>> group_by_plan_type; + Util::group_by(plan, &group_by_plan_type, [](const ExportPlanAction& p) { return p.plan_type; }); + + for (const ExportPlanType plan_type : order) + { + auto it = group_by_plan_type.find(plan_type); + if (it == group_by_plan_type.cend()) + { + continue; + } + + std::vector<const ExportPlanAction*> cont = it->second; + std::sort(cont.begin(), cont.end(), &ExportPlanAction::compare_by_name); + const std::string as_string = Strings::join("\n", cont, [](const ExportPlanAction* p) + { + return Dependencies::to_output_string(p->request_type, p->spec.to_string()); + }); + + switch (plan_type) + { + case ExportPlanType::ALREADY_BUILT: + System::println("The following packages are already built and will be exported:\n%s", as_string); + continue; + case ExportPlanType::PORT_AVAILABLE_BUT_NOT_BUILT: + System::println("The following packages need to be built:\n%s", as_string); + continue; + default: + Checks::unreachable(VCPKG_LINE_INFO); + } + } + } + + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) + { + static const std::string OPTION_DRY_RUN = "--dry-run"; + // input sanitization + static const std::string example = Commands::Help::create_example_string("export zlib zlib:x64-windows curl boost"); + args.check_min_arg_count(1, example); + + const std::vector<PackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) + { + return Input::check_and_get_package_spec(arg, default_triplet, example); + }); + for (auto&& spec : specs) + Input::check_triplet(spec.triplet(), paths); + + const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({ OPTION_DRY_RUN }); + const bool dryRun = options.find(OPTION_DRY_RUN) != options.cend(); + + // create the plan + StatusParagraphs status_db = database_load_check(paths); + std::vector<ExportPlanAction> export_plan = Dependencies::create_export_plan(paths, specs, status_db); + Checks::check_exit(VCPKG_LINE_INFO, !export_plan.empty(), "Export plan cannot be empty"); + + print_plan(export_plan); + + const bool has_non_user_requested_packages = std::find_if(export_plan.cbegin(), export_plan.cend(), [](const ExportPlanAction& package)-> bool + { + return package.request_type != RequestType::USER_REQUESTED; + }) != export_plan.cend(); + + if (has_non_user_requested_packages) + { + System::println(System::Color::warning, "Additional packages (*) need to be exported to complete this operation."); + } + + if (dryRun) + { + Checks::exit_success(VCPKG_LINE_INFO); + } + + Checks::exit_success(VCPKG_LINE_INFO); + } +} diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp index 9514184ff..56bff7954 100644 --- a/toolsrc/src/vcpkg_Dependencies.cpp +++ b/toolsrc/src/vcpkg_Dependencies.cpp @@ -98,6 +98,38 @@ namespace vcpkg::Dependencies , plan_type(plan_type) , request_type(request_type) { } + bool ExportPlanAction::compare_by_name(const ExportPlanAction* left, const ExportPlanAction* right) + { + return left->spec.name() < right->spec.name(); + } + + ExportPlanAction::ExportPlanAction() : spec() + , any_paragraph() + , plan_type(ExportPlanType::UNKNOWN) + , request_type(RequestType::UNKNOWN) { } + + ExportPlanAction::ExportPlanAction(const PackageSpec& spec, const AnyParagraph& any_paragraph, const RequestType& request_type) : ExportPlanAction() + { + this->spec = spec; + this->request_type = request_type; + + if (auto p = any_paragraph.binary_paragraph.get()) + { + this->plan_type = ExportPlanType::ALREADY_BUILT; + this->any_paragraph.binary_paragraph = *p; + return; + } + + if (auto p = any_paragraph.source_paragraph.get()) + { + this->plan_type = ExportPlanType::PORT_AVAILABLE_BUT_NOT_BUILT; + this->any_paragraph.source_paragraph = *p; + return; + } + + this->plan_type = ExportPlanType::UNKNOWN; + } + bool RemovePlanAction::compare_by_name(const RemovePlanAction* left, const RemovePlanAction* right) { return left->spec.name() < right->spec.name(); @@ -204,4 +236,42 @@ namespace vcpkg::Dependencies const std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend()); return Graphs::topological_sort(specs, RemoveAdjacencyProvider{ status_db, installed_ports, specs_as_set }); } + + std::vector<ExportPlanAction> create_export_plan(const VcpkgPaths& paths, const std::vector<PackageSpec>& specs, const StatusParagraphs& status_db) + { + struct ExportAdjacencyProvider final : Graphs::AdjacencyProvider<PackageSpec, ExportPlanAction> + { + const VcpkgPaths& paths; + const StatusParagraphs& status_db; + const std::unordered_set<PackageSpec>& specs_as_set; + + ExportAdjacencyProvider(const VcpkgPaths& p, const StatusParagraphs& s, const std::unordered_set<PackageSpec>& specs_as_set) : paths(p) + , status_db(s) + , specs_as_set(specs_as_set) {} + + std::vector<PackageSpec> adjacency_list(const ExportPlanAction& plan) const override + { + return plan.any_paragraph.dependencies(plan.spec.triplet()); + } + + ExportPlanAction 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; + + Expected<BinaryParagraph> maybe_bpgh = Paragraphs::try_load_cached_package(paths, spec); + if (auto bpgh = maybe_bpgh.get()) + return ExportPlanAction{ spec,{ nullopt, *bpgh, nullopt }, request_type }; + + Expected<SourceParagraph> maybe_spgh = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(spec)); + if (auto spgh = maybe_spgh.get()) + return ExportPlanAction{ spec,{ nullopt, nullopt, *spgh }, request_type }; + + return ExportPlanAction{ spec ,{ nullopt, nullopt, nullopt }, request_type }; + } + }; + + const std::unordered_set<PackageSpec> specs_as_set(specs.cbegin(), specs.cend()); + std::vector<ExportPlanAction> toposort = Graphs::topological_sort(specs, ExportAdjacencyProvider{ paths, status_db, specs_as_set }); + return toposort; + } } diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj b/toolsrc/vcpkglib/vcpkglib.vcxproj index 1a8dd975b..8c34184c0 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj @@ -187,6 +187,7 @@ <ClCompile Include="..\src\commands_ci.cpp" /> <ClCompile Include="..\src\commands_depends.cpp" /> <ClCompile Include="..\src\commands_env.cpp" /> + <ClCompile Include="..\src\commands_export.cpp" /> <ClCompile Include="..\src\LineInfo.cpp" /> <ClCompile Include="..\src\ParagraphParseResult.cpp" /> <ClCompile Include="..\src\PostBuildLint_BuildInfo.cpp" /> diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters index b51958c57..0bda5cc77 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters @@ -183,6 +183,9 @@ <ClCompile Include="..\src\commands_depends.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\src\commands_export.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\include\SourceParagraph.h"> |
