From c4d8116334a3fb235f729566b1095112aa2ac9cb Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 29 Mar 2018 16:25:36 +0200 Subject: Setup config subcommand handling infrastructure --- bdep/bdep.cxx | 25 ++++---------------- bdep/config.cli | 18 ++++++++++---- bdep/config.cxx | 72 +++++++++++++++++++++++++++++++++++++++++++++++++------- bdep/init.cxx | 2 -- bdep/utility.hxx | 13 ++++++++-- bdep/utility.txx | 33 +++++++++++++++++++++++++- 6 files changed, 126 insertions(+), 37 deletions(-) diff --git a/bdep/bdep.cxx b/bdep/bdep.cxx index 1f9c2ca..2541325 100644 --- a/bdep/bdep.cxx +++ b/bdep/bdep.cxx @@ -185,18 +185,7 @@ try // The next argument should be a command. // - if (!scan.more ()) - fail << "bdep command expected" << - info << "run 'bdep help' for more information"; - - int cmd_argc (2); - char* cmd_argv[] {argv[0], const_cast (scan.next ())}; - commands cmd; - cmd.parse (cmd_argc, cmd_argv, true, unknown_mode::stop); - - if (cmd_argc != 1) - fail << "unknown bdep command/option '" << cmd_argv[1] << "'" << - info << "run 'bdep help' for more information"; + commands cmd (parse_command (scan, "bdep command", "bdep help")); // If the command is 'help', then what's coming next is another command. // Parse it into cmd so that we only need to check for each command in one @@ -211,18 +200,14 @@ try if (args.more ()) { - cmd_argc = 2; - cmd_argv[1] = const_cast (args.next ()); + const char* a (args.next ()); - // First see if this is a command. - // cmd = commands (); // Clear the help option. - cmd.parse (cmd_argc, cmd_argv, true, unknown_mode::stop); - // If not, then it got to be a help topic. + // If not a command, then it got to be a help topic. // - if (cmd_argc != 1) - return help (ho, cmd_argv[1], nullptr); + if (!parse_command (a, cmd)) + return help (ho, a, nullptr); } else return help (ho, "", nullptr); diff --git a/bdep/config.cli b/bdep/config.cli index 067fd69..62ef5da 100644 --- a/bdep/config.cli +++ b/bdep/config.cli @@ -40,7 +40,12 @@ namespace bdep The \cb{config} command provides the following subcommands for managing project's build configurations. If no project directory is specified, - then the current working directory is assumed. + then the current working directory is assumed." + } + + class cmd_config_subcommands + { + "\h|CONFIG SUBCOMMANDS| \dl| @@ -85,9 +90,14 @@ namespace bdep The \cb{set} subcommand sets various properties of the specified build configuration. These include the default flag - (\c{\b{--}[\b{no-}]\b{default}}).|| - " - } + (\c{\b{--}[\b{no-}]\b{default}}).||" + + bool add; + bool create; + bool remove; + bool rename; + bool set; + }; // Note that not all project/configuration options are valid for all // subcommands. diff --git a/bdep/config.cxx b/bdep/config.cxx index 55a1062..0acd227 100644 --- a/bdep/config.cxx +++ b/bdep/config.cxx @@ -100,6 +100,12 @@ namespace bdep return r; } + static int + cmd_config_add (const cmd_config_options&, cli::scanner&) + { + fail << "@@ TODO" << endf; + } + shared_ptr cmd_config_create (const common_options& co, const dir_path& prj, @@ -129,22 +135,72 @@ namespace bdep "created"); } - int - cmd_config (const cmd_config_options& o, cli::scanner&) + static int + cmd_config_create (const cmd_config_options&, cli::scanner&) + { + fail << "@@ TODO" << endf; + } + + static int + cmd_config_remove (const cmd_config_options&, cli::scanner&) + { + fail << "@@ TODO" << endf; + } + + static int + cmd_config_rename (const cmd_config_options&, cli::scanner&) + { + fail << "@@ TODO" << endf; + } + + static int + cmd_config_set (const cmd_config_options&, cli::scanner&) { - //@@ TODO: get subcommand and pass to tracer. - //@@ TODO: define a CLI options class for subcommands? + fail << "@@ TODO" << endf; + } + int + cmd_config (const cmd_config_options& o, cli::scanner& scan) + { tracer trace ("config"); - //@@ TODO: validate project/config options for subcommands. + cmd_config_subcommands c ( + parse_command (scan, + "config subcommand", + "bdep help config")); + // Validate options/subcommands. + // + + // --[no-]default + // if (o.default_ () && o.no_default ()) fail << "both --default and --no-default specified"; - for (const string& n: o.config_name ()) - text << n; + if (const char* n = (o.default_ () ? "--default" : + o.no_default () ? "--no-default" : nullptr)) + { + if (!(c.add () || c.create () || c.set ())) + fail << n << " not valid for this command"; + } + + // --all + // + if (o.all ()) + { + if (!c.remove ()) + fail << "--all not valid for this command"; + } - return 0; + // Dispatch to subcommand function. + // + if (c.add ()) return cmd_config_add (o, scan); + if (c.create ()) return cmd_config_create (o, scan); + if (c.remove ()) return cmd_config_remove (o, scan); + if (c.rename ()) return cmd_config_rename (o, scan); + if (c.set ()) return cmd_config_set (o, scan); + + assert (false); // Unhandled (new) subcommand. + return 1; } } diff --git a/bdep/init.cxx b/bdep/init.cxx index 6d55523..335d45e 100644 --- a/bdep/init.cxx +++ b/bdep/init.cxx @@ -116,8 +116,6 @@ namespace bdep db.update (c); t.commit (); - //@@ --no-sync for some reason? - // cmd_sync (o, prj, c); } } diff --git a/bdep/utility.hxx b/bdep/utility.hxx index f3e2c73..865268a 100644 --- a/bdep/utility.hxx +++ b/bdep/utility.hxx @@ -19,6 +19,7 @@ #include #include +#include namespace bdep { @@ -100,8 +101,6 @@ namespace bdep // Run the bpkg process. // - class common_options; - const char* name_bpkg (const common_options&); @@ -140,6 +139,16 @@ namespace bdep ostream&, const string& name, const char* what); + + // CLI (sub)command parsing helper. + // + template + C + parse_command (cli::scanner& scan, const char* what, const char* help); + + template + bool + parse_command (cli::scanner& scan, C&); } #include diff --git a/bdep/utility.txx b/bdep/utility.txx index 8a4236b..2d6de1d 100644 --- a/bdep/utility.txx +++ b/bdep/utility.txx @@ -8,7 +8,6 @@ #include #include -#include namespace bdep { @@ -241,4 +240,36 @@ namespace bdep fail << "unable to write " << what << " manifest " << name << ": " << e; } } + + template + bool + parse_command (const char* cmd, C& r) + { + int argc (2); + char* argv[] {const_cast (""), const_cast (cmd)}; + + r.parse (argc, argv, true, cli::unknown_mode::stop); + + return argc == 1; + } + + template + C + parse_command (cli::scanner& scan, const char* what, const char* help) + { + // The next argument should be a command. + // + if (!scan.more ()) + fail << what << " expected" << + info << "run '" << help << "' for more information"; + + const char* cmd (scan.next ()); + + C r; + if (parse_command (cmd, r)) + return r; + + fail << "unknown " << what << " '" << cmd << "'" << + info << "run '" << help << "' for more information" << endf; + } } -- cgit v1.1