diff options
| author | Alexander Karatarakis <alkarata@microsoft.com> | 2016-09-18 20:50:08 -0700 |
|---|---|---|
| committer | Alexander Karatarakis <alkarata@microsoft.com> | 2016-09-18 20:54:03 -0700 |
| commit | ccca198c1b1730b0241911cb56dc8e3504958b2a (patch) | |
| tree | a2dd9b8b087a09afdcecc5cbb3377bed15127eb2 /toolsrc/src/vcpkg_cmd_arguments.cpp | |
| download | vcpkg-ccca198c1b1730b0241911cb56dc8e3504958b2a.tar.gz vcpkg-ccca198c1b1730b0241911cb56dc8e3504958b2a.zip | |
Initial commit
Diffstat (limited to 'toolsrc/src/vcpkg_cmd_arguments.cpp')
| -rw-r--r-- | toolsrc/src/vcpkg_cmd_arguments.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/toolsrc/src/vcpkg_cmd_arguments.cpp b/toolsrc/src/vcpkg_cmd_arguments.cpp new file mode 100644 index 000000000..4cfc12716 --- /dev/null +++ b/toolsrc/src/vcpkg_cmd_arguments.cpp @@ -0,0 +1,255 @@ +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include "vcpkg_cmd_arguments.h" +#include "vcpkg_Commands.h" +#include "vcpkg_Graphs.h" +#include <unordered_set> +#include "metrics.h" +#include "vcpkg.h" +#include "vcpkg_System.h" + +namespace vcpkg +{ + static void parse_value( + const std::string* arg_begin, + const std::string* arg_end, + const std::string& option_name, + std::unique_ptr<std::string>& option_field) + { + if (arg_begin == arg_end) + { + System::println(System::color::error, "Error: expected value after %s", option_name); + TrackProperty("error", "error option name"); + print_usage(); + exit(EXIT_FAILURE); + } + + if (option_field != nullptr) + { + System::println(System::color::error, "Error: %s specified multiple times", option_name); + TrackProperty("error", "error option specified multiple times"); + print_usage(); + exit(EXIT_FAILURE); + } + + option_field = std::make_unique<std::string>(*arg_begin); + } + + static void parse_switch( + opt_bool new_setting, + const std::string& option_name, + opt_bool& option_field) + { + if (option_field != opt_bool::unspecified && option_field != new_setting) + { + System::println(System::color::error, "Error: conflicting values specified for --%s", option_name); + TrackProperty("error", "error conflicting switches"); + print_usage(); + exit(EXIT_FAILURE); + } + option_field = new_setting; + } + + vcpkg_cmd_arguments vcpkg_cmd_arguments::create_from_command_line(const int argc, const wchar_t* const* const argv) + { + std::vector<std::string> v; + for (int i = 1; i < argc; ++i) + { + v.push_back(Strings::utf16_to_utf8(argv[i])); + } + + return vcpkg_cmd_arguments::create_from_arg_sequence(v.data(), v.data() + v.size()); + } + + vcpkg_cmd_arguments vcpkg_cmd_arguments::create_from_arg_sequence(const std::string* arg_begin, const std::string* arg_end) + { + vcpkg_cmd_arguments args; + + for (; arg_begin != arg_end; ++arg_begin) + { + std::string arg = *arg_begin; + + if (arg.empty()) + { + continue; + } + + if (arg[0] == '-' && arg[1] != '-') + { + System::println(System::color::error, "Error: short options are not supported: %s", arg); + TrackProperty("error", "error short options are not supported"); + exit(EXIT_FAILURE); + } + + if (arg[0] == '-' && arg[1] == '-') + { + // command switch + if (arg == "--vcpkg-root") + { + ++arg_begin; + parse_value(arg_begin, arg_end, "--vcpkg-root", args.vcpkg_root_dir); + continue; + } + if (arg == "--triplet") + { + ++arg_begin; + parse_value(arg_begin, arg_end, "--triplet", args.target_triplet); + continue; + } + if (arg == "--debug") + { + parse_switch(opt_bool::enabled, "debug", args.debug); + continue; + } + if (arg == "--sendmetrics") + { + parse_switch(opt_bool::enabled, "sendmetrics", args.sendmetrics); + continue; + } + if (arg == "--printmetrics") + { + parse_switch(opt_bool::enabled, "printmetrics", args.printmetrics); + continue; + } + if (arg == "--no-sendmetrics") + { + parse_switch(opt_bool::disabled, "sendmetrics", args.sendmetrics); + continue; + } + if (arg == "--no-printmetrics") + { + parse_switch(opt_bool::disabled, "printmetrics", args.printmetrics); + continue; + } + + args.optional_command_arguments.insert(arg); + continue; + } + + if (args.command.empty()) + { + args.command = arg; + } + else + { + args.command_arguments.push_back(arg); + } + } + + return args; + } + + std::unordered_set<std::string> vcpkg_cmd_arguments::check_and_get_optional_command_arguments(const std::vector<std::string>& valid_options) const + { + std::unordered_set<std::string> output; + auto options_copy = this->optional_command_arguments; + for (const std::string& option : valid_options) + { + auto it = options_copy.find(option); + if (it != options_copy.end()) + { + output.insert(option); + options_copy.erase(it); + } + } + + if (!options_copy.empty()) + { + System::println(System::color::error, "Unknown option(s) for command '%s':", this->command); + for (const std::string& option : options_copy) + { + System::println(option.c_str()); + } + exit(EXIT_FAILURE); + } + + return output; + } + + void vcpkg_cmd_arguments::check_max_args(size_t arg_count, const char* example_text) const + { + if (command_arguments.size() > arg_count) + { + System::println(System::color::error, "Error: too many arguments to command %s", command); + if (example_text != nullptr) + print_example(example_text); + else + print_usage(); + exit(EXIT_FAILURE); + } + } + + std::vector<package_spec> vcpkg_cmd_arguments::extract_package_specs_with_unmet_dependencies(const vcpkg_paths& paths, const triplet& default_target_triplet, const StatusParagraphs& status_db) const + { + std::vector<package_spec> specs = parse_all_arguments_as_package_specs(default_target_triplet); + std::unordered_set<package_spec> had_its_immediate_dependencies_added; + Graphs::Graph<package_spec> graph; + graph.add_vertices(specs); + + while (!specs.empty()) + { + package_spec spec = specs.back(); + specs.pop_back(); + + if (had_its_immediate_dependencies_added.find(spec) != had_its_immediate_dependencies_added.end()) + { + continue; + } + + std::vector<std::string> dependencies_as_string = get_unmet_package_dependencies(paths, spec, status_db); + + for (const std::string& dep_as_string : dependencies_as_string) + { + package_spec current_dep = {dep_as_string, spec.target_triplet}; + auto it = status_db.find(current_dep.name, current_dep.target_triplet); + if (it != status_db.end() && (*it)->want == want_t::install) + { + continue; + } + + graph.add_edge(spec, current_dep); + if (had_its_immediate_dependencies_added.find(current_dep) == had_its_immediate_dependencies_added.end()) + { + specs.push_back(std::move(current_dep)); + } + } + + had_its_immediate_dependencies_added.insert(spec); + } + + return graph.find_topological_sort(); + } + + std::vector<package_spec> vcpkg_cmd_arguments::parse_all_arguments_as_package_specs(const triplet& default_target_triplet, const char* example_text) const + { + size_t arg_count = command_arguments.size(); + if (arg_count < 1) + { + System::println(System::color::error, "Error: %s requires one or more package specifiers", this->command); + if (example_text == nullptr) + print_example(Strings::format("%s zlib zlib:x64-windows curl boost", this->command).c_str()); + else + print_example(example_text); + exit(EXIT_FAILURE); + } + std::vector<package_spec> specs; + specs.reserve(arg_count); + + for (const std::string& command_argument : command_arguments) + { + expected<package_spec> current_spec = vcpkg::parse(command_argument, default_target_triplet); + if (auto spec = current_spec.get()) + { + specs.push_back(std::move(*spec)); + } + else + { + System::println(System::color::error, "Error: %s: %s", current_spec.error_code().message(), command_argument); + print_example(Strings::format("%s zlib:x64-windows", this->command).c_str()); + exit(EXIT_FAILURE); + } + } + + return specs; + } +} |
