diff options
| author | Robert Schumacher <roschuma@microsoft.com> | 2017-11-02 15:20:42 -0700 |
|---|---|---|
| committer | Robert Schumacher <roschuma@microsoft.com> | 2017-11-02 15:20:42 -0700 |
| commit | 6a91d1ece10ce0aeda89c44611d5335a07b8e40d (patch) | |
| tree | edeb7817fcfa3790ad68b785a3a19034b456b252 /toolsrc | |
| parent | 38136a2d05435dc1ef4d9604b1336509a6d667f8 (diff) | |
| download | vcpkg-6a91d1ece10ce0aeda89c44611d5335a07b8e40d.tar.gz vcpkg-6a91d1ece10ce0aeda89c44611d5335a07b8e40d.zip | |
[vcpkg] Refactor argument parsing to use common code paths.
Diffstat (limited to 'toolsrc')
31 files changed, 424 insertions, 287 deletions
diff --git a/toolsrc/include/vcpkg/base/span.h b/toolsrc/include/vcpkg/base/span.h index 6be546351..158f1ac74 100644 --- a/toolsrc/include/vcpkg/base/span.h +++ b/toolsrc/include/vcpkg/base/span.h @@ -57,4 +57,16 @@ namespace vcpkg {
return {v.data(), v.size()};
}
+
+ template<class T>
+ constexpr T* begin(Span<T> sp)
+ {
+ return sp.begin();
+ }
+
+ template<class T>
+ constexpr T* end(Span<T> sp)
+ {
+ return sp.end();
+ }
}
\ No newline at end of file diff --git a/toolsrc/include/vcpkg/base/util.h b/toolsrc/include/vcpkg/base/util.h index e67d38ad8..155b16cf7 100644 --- a/toolsrc/include/vcpkg/base/util.h +++ b/toolsrc/include/vcpkg/base/util.h @@ -30,7 +30,7 @@ namespace vcpkg::Util } template<class Cont, class Func> - using FmapOut = decltype(std::declval<Func>()(*begin(std::declval<Cont>()))); + using FmapOut = decltype(std::declval<Func&>()(*begin(std::declval<Cont&>()))); template<class Cont, class Func, class Out = FmapOut<Cont, Func>> std::vector<Out> fmap(Cont&& xs, Func&& f) diff --git a/toolsrc/include/vcpkg/build.h b/toolsrc/include/vcpkg/build.h index 94d9fddf5..824f3ccaf 100644 --- a/toolsrc/include/vcpkg/build.h +++ b/toolsrc/include/vcpkg/build.h @@ -18,10 +18,10 @@ namespace vcpkg::Build { namespace Command { - void perform_and_exit(const FullPackageSpec& full_spec, - const fs::path& port_dir, - const ParsedArguments& options, - const VcpkgPaths& paths); + void perform_and_exit_ex(const FullPackageSpec& full_spec, + const fs::path& port_dir, + const ParsedArguments& options, + const VcpkgPaths& paths); void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); } diff --git a/toolsrc/include/vcpkg/commands.h b/toolsrc/include/vcpkg/commands.h index d9ebad2c4..74fd80c03 100644 --- a/toolsrc/include/vcpkg/commands.h +++ b/toolsrc/include/vcpkg/commands.h @@ -23,16 +23,19 @@ namespace vcpkg::Commands namespace CI { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); } namespace Env { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet); } namespace Create { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } @@ -49,16 +52,19 @@ namespace vcpkg::Commands namespace Search { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } namespace List { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } namespace Owns { + extern const CommandStructure COMMAND_STRUCTURE; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } @@ -99,6 +105,7 @@ namespace vcpkg::Commands namespace Contact { + extern const CommandStructure COMMAND_STRUCTURE; const std::string& email(); void perform_and_exit(const VcpkgCmdArguments& args); } diff --git a/toolsrc/include/vcpkg/vcpkgcmdarguments.h b/toolsrc/include/vcpkg/vcpkgcmdarguments.h index e59979ad1..a832caf04 100644 --- a/toolsrc/include/vcpkg/vcpkgcmdarguments.h +++ b/toolsrc/include/vcpkg/vcpkgcmdarguments.h @@ -17,13 +17,47 @@ namespace vcpkg std::unordered_map<std::string, std::string> settings; }; - struct VcpkgCmdArguments + struct VcpkgPaths; + + struct CommandSwitch + { + std::string name; + CStringView short_help_text; + }; + + struct CommandSetting { + std::string name; + CStringView short_help_text; + }; + + struct CommandOptionsStructure + { + Span<const CommandSwitch> switches; + Span<const CommandSetting> settings; + }; + + struct CommandStructure + { + std::string example_text; + + size_t minimum_arity; + size_t maximum_arity; + + CommandOptionsStructure options; + + std::vector<std::string> (*valid_arguments)(const VcpkgPaths& paths); + }; + #if defined(_WIN32) - static VcpkgCmdArguments create_from_command_line(const int argc, const wchar_t* const* const argv); + using CommandLineCharType = wchar_t; #else - static VcpkgCmdArguments create_from_command_line(const int argc, const char* const* const argv); + using CommandLineCharType = char; #endif + + struct VcpkgCmdArguments + { + static VcpkgCmdArguments create_from_command_line(const int argc, const CommandLineCharType* const* const argv); static VcpkgCmdArguments create_from_arg_sequence(const std::string* arg_begin, const std::string* arg_end); std::unique_ptr<std::string> vcpkg_root_dir; @@ -35,32 +69,9 @@ namespace vcpkg std::string command; std::vector<std::string> command_arguments; - ParsedArguments check_and_get_optional_command_arguments(const std::vector<std::string>& valid_switches, - const std::vector<std::string>& valid_settings) const; - - void check_max_arg_count(const size_t expected_arg_count) const; - void check_max_arg_count(const size_t expected_arg_count, const std::string& example_text) const; - void check_min_arg_count(const size_t expected_arg_count) const; - void check_min_arg_count(const size_t expected_arg_count, const std::string& example_text) const; - void check_exact_arg_count(const size_t expected_arg_count) const; - void check_exact_arg_count(const size_t expected_arg_count, const std::string& example_text) const; + ParsedArguments parse_arguments(const CommandStructure& command_structure) const; private: std::unordered_map<std::string, Optional<std::string>> optional_command_arguments; }; - - struct VcpkgPaths; - - struct CommandStructure - { - CStringView example_text; - - size_t minimum_arity; - size_t maximum_arity; - - Span<const std::string> switches; - Span<const std::string> settings; - - std::vector<std::string> (*valid_arguments)(const VcpkgPaths& paths); - }; } diff --git a/toolsrc/src/tests.arguments.cpp b/toolsrc/src/tests.arguments.cpp index 25bf0f085..0f082222d 100644 --- a/toolsrc/src/tests.arguments.cpp +++ b/toolsrc/src/tests.arguments.cpp @@ -34,9 +34,12 @@ namespace UnitTest1 TEST_METHOD(create_from_arg_sequence_valued_options)
{
+ std::array<CommandSetting, 1> settings = { {{"--a", ""}} };
+ CommandStructure cmdstruct = { "", 0, SIZE_MAX, {{}, settings }, nullptr };
+
std::vector<std::string> t = {"--a=b", "command", "argument"};
auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size());
- auto opts = v.check_and_get_optional_command_arguments({}, {"--a"});
+ auto opts = v.parse_arguments(cmdstruct);
Assert::AreEqual("b", opts.settings["--a"].c_str());
Assert::AreEqual(size_t{1}, v.command_arguments.size());
Assert::AreEqual("argument", v.command_arguments[0].c_str());
@@ -45,9 +48,13 @@ namespace UnitTest1 TEST_METHOD(create_from_arg_sequence_valued_options2)
{
+ std::array<CommandSwitch, 2> switches = { {{"--a", ""}, {"--c", ""}} };
+ std::array<CommandSetting, 2> settings = { { {"--b", ""}, {"--d", ""}} };
+ CommandStructure cmdstruct = {"", 0, SIZE_MAX, {switches, settings}, nullptr};
+
std::vector<std::string> t = {"--a", "--b=c"};
auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size());
- auto opts = v.check_and_get_optional_command_arguments({"--a", "--c"}, {"--b", "--d"});
+ auto opts = v.parse_arguments(cmdstruct);
Assert::AreEqual("c", opts.settings["--b"].c_str());
Assert::IsTrue(opts.settings.find("--d") == opts.settings.end());
Assert::IsTrue(opts.switches.find("--a") != opts.switches.end());
diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index c59b6f7d1..8b4654aa8 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -28,10 +28,10 @@ namespace vcpkg::Build::Command static const std::string OPTION_CHECKS_ONLY = "--checks-only"; - void perform_and_exit(const FullPackageSpec& full_spec, - const fs::path& port_dir, - const ParsedArguments& options, - const VcpkgPaths& paths) + void perform_and_exit_ex(const FullPackageSpec& full_spec, + const fs::path& port_dir, + const ParsedArguments& options, + const VcpkgPaths& paths) { const PackageSpec& spec = full_spec.package_spec; if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY)) @@ -97,21 +97,32 @@ namespace vcpkg::Build::Command Checks::exit_success(VCPKG_LINE_INFO); } + static const std::array<CommandSwitch, 1> BUILD_SWITCHES = {{ + {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("build zlib:x64-windows"), + 1, + 1, + {BUILD_SWITCHES, {}}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { - static const std::string EXAMPLE = Help::create_example_string("build zlib:x64-windows"); // Build only takes a single package and all dependencies must already be installed - args.check_exact_arg_count(1, EXAMPLE); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const std::string command_argument = args.command_arguments.at(0); - const FullPackageSpec spec = Input::check_and_get_full_package_spec(command_argument, default_triplet, EXAMPLE); + const FullPackageSpec spec = + Input::check_and_get_full_package_spec(command_argument, default_triplet, COMMAND_STRUCTURE.example_text); Input::check_triplet(spec.package_spec.triplet(), paths); if (!spec.features.empty() && !GlobalState::feature_packages) { Checks::exit_with_message( VCPKG_LINE_INFO, "Feature packages are experimentally available under the --featurepackages flag."); } - const ParsedArguments options = args.check_and_get_optional_command_arguments({OPTION_CHECKS_ONLY}, {}); - perform_and_exit(spec, paths.port_dir(spec.package_spec), options, paths); + perform_and_exit_ex(spec, paths.port_dir(spec.package_spec), options, paths); } } diff --git a/toolsrc/src/vcpkg/commands.autocomplete.cpp b/toolsrc/src/vcpkg/commands.autocomplete.cpp index 410bfcd0d..0df7ec5eb 100644 --- a/toolsrc/src/vcpkg/commands.autocomplete.cpp +++ b/toolsrc/src/vcpkg/commands.autocomplete.cpp @@ -121,7 +121,6 @@ namespace vcpkg::Commands::Autocomplete static constexpr CommandEntry COMMANDS[] = { CommandEntry{"install", R"###(^install\s(.*\s|)(\S*)$)###", Install::COMMAND_STRUCTURE}, - CommandEntry{"install", R"###(^install\s(.*\s|)(\S*)$)###", Install::COMMAND_STRUCTURE}, CommandEntry{"edit", R"###(^edit\s(.*\s|)(\S*)$)###", Edit::COMMAND_STRUCTURE}, CommandEntry{"remove", R"###(^remove\s(.*\s|)(\S*)$)###", Remove::COMMAND_STRUCTURE}, CommandEntry{"integrate", R"###(^integrate(\s+)(\S*)$)###", Integrate::COMMAND_STRUCTURE}, @@ -137,11 +136,16 @@ namespace vcpkg::Commands::Autocomplete const bool is_option = Strings::case_insensitive_ascii_starts_with(prefix, "-"); if (is_option) { - results = Util::fmap(command.structure.switches, [](auto&& s) -> std::string { return s; }); + results = + Util::fmap(command.structure.options.switches, [](const CommandSwitch& s) { return s.name; }); + + auto settings = Util::fmap(command.structure.options.settings, [](auto&& s) { return s.name; }); + results.insert(results.end(), settings.begin(), settings.end()); } else { - results = command.structure.valid_arguments(paths); + if (command.structure.valid_arguments != nullptr) + results = command.structure.valid_arguments(paths); } Util::unstable_keep_if(results, [&](const std::string& s) { diff --git a/toolsrc/src/vcpkg/commands.buildexternal.cpp b/toolsrc/src/vcpkg/commands.buildexternal.cpp index 2cc7aabde..82d03db48 100644 --- a/toolsrc/src/vcpkg/commands.buildexternal.cpp +++ b/toolsrc/src/vcpkg/commands.buildexternal.cpp @@ -7,17 +7,23 @@ namespace vcpkg::Commands::BuildExternal { + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string(R"(build_external zlib2 C:\path\to\dir\with\controlfile\)"), + 2, + 2, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { - static const std::string EXAMPLE = - Help::create_example_string(R"(build_external zlib2 C:\path\to\dir\with\controlfile\)"); - args.check_exact_arg_count(2, EXAMPLE); - const FullPackageSpec spec = - Input::check_and_get_full_package_spec(args.command_arguments.at(0), default_triplet, EXAMPLE); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); + + const FullPackageSpec spec = Input::check_and_get_full_package_spec( + args.command_arguments.at(0), default_triplet, COMMAND_STRUCTURE.example_text); Input::check_triplet(spec.package_spec.triplet(), paths); - const ParsedArguments options = args.check_and_get_optional_command_arguments({}, {}); const fs::path port_dir = args.command_arguments.at(1); - Build::Command::perform_and_exit(spec, port_dir, options, paths); + Build::Command::perform_and_exit_ex(spec, port_dir, options, paths); } } diff --git a/toolsrc/src/vcpkg/commands.cache.cpp b/toolsrc/src/vcpkg/commands.cache.cpp index 64a3169b1..6fd123b7c 100644 --- a/toolsrc/src/vcpkg/commands.cache.cpp +++ b/toolsrc/src/vcpkg/commands.cache.cpp @@ -26,13 +26,19 @@ namespace vcpkg::Commands::Cache return output; } + const CommandStructure COMMAND_STRUCTURE = { + Strings::format( + "The argument should be a substring to search for, or no argument to display all cached libraries.\n%s", + Help::create_example_string("cache png")), + 0, + 1, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format( - "The argument should be a substring to search for, or no argument to display all cached libraries.\n%s", - Help::create_example_string("cache png")); - args.check_max_arg_count(1, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const std::vector<BinaryParagraph> binary_paragraphs = read_all_binary_paragraphs(paths); if (binary_paragraphs.empty()) diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index d012ff6dc..dce294004 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -58,13 +58,23 @@ namespace vcpkg::Commands::CI Install::InstallSummary summary; }; + static const std::string OPTION_EXCLUDE = "--exclude"; + + static const std::array<CommandSetting, 1> CI_SETTINGS = {{ + {OPTION_EXCLUDE, "Comma separated list of ports to skip"}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("ci x64-windows"), + 0, + SIZE_MAX, + {{}, CI_SETTINGS}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { - static const std::string OPTION_EXCLUDE = "--exclude"; - - static const std::string EXAMPLE = Help::create_example_string("ci x64-windows"); - - const ParsedArguments options = args.check_and_get_optional_command_arguments({}, {OPTION_EXCLUDE}); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const std::vector<std::string> exclusions = Strings::split(options.settings.at(OPTION_EXCLUDE), ","); const std::set<std::string> exclusions_set(exclusions.cbegin(), exclusions.cend()); diff --git a/toolsrc/src/vcpkg/commands.contact.cpp b/toolsrc/src/vcpkg/commands.contact.cpp index 5694c1fa6..5d62faeea 100644 --- a/toolsrc/src/vcpkg/commands.contact.cpp +++ b/toolsrc/src/vcpkg/commands.contact.cpp @@ -2,6 +2,7 @@ #include <vcpkg/base/system.h> #include <vcpkg/commands.h> +#include <vcpkg/help.h> namespace vcpkg::Commands::Contact { @@ -11,10 +12,17 @@ namespace vcpkg::Commands::Contact return S_EMAIL; } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("contact"), + 0, + 0, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args) { - args.check_exact_arg_count(0); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); System::println("Send an email to %s with any feedback.", email()); Checks::exit_success(VCPKG_LINE_INFO); diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 9d969ea28..15b10c7ea 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -13,7 +13,7 @@ namespace vcpkg::Commands Span<const PackageNameAndFunction<CommandTypeA>> get_available_commands_type_a() { static std::vector<PackageNameAndFunction<CommandTypeA>> t = { - {"install", &Install::perform_and_exit}, + PackageNameAndFunction<CommandTypeA>{"install", &Install::perform_and_exit}, {"ci", &CI::perform_and_exit}, {"remove", &Remove::perform_and_exit}, {"build", &Build::Command::perform_and_exit}, diff --git a/toolsrc/src/vcpkg/commands.create.cpp b/toolsrc/src/vcpkg/commands.create.cpp index f1acacd14..c7183d257 100644 --- a/toolsrc/src/vcpkg/commands.create.cpp +++ b/toolsrc/src/vcpkg/commands.create.cpp @@ -8,13 +8,18 @@ namespace vcpkg::Commands::Create { + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string( + R"###(create zlib2 http://zlib.net/zlib1211.zip "zlib1211-2.zip")###"), + 2, + 3, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Help::create_example_string( - R"###(create zlib2 http://zlib.net/zlib1211.zip "zlib1211-2.zip")###"); - args.check_max_arg_count(3, EXAMPLE); - args.check_min_arg_count(2, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const std::string port_name = args.command_arguments.at(0); const std::string url = args.command_arguments.at(1); diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index e5554f7e2..bb300d96e 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -9,11 +9,17 @@ namespace vcpkg::Commands::DependInfo { + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string(R"###(depend-info [pat])###"), + 0, + 1, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Help::create_example_string(R"###(depend-info [pat])###"); - args.check_max_arg_count(1, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); std::vector<std::unique_ptr<SourceControlFile>> source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index bf618e256..e40e394fb 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -34,11 +34,6 @@ namespace vcpkg::Commands::Edit static const std::string OPTION_BUILDTREES = "--buildtrees"; - static const std::array<std::string, 1> SWITCHES = { - OPTION_BUILDTREES, - }; - static const std::array<std::string, 0> SETTINGS; - static std::vector<std::string> valid_arguments(const VcpkgPaths& paths) { auto sources_and_errors = Paragraphs::try_load_all_ports(paths.get_filesystem(), paths.ports); @@ -47,12 +42,15 @@ namespace vcpkg::Commands::Edit [](auto&& pgh) -> std::string { return pgh->core_paragraph->name; }); } + static const std::array<CommandSwitch, 1> EDIT_SWITCHES = {{ + {OPTION_BUILDTREES, "Open editor into the port-specific buildtree subfolder"}, + }}; + const CommandStructure COMMAND_STRUCTURE = { - "edit zlib", + Help::create_example_string("edit zlib"), 1, 1, - SWITCHES, - SETTINGS, + {EDIT_SWITCHES, {}}, &valid_arguments, }; @@ -63,9 +61,7 @@ namespace vcpkg::Commands::Edit auto& fs = paths.get_filesystem(); - static const std::string EXAMPLE = Help::create_example_string("edit zlib"); - args.check_exact_arg_count(1, EXAMPLE); - const ParsedArguments options = args.check_and_get_optional_command_arguments({OPTION_BUILDTREES}, {}); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const std::string port_name = args.command_arguments.at(0); const fs::path portpath = paths.ports / port_name; diff --git a/toolsrc/src/vcpkg/commands.env.cpp b/toolsrc/src/vcpkg/commands.env.cpp index c0d26dac2..98b5aced9 100644 --- a/toolsrc/src/vcpkg/commands.env.cpp +++ b/toolsrc/src/vcpkg/commands.env.cpp @@ -7,11 +7,17 @@ namespace vcpkg::Commands::Env { + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("env --triplet x64-windows"), + 0, + 0, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { - static const std::string EXAMPLE = Help::create_example_string(R"(env --triplet x64-windows)"); - args.check_exact_arg_count(0, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, default_triplet); const Toolset& toolset = paths.get_toolset(pre_build_info.platform_toolset, pre_build_info.visual_studio_path); diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp index 51f6b9ad0..a5940ea1e 100644 --- a/toolsrc/src/vcpkg/commands.hash.cpp +++ b/toolsrc/src/vcpkg/commands.hash.cpp @@ -28,13 +28,18 @@ namespace vcpkg::Commands::Hash System::println(hash); } + const CommandStructure COMMAND_STRUCTURE = { + Strings::format("The argument should be a file path\n%s", + Help::create_example_string("hash boost_1_62_0.tar.bz2")), + 1, + 2, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args) { - static const std::string EXAMPLE = Strings::format("The argument should be a file path\n%s", - Help::create_example_string("hash boost_1_62_0.tar.bz2")); - args.check_min_arg_count(1, EXAMPLE); - args.check_max_arg_count(2, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); if (args.command_arguments.size() == 1) { diff --git a/toolsrc/src/vcpkg/commands.import.cpp b/toolsrc/src/vcpkg/commands.import.cpp index 5e74b6d94..24394207b 100644 --- a/toolsrc/src/vcpkg/commands.import.cpp +++ b/toolsrc/src/vcpkg/commands.import.cpp @@ -92,12 +92,18 @@ namespace vcpkg::Commands::Import fs.write_contents(control_file_path, Strings::serialize(control_file_data)); } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string( + R"(import C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)"), + 3, + 3, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Help::create_example_string( - R"(import C:\path\to\CONTROLfile C:\path\to\includedir C:\path\to\projectdir)"); - args.check_exact_arg_count(3, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const fs::path control_file_path(args.command_arguments[0]); const fs::path include_directory(args.command_arguments[1]); diff --git a/toolsrc/src/vcpkg/commands.integrate.cpp b/toolsrc/src/vcpkg/commands.integrate.cpp index 604bd2c6e..31b9ec722 100644 --- a/toolsrc/src/vcpkg/commands.integrate.cpp +++ b/toolsrc/src/vcpkg/commands.integrate.cpp @@ -333,10 +333,6 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console static const std::string PROJECT = "project"; } - static const std::array<std::string, 0> INSTALL_SWITCHES; - - static const std::array<std::string, 0> INSTALL_SETTINGS; - static std::vector<std::string> valid_arguments(const VcpkgPaths&) { return {Subcommand::INSTALL, Subcommand::REMOVE, Subcommand::PROJECT}; @@ -348,18 +344,13 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console INTEGRATE_COMMAND_HELPSTRING), 1, 1, - INSTALL_SWITCHES, - INSTALL_SETTINGS, + {}, &valid_arguments, }; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format("Commands:\n" - "%s", - INTEGRATE_COMMAND_HELPSTRING); - args.check_exact_arg_count(1, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); #if defined(_WIN32) if (args.command_arguments[0] == Subcommand::INSTALL) diff --git a/toolsrc/src/vcpkg/commands.list.cpp b/toolsrc/src/vcpkg/commands.list.cpp index 145d4c931..1f2387843 100644 --- a/toolsrc/src/vcpkg/commands.list.cpp +++ b/toolsrc/src/vcpkg/commands.list.cpp @@ -24,13 +24,23 @@ namespace vcpkg::Commands::List } } + static const std::array<CommandSwitch, 1> LIST_SWITCHES = {{ + {OPTION_FULLDESC, "Do not truncate long text"}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + Strings::format( + "The argument should be a substring to search for, or no argument to display all installed libraries.\n%s", + Help::create_example_string("list png")), + 0, + 1, + {LIST_SWITCHES, {}}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format( - "The argument should be a substring to search for, or no argument to display all installed libraries.\n%s", - Help::create_example_string("list png")); - args.check_max_arg_count(1, EXAMPLE); - const ParsedArguments options = args.check_and_get_optional_command_arguments({OPTION_FULLDESC}, {}); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const StatusParagraphs status_paragraphs = database_load_check(paths); std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_paragraphs); diff --git a/toolsrc/src/vcpkg/commands.owns.cpp b/toolsrc/src/vcpkg/commands.owns.cpp index b2db966e1..52249187b 100644 --- a/toolsrc/src/vcpkg/commands.owns.cpp +++ b/toolsrc/src/vcpkg/commands.owns.cpp @@ -23,13 +23,18 @@ namespace vcpkg::Commands::Owns } } } + const CommandStructure COMMAND_STRUCTURE = { + Strings::format("The argument should be a pattern to search for. %s", + Help::create_example_string("owns zlib.dll")), + 1, + 1, + {}, + nullptr, + }; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format("The argument should be a pattern to search for. %s", - Help::create_example_string("owns zlib.dll")); - args.check_exact_arg_count(1, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const StatusParagraphs status_db = database_load_check(paths); search_file(paths, args.command_arguments[0], status_db); diff --git a/toolsrc/src/vcpkg/commands.portsdiff.cpp b/toolsrc/src/vcpkg/commands.portsdiff.cpp index 5008f3e8a..0277c8bdb 100644 --- a/toolsrc/src/vcpkg/commands.portsdiff.cpp +++ b/toolsrc/src/vcpkg/commands.portsdiff.cpp @@ -114,13 +114,18 @@ namespace vcpkg::Commands::PortsDiff VCPKG_LINE_INFO, output.output == VALID_COMMIT_OUTPUT, "Invalid commit id %s", git_commit_id); } + const CommandStructure COMMAND_STRUCTURE = { + Strings::format("The argument should be a branch/tag/hash to checkout.\n%s", + Help::create_example_string("portsdiff mybranchname")), + 1, + 2, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format("The argument should be a branch/tag/hash to checkout.\n%s", - Help::create_example_string("portsdiff mybranchname")); - args.check_min_arg_count(1, EXAMPLE); - args.check_max_arg_count(2, EXAMPLE); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); const fs::path& git_exe = paths.get_git_exe(); diff --git a/toolsrc/src/vcpkg/commands.search.cpp b/toolsrc/src/vcpkg/commands.search.cpp index ad3046e6d..01291ddfb 100644 --- a/toolsrc/src/vcpkg/commands.search.cpp +++ b/toolsrc/src/vcpkg/commands.search.cpp @@ -79,14 +79,24 @@ namespace vcpkg::Commands::Search } } + static std::array<CommandSwitch, 2> SEARCH_SWITCHES = {{ + {OPTION_GRAPH, "Open editor into the port-specific buildtree subfolder"}, + {OPTION_FULLDESC, "Do not truncate long text"}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + Strings::format( + "The argument should be a substring to search for, or no argument to display all libraries.\n%s", + Help::create_example_string("search png")), + 0, + 1, + {SEARCH_SWITCHES, {}}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - static const std::string EXAMPLE = Strings::format( - "The argument should be a substring to search for, or no argument to display all libraries.\n%s", - Help::create_example_string("search png")); - args.check_max_arg_count(1, EXAMPLE); - const ParsedArguments options = - args.check_and_get_optional_command_arguments({OPTION_GRAPH, OPTION_FULLDESC}, {}); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const bool full_description = Util::Sets::contains(options.switches, OPTION_FULLDESC); auto source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); diff --git a/toolsrc/src/vcpkg/commands.version.cpp b/toolsrc/src/vcpkg/commands.version.cpp index e8756a77d..3f44cf1a2 100644 --- a/toolsrc/src/vcpkg/commands.version.cpp +++ b/toolsrc/src/vcpkg/commands.version.cpp @@ -2,6 +2,7 @@ #include <vcpkg/base/system.h> #include <vcpkg/commands.h> +#include <vcpkg/help.h> #include <vcpkg/metrics.h> #define STRINGIFY(...) #__VA_ARGS__ @@ -61,11 +62,17 @@ namespace vcpkg::Commands::Version } } } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("version"), + 0, + 0, + {}, + nullptr, + }; void perform_and_exit(const VcpkgCmdArguments& args) { - args.check_exact_arg_count(0); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); System::println("Vcpkg package management program version %s\n" "\n" diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index eb4f5db3c..bbeecefed 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -257,51 +257,57 @@ namespace vcpkg::Export std::vector<PackageSpec> specs; }; + static const std::string OPTION_DRY_RUN = "--dry-run"; + static const std::string OPTION_RAW = "--raw"; + static const std::string OPTION_NUGET = "--nuget"; + static const std::string OPTION_IFW = "--ifw"; + static const std::string OPTION_ZIP = "--zip"; + static const std::string OPTION_SEVEN_ZIP = "--7zip"; + static const std::string OPTION_NUGET_ID = "--nuget-id"; + static const std::string OPTION_NUGET_VERSION = "--nuget-version"; + static const std::string OPTION_IFW_REPOSITORY_URL = "--ifw-repository-url"; + static const std::string OPTION_IFW_PACKAGES_DIR_PATH = "--ifw-packages-directory-path"; + static const std::string OPTION_IFW_REPOSITORY_DIR_PATH = "--ifw-repository-directory-path"; + static const std::string OPTION_IFW_CONFIG_FILE_PATH = "--ifw-configuration-file-path"; + static const std::string OPTION_IFW_INSTALLER_FILE_PATH = "--ifw-installer-file-path"; + + static const std::array<CommandSwitch, 6> EXPORT_SWITCHES = {{ + {OPTION_DRY_RUN, "Do not actually export"}, + {OPTION_RAW, "Export to an uncompressed directory"}, + {OPTION_NUGET, "Export a NuGet package"}, + {OPTION_IFW, "Export to an IFW-based installer"}, + {OPTION_ZIP, "Export to a zip file"}, + {OPTION_SEVEN_ZIP, "Export to a 7zip (.7z) file"}, + }}; + static const std::array<CommandSetting, 7> EXPORT_SETTINGS = {{ + {OPTION_NUGET_ID, "Specify the id for the exported NuGet package"}, + {OPTION_NUGET_VERSION, "Specify the version for the exported NuGet package"}, + {OPTION_IFW_REPOSITORY_URL, ""}, + {OPTION_IFW_PACKAGES_DIR_PATH, ""}, + {OPTION_IFW_REPOSITORY_DIR_PATH, ""}, + {OPTION_IFW_CONFIG_FILE_PATH, ""}, + {OPTION_IFW_INSTALLER_FILE_PATH, ""}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("export zlib zlib:x64-windows boost --nuget"), + 0, + SIZE_MAX, + {EXPORT_SWITCHES, EXPORT_SETTINGS}, + nullptr, + }; + static ExportArguments handle_export_command_arguments(const VcpkgCmdArguments& args, const Triplet& default_triplet) { ExportArguments ret; - static const std::string OPTION_DRY_RUN = "--dry-run"; - static const std::string OPTION_RAW = "--raw"; - static const std::string OPTION_NUGET = "--nuget"; - static const std::string OPTION_IFW = "--ifw"; - static const std::string OPTION_ZIP = "--zip"; - static const std::string OPTION_SEVEN_ZIP = "--7zip"; - static const std::string OPTION_NUGET_ID = "--nuget-id"; - static const std::string OPTION_NUGET_VERSION = "--nuget-version"; - static const std::string OPTION_IFW_REPOSITORY_URL = "--ifw-repository-url"; - static const std::string OPTION_IFW_PACKAGES_DIR_PATH = "--ifw-packages-directory-path"; - static const std::string OPTION_IFW_REPOSITORY_DIR_PATH = "--ifw-repository-directory-path"; - static const std::string OPTION_IFW_CONFIG_FILE_PATH = "--ifw-configuration-file-path"; - static const std::string OPTION_IFW_INSTALLER_FILE_PATH = "--ifw-installer-file-path"; + const auto options = args.parse_arguments(COMMAND_STRUCTURE); // input sanitization - static const std::string EXAMPLE = Help::create_example_string("export zlib zlib:x64-windows boost --nuget"); - args.check_min_arg_count(1, EXAMPLE); - ret.specs = Util::fmap(args.command_arguments, [&](auto&& arg) { - return Input::check_and_get_package_spec(arg, default_triplet, EXAMPLE); + return Input::check_and_get_package_spec(arg, default_triplet, COMMAND_STRUCTURE.example_text); }); - - const auto options = args.check_and_get_optional_command_arguments( - { - OPTION_DRY_RUN, - OPTION_RAW, - OPTION_NUGET, - OPTION_IFW, - OPTION_ZIP, - OPTION_SEVEN_ZIP, - }, - { - OPTION_NUGET_ID, - OPTION_NUGET_VERSION, - OPTION_IFW_REPOSITORY_URL, - OPTION_IFW_PACKAGES_DIR_PATH, - OPTION_IFW_REPOSITORY_DIR_PATH, - OPTION_IFW_CONFIG_FILE_PATH, - OPTION_IFW_INSTALLER_FILE_PATH, - }); ret.dry_run = options.switches.find(OPTION_DRY_RUN) != options.switches.cend(); ret.raw = options.switches.find(OPTION_RAW) != options.switches.cend(); ret.nuget = options.switches.find(OPTION_NUGET) != options.switches.cend(); @@ -313,7 +319,7 @@ namespace vcpkg::Export { System::println(System::Color::error, "Must provide at least one export type: --raw --nuget --ifw --zip --7zip"); - System::print(EXAMPLE); + System::print(COMMAND_STRUCTURE.example_text); Checks::exit_fail(VCPKG_LINE_INFO); } diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 8783833f2..5d4cf99a4 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -91,10 +91,17 @@ namespace vcpkg::Help System::println(create_example_string(command_and_arguments)); } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("help"), + 0, + 1, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - args.check_max_arg_count(1); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); if (args.command_arguments.empty()) { diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index b1f722d59..20ffd3164 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -535,13 +535,13 @@ namespace vcpkg::Install static const std::string OPTION_RECURSE = "--recurse"; static const std::string OPTION_KEEP_GOING = "--keep-going"; - static const std::array<std::string, 5> INSTALL_SWITCHES = { - OPTION_DRY_RUN, - OPTION_USE_HEAD_VERSION, - OPTION_NO_DOWNLOADS, - OPTION_RECURSE, - OPTION_KEEP_GOING, - }; + static const std::array<CommandSwitch, 5> INSTALL_SWITCHES = {{ + {OPTION_DRY_RUN, "Do not actually build or install"}, + {OPTION_USE_HEAD_VERSION, "Install the libraries on the command line using the latest upstream sources"}, + {OPTION_NO_DOWNLOADS, "Do not download new sources"}, + {OPTION_RECURSE, "Allow removal of packages as part of installation"}, + {OPTION_KEEP_GOING, "Continue installing packages on failure"}, + }}; static const std::array<std::string, 0> INSTALL_SETTINGS; std::vector<std::string> get_all_port_names(const VcpkgPaths& paths) @@ -553,22 +553,20 @@ namespace vcpkg::Install } const CommandStructure COMMAND_STRUCTURE = { - "install zlib zlib:x64-windows curl boost", + Help::create_example_string("install zlib zlib:x64-windows curl boost"), 1, SIZE_MAX, - INSTALL_SWITCHES, - INSTALL_SETTINGS, + {INSTALL_SWITCHES, {}}, &get_all_port_names, }; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { // input sanitization - static const std::string EXAMPLE = Help::create_example_string("install zlib zlib:x64-windows curl boost"); - args.check_min_arg_count(1, EXAMPLE); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) { - return Input::check_and_get_full_package_spec(arg, default_triplet, EXAMPLE); + return Input::check_and_get_full_package_spec(arg, default_triplet, COMMAND_STRUCTURE.example_text); }); for (auto&& spec : specs) @@ -581,8 +579,6 @@ namespace vcpkg::Install } } - const ParsedArguments options = args.check_and_get_optional_command_arguments( - {OPTION_DRY_RUN, OPTION_USE_HEAD_VERSION, OPTION_NO_DOWNLOADS, OPTION_RECURSE, OPTION_KEEP_GOING}, {}); const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION)); const bool no_downloads = Util::Sets::contains(options.switches, (OPTION_NO_DOWNLOADS)); diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index 156f23003..7f40fb16e 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -169,14 +169,13 @@ namespace vcpkg::Remove static const std::string OPTION_DRY_RUN = "--dry-run"; static const std::string OPTION_OUTDATED = "--outdated"; - static const std::array<std::string, 5> SWITCHES = { - OPTION_PURGE, - OPTION_NO_PURGE, - OPTION_RECURSE, - OPTION_DRY_RUN, - OPTION_OUTDATED, - }; - static const std::array<std::string, 0> SETTINGS; + static const std::array<CommandSwitch, 5> SWITCHES = {{ + {OPTION_PURGE, "Remove the cached copy of the package (default)"}, + {OPTION_NO_PURGE, "Do not remove the cached copy of the package"}, + {OPTION_RECURSE, "Allow removal of packages not explicitly specified on the command line"}, + {OPTION_DRY_RUN, "Print the packages to be removed, but do not remove them"}, + {OPTION_OUTDATED, "Select all packages with versions that do not match the portfiles"}, + }}; static std::vector<std::string> valid_arguments(const VcpkgPaths& paths) { @@ -187,25 +186,26 @@ namespace vcpkg::Remove } const CommandStructure COMMAND_STRUCTURE = { - "remove zlib zlib:x64-windows curl boost", - 1, + Help::create_example_string("remove zlib zlib:x64-windows curl boost"), + 0, SIZE_MAX, - SWITCHES, - SETTINGS, + {SWITCHES, {}}, &valid_arguments, }; void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { - static const std::string EXAMPLE = Help::create_example_string("remove zlib zlib:x64-windows curl boost"); - const ParsedArguments options = args.check_and_get_optional_command_arguments( - {OPTION_PURGE, OPTION_NO_PURGE, OPTION_RECURSE, OPTION_DRY_RUN, OPTION_OUTDATED}, {}); + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); StatusParagraphs status_db = database_load_check(paths); std::vector<PackageSpec> specs; if (Util::Sets::contains(options.switches, OPTION_OUTDATED)) { - args.check_exact_arg_count(0, EXAMPLE); + if (args.command_arguments.size() != 0) + { + 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(paths, status_db), [](auto&& outdated) { return outdated.spec; }); @@ -217,9 +217,13 @@ namespace vcpkg::Remove } else { - args.check_min_arg_count(1, EXAMPLE); + if (args.command_arguments.size() < 1) + { + System::println(System::Color::error, "Error: 'remove' accepts either libraries or '--outdated'"); + Checks::exit_fail(VCPKG_LINE_INFO); + } specs = Util::fmap(args.command_arguments, [&](auto&& arg) { - return Input::check_and_get_package_spec(arg, default_triplet, EXAMPLE); + return Input::check_and_get_package_spec(arg, default_triplet, COMMAND_STRUCTURE.example_text); }); for (auto&& spec : specs) @@ -231,7 +235,7 @@ namespace vcpkg::Remove if (purge_was_passed && no_purge_was_passed) { System::println(System::Color::error, "Error: cannot specify both --no-purge and --purge."); - System::print(EXAMPLE); + System::print(COMMAND_STRUCTURE.example_text); Checks::exit_fail(VCPKG_LINE_INFO); } const Purge purge = to_purge(purge_was_passed || !no_purge_was_passed); diff --git a/toolsrc/src/vcpkg/update.cpp b/toolsrc/src/vcpkg/update.cpp index 7d565251e..61a3f89c5 100644 --- a/toolsrc/src/vcpkg/update.cpp +++ b/toolsrc/src/vcpkg/update.cpp @@ -38,10 +38,17 @@ namespace vcpkg::Update return output; } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("update"), + 0, + 0, + {}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { - args.check_exact_arg_count(0); - args.check_and_get_optional_command_arguments({}, {}); + args.parse_arguments(COMMAND_STRUCTURE); System::println("Using local portfile versions. To update the local portfiles, use `git pull`."); const StatusParagraphs status_db = database_load_check(paths); diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 209f6a3f2..35cdbc12e 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -45,11 +45,8 @@ namespace vcpkg option_field = new_setting; } -#if defined(_WIN32) - VcpkgCmdArguments VcpkgCmdArguments::create_from_command_line(const int argc, const wchar_t* const* const argv) -#else - VcpkgCmdArguments VcpkgCmdArguments::create_from_command_line(const int argc, const char* const* const argv) -#endif + VcpkgCmdArguments VcpkgCmdArguments::create_from_command_line(const int argc, + const CommandLineCharType* const* const argv) { std::vector<std::string> v; for (int i = 1; i < argc; ++i) @@ -158,46 +155,83 @@ namespace vcpkg return args; } - ParsedArguments VcpkgCmdArguments::check_and_get_optional_command_arguments( - const std::vector<std::string>& valid_switches, const std::vector<std::string>& valid_settings) const + ParsedArguments VcpkgCmdArguments::parse_arguments(const CommandStructure& command_structure) const { bool failed = false; ParsedArguments output; + const size_t actual_arg_count = command_arguments.size(); + + if (command_structure.minimum_arity == command_structure.maximum_arity) + { + if (actual_arg_count != command_structure.minimum_arity) + { + System::println(System::Color::error, + "Error: '%s' requires %u arguments, but %u were provided.", + this->command, + command_structure.minimum_arity, + actual_arg_count); + failed = true; + } + } + else + { + if (actual_arg_count < command_structure.minimum_arity) + { + System::println(System::Color::error, + "Error: '%s' requires at least %u arguments, but %u were provided", + this->command, + command_structure.minimum_arity, + actual_arg_count); + failed = true; + } + if (actual_arg_count > command_structure.maximum_arity) + { + System::println(System::Color::error, + "Error: '%s' requires at most %u arguments, but %u were provided", + this->command, + command_structure.maximum_arity, + actual_arg_count); + failed = true; + } + } + auto options_copy = this->optional_command_arguments; - for (const std::string& option : valid_switches) + for (auto&& option : command_structure.options.switches) { - const auto it = options_copy.find(option); + const auto it = options_copy.find(option.name); if (it != options_copy.end()) { if (it->second.has_value()) { // Having a string value indicates it was passed like '--a=xyz' - System::println(System::Color::error, "The option '%s' does not accept an argument.", option); + System::println( + System::Color::error, "Error: The option '%s' does not accept an argument.", option.name); failed = true; } else { - output.switches.insert(option); + output.switches.insert(option.name); options_copy.erase(it); } } } - for (const std::string& option : valid_settings) + for (auto&& option : command_structure.options.settings) { - const auto it = options_copy.find(option); + const auto it = options_copy.find(option.name); if (it != options_copy.end()) { if (!it->second.has_value()) { // Not having a string value indicates it was passed like '--a' - System::println(System::Color::error, "The option '%s' must be passed an argument.", option); + System::println( + System::Color::error, "Error: The option '%s' must be passed an argument.", option.name); failed = true; } else { - output.settings.emplace(option, it->second.value_or_exit(VCPKG_LINE_INFO)); + output.settings.emplace(option.name, it->second.value_or_exit(VCPKG_LINE_INFO)); options_copy.erase(it); } } @@ -210,83 +244,32 @@ namespace vcpkg { System::println(" %s", option.first); } - System::println("\nValid options are:", this->command); - for (auto&& option : valid_switches) + System::println(); + failed = true; + } + + if (failed) + { + if (!command_structure.example_text.empty()) { - System::println(" %s", option); + System::println("%s", command_structure.example_text); } - for (auto&& option : valid_settings) + + System::println("Options:", this->command); + for (auto&& option : command_structure.options.switches) { - System::println(" %s=...", option); + System::println(" %-40s %s", option.name, option.short_help_text); + } + for (auto&& option : command_structure.options.settings) + { + System::println(" %-40s %s", (option.name + "=..."), option.short_help_text); } System::println(" --triplet <t>"); System::println(" --vcpkg-root <path>"); Checks::exit_fail(VCPKG_LINE_INFO); } - if (failed) Checks::exit_fail(VCPKG_LINE_INFO); return output; } - - void VcpkgCmdArguments::check_max_arg_count(const size_t expected_arg_count) const - { - return check_max_arg_count(expected_arg_count, ""); - } - - void VcpkgCmdArguments::check_min_arg_count(const size_t expected_arg_count) const - { - return check_min_arg_count(expected_arg_count, ""); - } - - void VcpkgCmdArguments::check_exact_arg_count(const size_t expected_arg_count) const - { - return check_exact_arg_count(expected_arg_count, ""); - } - - void VcpkgCmdArguments::check_max_arg_count(const size_t expected_arg_count, const std::string& example_text) const - { - const size_t actual_arg_count = command_arguments.size(); - if (actual_arg_count > expected_arg_count) - { - System::println(System::Color::error, - "Error: `%s` requires at most %u arguments, but %u were provided", - this->command, - expected_arg_count, - actual_arg_count); - System::print(example_text); - Checks::exit_fail(VCPKG_LINE_INFO); - } - } - - void VcpkgCmdArguments::check_min_arg_count(const size_t expected_arg_count, const std::string& example_text) const - { - const size_t actual_arg_count = command_arguments.size(); - if (actual_arg_count < expected_arg_count) - { - System::println(System::Color::error, - "Error: `%s` requires at least %u arguments, but %u were provided", - this->command, - expected_arg_count, - actual_arg_count); - System::print(example_text); - Checks::exit_fail(VCPKG_LINE_INFO); - } - } - - void VcpkgCmdArguments::check_exact_arg_count(const size_t expected_arg_count, - const std::string& example_text) const - { - const size_t actual_arg_count = command_arguments.size(); - if (actual_arg_count != expected_arg_count) - { - System::println(System::Color::error, - "Error: `%s` requires %u arguments, but %u were provided", - this->command, - expected_arg_count, - actual_arg_count); - System::print(example_text); - Checks::exit_fail(VCPKG_LINE_INFO); - } - } } |
