From ed437dbd3483baa3d15d1d86d8f057d9112653b1 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 14 Aug 2019 14:36:44 +0300 Subject: Add support for default options files --- bpkg/bpkg.cxx | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 14 deletions(-) (limited to 'bpkg/bpkg.cxx') diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx index fdcb8bb..be38297 100644 --- a/bpkg/bpkg.cxx +++ b/bpkg/bpkg.cxx @@ -7,7 +7,8 @@ #endif #include -#include // set_terminate(), terminate_handler +#include // set_terminate(), terminate_handler +#include // enable_if, is_base_of #include // backtrace() @@ -52,6 +53,91 @@ using namespace bpkg; namespace bpkg { + // Deduce the default options files and the directory to start searching + // from based on the command line options and arguments. + // + // default_options_files + // options_files (const char* cmd, const xxx_options&, const strings& args); + + // Return the default options files and the configuration directory as a + // search start directory for commands that operate on a configuration (and + // thus have their options derived from configuration_options). + // + // Note that we don't support package-level default options files. + // + static inline default_options_files + options_files (const char* cmd, + const configuration_options& o, + const strings&) + { + // bpkg.options + // bpkg-.options + + return default_options_files { + {path ("bpkg.options"), path (string ("bpkg-") + cmd + ".options")}, + normalize (o.directory (), "configuration")}; + } + + // Return the default options files without search start directory for + // commands that don't operate on a configuration (and thus their options + // are not derived from configuration_options). + // + template + static inline typename enable_if::value, + default_options_files>::type + options_files (const char* cmd, + const O&, + const strings&) + { + // bpkg.options + // bpkg-.options + + return default_options_files { + {path ("bpkg.options"), path (string ("bpkg-") + cmd + ".options")}, + nullopt /* start_dir */}; + } + + // Merge the default options and the command line options. Fail if options + // used to deduce the default options files or the start directory appear in + // an options file (or for other good reasons). + // + // xxx_options + // merge_options (const default_options&, const xxx_options&); + + // Merge the default options and the command line options for commands + // that operate on configuration. Fail if --directory|-d appears in the + // options file to avoid the chicken and egg problem. + // + template + static inline typename enable_if::value, + O>::type + merge_options (const default_options& defs, const O& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry& e, const O&) + { + if (e.options.directory_specified ()) + fail (e.file) << "--directory|-d in default options file"; + }); + } + + // Merge the default options and the command line options for commands that + // allow any option in the options files (and thus their options are not + // derived from configuration_options). + // + template + static inline typename enable_if::value, + O>::type + merge_options (const default_options& defs, const O& cmd) + { + return merge_default_options (defs, cmd); + } + int main (int argc, char* argv[]); } @@ -77,9 +163,12 @@ static O init (const common_options& co, cli::group_scanner& scan, strings& args, + const char* cmd, bool keep_sep, bool tmp) { + tracer trace ("init"); + O o; static_cast (o) = co; @@ -126,14 +215,48 @@ init (const common_options& co, } } + // Note that the diagnostics verbosity level can only be calculated after + // default options are loaded and merged (see below). Thus, to trace the + // default options files search, we refer to the verbosity level specified + // on the command line. + // + auto verbosity = [&o] () + { + return o.verbose_specified () + ? o.verbose () + : o.V () ? 3 : o.v () ? 2 : o.quiet () ? 0 : 1; + }; + + // Handle default options files. + // + // Note: don't need to use group_scaner (no arguments in options files). + // + if (!o.no_default_options ()) // Command line option. + try + { + o = merge_options ( + load_default_options ( + nullopt /* sys_dir */, + path::home_directory (), + options_files (cmd, o, args), + [&trace, &verbosity] (const path& f, bool remote) + { + if (verbosity () >= 3) + trace << "loading " << (remote ? "remote " : "local ") << f; + }), + o); + } + catch (const system_error& e) + { + fail << "unable to load default options files: " << e; + } + // Global initializations. // // Diagnostics verbosity. // - verb = o.verbose_specified () - ? o.verbose () - : o.V () ? 3 : o.v () ? 2 : o.quiet () ? 0 : 1; + verb = verbosity (); // Temporary directory. // @@ -231,6 +354,7 @@ try return help (init (co, scan, argsv, + "help", false /* keep_sep */, false /* tmp */), "", @@ -263,6 +387,7 @@ try ho = init (co, scan, argsv, + "help", false /* keep_sep */, false /* tmp */); @@ -310,6 +435,7 @@ try // r = pkg_verify (init (co, // scan, // argsv, + // "pkg-verify", // false /* keep_sep */, // true /* tmp */), // args); @@ -317,16 +443,21 @@ try // break; // } // -#define COMMAND_IMPL(NP, SP, CMD, SEP, TMP) \ - if (cmd.NP##CMD ()) \ - { \ - if (h) \ - r = help (ho, SP#CMD, print_bpkg_##NP##CMD##_usage); \ - else \ - r = NP##CMD (init (co, scan, argsv, SEP, TMP), \ - args); \ - \ - break; \ +#define COMMAND_IMPL(NP, SP, CMD, SEP, TMP) \ + if (cmd.NP##CMD ()) \ + { \ + if (h) \ + r = help (ho, SP#CMD, print_bpkg_##NP##CMD##_usage); \ + else \ + r = NP##CMD (init (co, \ + scan, \ + argsv, \ + SP#CMD, \ + SEP, \ + TMP), \ + args); \ + \ + break; \ } // cfg-* commands -- cgit v1.1