// file : bpkg/bpkg.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include // strcmp() #include #include #include #include #include #include // Commands. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace bpkg; // Initialize the command option class O with the common options and then // parse the rest of the command line placing non-option arguments to args. // Once this is done, use the "final" values of the common options to do // global initializations (verbosity level, etc). // template static O parse (const common_options& co, cli::scanner& scan, strings& args) { O o; static_cast (o) = co; // We want to be able to specify options and arguments in any order (it is // really handy to just add -v at the end of the command line). // for (bool opt (true); scan.more (); ) { if (opt) { // If we see first "--", then we are done parsing options. // if (strcmp (scan.peek (), "--") == 0) { scan.next (); opt = false; continue; } // Parse the next chunk of options until we reach an argument (or eos). // o.parse (scan); if (!scan.more ()) break; // Fall through. } args.push_back (scan.next ()); } // Global initializations. // // Diagnostics verbosity. // verb = o.verbose_specified () ? o.verbose () : o.v () ? 2 : o.q () ? 0 : 1; return o; } int main (int argc, char* argv[]) try { using namespace cli; argv_file_scanner scan (argc, argv, "--options-file"); // First parse common options and --version/--help. // options o; o.parse (scan, unknown_mode::stop); if (o.version ()) { cout << "bpkg " << BPKG_VERSION_STR << endl << "libbpkg " << LIBBPKG_VERSION_STR << endl << "libbutl " << LIBBUTL_VERSION_STR << endl << "Copyright (c) 2014-2016 Code Synthesis Ltd" << endl << "This is free software released under the MIT license." << endl; return 0; } strings argsv; // To be filled by parse() above. vector_scanner args (argsv); const common_options& co (o); if (o.help ()) return help (parse (co, scan, argsv), "", nullptr); // The next argument should be a command. // if (!scan.more ()) fail << "bpkg command expected" << info << "run 'bpkg 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 bpkg command/option '" << cmd_argv[1] << "'" << info << "run 'bpkg help' for more information"; // 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 place. // bool h (cmd.help ()); help_options ho; if (h) { ho = parse (co, scan, argsv); if (args.more ()) { cmd_argc = 2; cmd_argv[1] = const_cast (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 (cmd_argc != 1) return help (ho, cmd_argv[1], nullptr); } else return help (ho, "", nullptr); } // Handle commands. // int r (1); for (;;) { // help // if (cmd.help ()) { assert (h); r = help (ho, "help", print_bpkg_help_usage); break; } // Commands. // // if (cmd.pkg_verify ()) // { // if (h) // r = help (ho, "pkg-verify", print_bpkg_pkg_verify_usage); // else // r = pkg_verify (parse (co, scan, argsv), args); // // break; // } // #define COMMAND_IMPL(NP, SP, CMD) \ if (cmd.NP##CMD ()) \ { \ if (h) \ r = help (ho, SP#CMD, print_bpkg_##NP##CMD##_usage); \ else \ r = NP##CMD (parse (co, scan, argsv), args); \ \ break; \ } // pkg-* commands // #define PKG_COMMAND(CMD) COMMAND_IMPL(pkg_, "pkg-", CMD) PKG_COMMAND (build); PKG_COMMAND (clean); PKG_COMMAND (configure); PKG_COMMAND (disfigure); PKG_COMMAND (drop); PKG_COMMAND (fetch); PKG_COMMAND (install); PKG_COMMAND (purge); PKG_COMMAND (status); PKG_COMMAND (test); PKG_COMMAND (uninstall); PKG_COMMAND (unpack); PKG_COMMAND (update); PKG_COMMAND (verify); // cfg-* commands // #define CFG_COMMAND(CMD) COMMAND_IMPL(cfg_, "cfg-", CMD) CFG_COMMAND (add); CFG_COMMAND (create); CFG_COMMAND (fetch); // rep-* commands // #define REP_COMMAND(CMD) COMMAND_IMPL(rep_, "rep-", CMD) REP_COMMAND (info); REP_COMMAND (create); assert (false); fail << "unhandled command"; } if (r != 0) return r; // Warn if args contain some leftover junk. We already successfully // performed the command so failing would probably be misleading. // if (args.more ()) { diag_record dr; dr << warn << "ignoring unexpected argument(s)"; while (args.more ()) dr << " '" << args.next () << "'"; } return 0; } catch (const failed&) { return 1; // Diagnostics has already been issued. } catch (const cli::exception& e) { error << e; return 1; } /* catch (const std::exception& e) { error << e.what (); return 1; } */