aboutsummaryrefslogtreecommitdiff
path: root/toolsrc/src/vcpkg_cmd_arguments.cpp
diff options
context:
space:
mode:
authorAlexander Karatarakis <alkarata@microsoft.com>2016-09-18 20:50:08 -0700
committerAlexander Karatarakis <alkarata@microsoft.com>2016-09-18 20:54:03 -0700
commitccca198c1b1730b0241911cb56dc8e3504958b2a (patch)
treea2dd9b8b087a09afdcecc5cbb3377bed15127eb2 /toolsrc/src/vcpkg_cmd_arguments.cpp
downloadvcpkg-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.cpp255
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;
+ }
+}