diff options
-rw-r--r-- | bdep/bdep.cxx | 106 | ||||
-rw-r--r-- | bdep/buildfile | 2 | ||||
-rw-r--r-- | bdep/ci-parsers.cxx | 6 | ||||
-rw-r--r-- | bdep/ci-parsers.hxx | 3 | ||||
-rw-r--r-- | bdep/config.cxx | 66 | ||||
-rw-r--r-- | bdep/config.hxx | 9 | ||||
-rw-r--r-- | bdep/diagnostics.hxx | 19 | ||||
-rw-r--r-- | bdep/help.cxx | 18 | ||||
-rw-r--r-- | bdep/help.hxx | 6 | ||||
-rw-r--r-- | bdep/init.cxx | 54 | ||||
-rw-r--r-- | bdep/init.hxx | 9 | ||||
-rw-r--r-- | bdep/new-parsers.cxx | 35 | ||||
-rw-r--r-- | bdep/new-parsers.hxx | 9 | ||||
-rw-r--r-- | bdep/new.cxx | 137 | ||||
-rw-r--r-- | bdep/new.hxx | 7 | ||||
-rw-r--r-- | bdep/project.cxx | 2 | ||||
-rw-r--r-- | bdep/release-parsers.hxx | 6 | ||||
-rw-r--r-- | bdep/release.cxx | 52 | ||||
-rw-r--r-- | bdep/release.hxx | 9 | ||||
-rw-r--r-- | bdep/sync.cxx | 55 | ||||
-rw-r--r-- | bdep/sync.hxx | 9 | ||||
-rw-r--r-- | bdep/types-parsers.hxx | 9 | ||||
-rw-r--r-- | bdep/types.hxx | 7 | ||||
-rw-r--r-- | bdep/utility.cxx | 13 | ||||
-rw-r--r-- | bdep/utility.hxx | 5 | ||||
-rw-r--r-- | tests/new.testscript | 41 |
26 files changed, 672 insertions, 22 deletions
diff --git a/bdep/bdep.cxx b/bdep/bdep.cxx index 5182647..d737d67 100644 --- a/bdep/bdep.cxx +++ b/bdep/bdep.cxx @@ -6,9 +6,10 @@ # include <signal.h> // signal() #endif -#include <cstring> // strcmp() +#include <cstring> // strcmp() #include <iostream> -#include <exception> // set_terminate(), terminate_handler +#include <exception> // set_terminate(), terminate_handler +#include <type_traits> // enable_if, is_base_of #include <libbutl/backtrace.mxx> // backtrace() @@ -44,6 +45,61 @@ using namespace bdep; namespace bdep { + // 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 cmd_xxx_options&, + // const strings& args); + + // Return the default options files and the project directory as a search + // start directory for commands that operate on project/packages (and thus + // have their options derived from project_options). + // + // Note that currently we don't support package-level default options files, + // since it can be surprising that running a command for multiple packages + // and doing the same for these packages individually may end up with + // different outcomes. + // + static inline default_options_files + options_files (const char* cmd, const project_options& o, const strings&) + { + // bdep.options + // bdep-<cmd>.options + + return default_options_files { + {path ("bdep.options"), path (string ("bdep-") + cmd + ".options")}, + find_project (o)}; + } + + // 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). + // + // cmd_xxx_options + // merge_options (const default_options<cmd_xxx_options>&, + // const cmd_xxx_options&); + + // Merge the default options and the command line options for commands + // that operate on project/packages. Fail if --directory|-d appears in the + // options file to avoid the chicken and egg problem. + // + template <typename O> + static inline typename enable_if<is_base_of<project_options, O>::value, + O>::type + merge_options (const default_options<O>& defs, const O& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry<O>& e, const O&) + { + if (e.options.directory_specified ()) + fail (e.file) << "--directory|-d in default options file"; + }); + } + int main (int argc, char* argv[]); } @@ -93,6 +149,7 @@ static O init (const common_options& co, cli::group_scanner& scan, strings& args, + const char* cmd, bool keep_sep, bool tmp) { @@ -141,6 +198,24 @@ init (const common_options& co, scan_argument (args, scan); } + // Handle default option files. + // + // Note: don't need to use group_scaner (no arguments in options files). + // + try + { + o = merge_options ( + load_default_options<O, cli::argv_file_scanner, cli::unknown_mode> ( + nullopt /* sys_dir */, + path::home_directory (), + options_files (cmd, o, args)), + o); + } + catch (const system_error& e) + { + fail << "unable to load default options files: " << e; + } + // Global initializations. // @@ -248,6 +323,7 @@ try return help (init<help_options> (co, scan, argsv, + "help", false /* keep_sep */, false /* tmp */), "", @@ -269,6 +345,7 @@ try ho = init<help_options> (co, scan, argsv, + "help", false /* keep_sep */, false /* tmp */); @@ -319,16 +396,21 @@ try // break; // } // -#define COMMAND_IMPL(ON, FN, SN, SEP, TMP) \ - if (cmd.ON ()) \ - { \ - if (h) \ - r = help (ho, SN, print_bdep_##FN##_usage); \ - else \ - r = cmd_##FN (init<cmd_##FN##_options> (co, scan, argsv, SEP, TMP), \ - args); \ - \ - break; \ +#define COMMAND_IMPL(ON, FN, SN, SEP, TMP) \ + if (cmd.ON ()) \ + { \ + if (h) \ + r = help (ho, SN, print_bdep_##FN##_usage); \ + else \ + r = cmd_##FN (init<cmd_##FN##_options> (co, \ + scan, \ + argsv, \ + SN, \ + SEP, \ + TMP), \ + args); \ + \ + break; \ } // Temp dir is initialized manually for these commands. diff --git a/bdep/buildfile b/bdep/buildfile index f7ce96b..8addd16 100644 --- a/bdep/buildfile +++ b/bdep/buildfile @@ -133,7 +133,7 @@ if $cli.configured --guard-prefix BDEP --cxx-prologue "#include <bdep/types-parsers.hxx>" \ --cli-namespace bdep::cli --generate-vector-scanner --generate-file-scanner \ --generate-group-scanner --keep-separator --generate-specifier \ ---generate-modifier --generate-description --generate-parse \ +--generate-modifier --generate-description --generate-parse --generate-merge \ --page-usage 'bdep::print_$name$_' --ansi-color --include-base-last \ --suppress-undocumented --option-length 23 diff --git a/bdep/ci-parsers.cxx b/bdep/ci-parsers.cxx index 5a56763..0dfafcb 100644 --- a/bdep/ci-parsers.cxx +++ b/bdep/ci-parsers.cxx @@ -115,5 +115,11 @@ namespace bdep xs = true; } + + void parser<cmd_ci_override>:: + merge (cmd_ci_override& b, const cmd_ci_override& a) + { + b.insert (b.end (), a.begin (), a.end ()); + } } } diff --git a/bdep/ci-parsers.hxx b/bdep/ci-parsers.hxx index 943821c..d196f41 100644 --- a/bdep/ci-parsers.hxx +++ b/bdep/ci-parsers.hxx @@ -29,6 +29,9 @@ namespace bdep { static void parse (cmd_ci_override&, bool&, scanner&); + + static void + merge (cmd_ci_override&, const cmd_ci_override&); }; } } diff --git a/bdep/config.cxx b/bdep/config.cxx index da7f5f4..f207bad 100644 --- a/bdep/config.cxx +++ b/bdep/config.cxx @@ -786,4 +786,70 @@ namespace bdep assert (false); // Unhandled (new) subcommand. return 1; } + + default_options_files + options_files (const char*, + const cmd_config_options& o, + const strings& args) + { + // bdep.options + // bdep-config.options + // bdep-config-<subcmd>.options + // + // Note that bdep-config-add.options is loaded for both the add and + // create subcommands since create is-a add. + // + // Also note that these files are loaded by other commands (bdep-init + // and bdep-new). + + default_options_files r { + {path ("bdep.options"), path ("bdep-config.options")}, + find_project (o)}; + + // Validate the subcommand. + // + { + cli::vector_scanner scan (args); + parse_command<cmd_config_subcommands> (scan, + "config subcommand", + "bdep help config"); + } + + const string& sc (args[0]); + + auto add = [&r] (const string& n) + { + r.files.push_back (path ("bdep-" + n + ".options")); + }; + + if (sc == "create") + add ("config-add"); + + add ("config-" + sc); + + return r; + } + + cmd_config_options + merge_options (const default_options<cmd_config_options>& defs, + const cmd_config_options& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry<cmd_config_options>& e, + const cmd_config_options&) + { + const cmd_config_options& o (e.options); + + auto forbid = [&e] (const char* opt, bool specified) + { + if (specified) + fail (e.file) << opt << " in default options file"; + }; + + forbid ("--directory|-d", o.directory_specified ()); + forbid ("--wipe", o.wipe ()); // Dangerous. + }); + } } diff --git a/bdep/config.hxx b/bdep/config.hxx index 0954850..ac830c4 100644 --- a/bdep/config.hxx +++ b/bdep/config.hxx @@ -49,6 +49,15 @@ namespace bdep const char* what, optional<string>& name, optional<uint64_t>& id); + + default_options_files + options_files (const char* cmd, + const cmd_config_options&, + const strings& args); + + cmd_config_options + merge_options (const default_options<cmd_config_options>&, + const cmd_config_options&); } #endif // BDEP_CONFIG_HXX diff --git a/bdep/diagnostics.hxx b/bdep/diagnostics.hxx index 89d8ac8..40b2d11 100644 --- a/bdep/diagnostics.hxx +++ b/bdep/diagnostics.hxx @@ -5,7 +5,7 @@ #ifndef BDEP_DIAGNOSTICS_HXX #define BDEP_DIAGNOSTICS_HXX -#include <utility> // forward() +#include <utility> // move(), forward() #include <odb/tracer.hxx> @@ -98,8 +98,8 @@ namespace bdep // Zero lines or columns are not printed. // explicit - location (string f, uint64_t l, uint64_t c) - : file (move (f)), line (l), column (c) {} + location (string f, uint64_t l = 0, uint64_t c = 0) + : file (std::move (f)), line (l), column (c) {} location () = default; @@ -118,6 +118,11 @@ namespace bdep const location& l) : type_ (type), name_ (name), loc_ (l) {} + location_prologue_base (const char* type, + const char* name, + const path& f) + : type_ (type), name_ (name), loc_ (f.string ()) {} + void operator() (const diag_record& r) const; @@ -151,10 +156,18 @@ namespace bdep return location_prologue (epilogue_, type_, name_, l); } + location_prologue + operator() (const path& f) const + { + return location_prologue (epilogue_, type_, name_, f); + } + template <typename L> location_prologue operator() (const L& l) const { + // get_location() is the user-supplied ADL-searched function. + // return location_prologue ( epilogue_, type_, name_, get_location (l, data_)); } diff --git a/bdep/help.cxx b/bdep/help.cxx index cd2c671..e37c65d 100644 --- a/bdep/help.cxx +++ b/bdep/help.cxx @@ -62,4 +62,22 @@ namespace bdep throw failed (); } + + default_options_files + options_files (const char*, const help_options&, const strings&) + { + // bdep.options + // bdep-help.options + + return default_options_files { + {path ("bdep.options"), path ("bdep-help.options")}, + nullopt /* start_dir */}; + } + + help_options + merge_options (const default_options<help_options>& defs, + const help_options& cmd) + { + return merge_default_options (defs, cmd); + } } diff --git a/bdep/help.hxx b/bdep/help.hxx index 6f0cac2..ffefbb9 100644 --- a/bdep/help.hxx +++ b/bdep/help.hxx @@ -16,6 +16,12 @@ namespace bdep int help (const help_options&, const string& topic, usage_function* usage); + + default_options_files + options_files (const char* cmd, const help_options&, const strings& args); + + help_options + merge_options (const default_options<help_options>&, const help_options&); } #endif // BDEP_HELP_HXX diff --git a/bdep/init.cxx b/bdep/init.cxx index 30cabb2..e6ddc1e 100644 --- a/bdep/init.cxx +++ b/bdep/init.cxx @@ -233,4 +233,58 @@ namespace bdep return 0; } + + default_options_files + options_files (const char*, const cmd_init_options& o, const strings&) + { + // bdep.options + // bdep-{config config-add}.options # -A + // bdep-{config config-add config-create}.options # -C + // bdep-init.options + + default_options_files r {{path ("bdep.options")}, find_project (o)}; + + auto add = [&r] (const string& n) + { + r.files.push_back (path ("bdep-" + n + ".options")); + }; + + if (o.config_add_specified () || o.config_create_specified ()) + { + add ("config"); + add ("config-add"); + } + + if (o.config_create_specified ()) + add ("config-create"); + + add ("init"); + + return r; + } + + cmd_init_options + merge_options (const default_options<cmd_init_options>& defs, + const cmd_init_options& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry<cmd_init_options>& e, + const cmd_init_options&) + { + const cmd_init_options& o (e.options); + + auto forbid = [&e] (const char* opt, bool specified) + { + if (specified) + fail (e.file) << opt << " in default options file"; + }; + + forbid ("--directory|-d", o.directory_specified ()); + forbid ("--config-add|-A", o.config_add_specified ()); + forbid ("--config-create|-C", o.config_create_specified ()); + forbid ("--wipe", o.wipe ()); // Dangerous. + }); + } } diff --git a/bdep/init.hxx b/bdep/init.hxx index 059f736..8569f91 100644 --- a/bdep/init.hxx +++ b/bdep/init.hxx @@ -39,6 +39,15 @@ namespace bdep int cmd_init (const cmd_init_options&, cli::group_scanner& args); + + default_options_files + options_files (const char* cmd, + const cmd_init_options&, + const strings& args); + + cmd_init_options + merge_options (const default_options<cmd_init_options>&, + const cmd_init_options&); } #endif // BDEP_INIT_HXX diff --git a/bdep/new-parsers.cxx b/bdep/new-parsers.cxx index 7a12132..49dee66 100644 --- a/bdep/new-parsers.cxx +++ b/bdep/new-parsers.cxx @@ -76,6 +76,8 @@ namespace bdep r.parse (s); } + // parser<type> + // void parser<type>:: parse (type& r, bool& xs, scanner& s) { @@ -114,6 +116,19 @@ namespace bdep xs = true; } + void parser<type>:: + merge (type& b, const type& a) + { + b.type = a.type; + + b.exe_opt.merge (a.exe_opt); + b.lib_opt.merge (a.lib_opt); + b.bare_opt.merge (a.bare_opt); + b.empty_opt.merge (a.empty_opt); + } + + // parser<lang> + // void parser<lang>:: parse (lang& r, bool& xs, scanner& s) { @@ -142,6 +157,17 @@ namespace bdep xs = true; } + void parser<lang>:: + merge (lang& b, const lang& a) + { + b.lang = a.lang; + + b.c_opt.merge (a.c_opt); + b.cxx_opt.merge (a.cxx_opt); + } + + // parser<vcs> + // void parser<vcs>:: parse (vcs& r, bool& xs, scanner& s) { @@ -169,5 +195,14 @@ namespace bdep xs = true; } + + void parser<vcs>:: + merge (vcs& b, const vcs& a) + { + b.vcs = a.vcs; + + b.git_opt.merge (a.git_opt); + b.none_opt.merge (a.none_opt); + } } } diff --git a/bdep/new-parsers.hxx b/bdep/new-parsers.hxx index 0bc6d56..b2a2b99 100644 --- a/bdep/new-parsers.hxx +++ b/bdep/new-parsers.hxx @@ -27,6 +27,9 @@ namespace bdep { static void parse (cmd_new_type&, bool&, scanner&); + + static void + merge (cmd_new_type&, const cmd_new_type&); }; template <> @@ -34,6 +37,9 @@ namespace bdep { static void parse (cmd_new_lang&, bool&, scanner&); + + static void + merge (cmd_new_lang&, const cmd_new_lang&); }; template <> @@ -41,6 +47,9 @@ namespace bdep { static void parse (cmd_new_vcs&, bool&, scanner&); + + static void + merge (cmd_new_vcs&, const cmd_new_vcs&); }; } } diff --git a/bdep/new.cxx b/bdep/new.cxx index 1aebc57..507ee3d 100644 --- a/bdep/new.cxx +++ b/bdep/new.cxx @@ -493,7 +493,7 @@ namespace bdep if (o.directory_specified ()) (prj = o.directory ()).complete ().normalize (); else - prj = path::current_directory (); + prj = current_directory (); out = o.output_dir_specified () ? o.output_dir () : prj / dir_path (n); out.complete ().normalize (); @@ -2002,7 +2002,7 @@ namespace bdep optional<command_substitution_map> subs; strings vars; - if (!o.post_hook ().empty ()) + if (o.post_hook_specified ()) { subs = command_substitution_map (); @@ -2118,4 +2118,137 @@ namespace bdep return 0; } + + default_options_files + options_files (const char*, const cmd_new_options& o, const strings&) + { + // bdep.options + // bdep-{config config-add}.options # -A + // bdep-{config config-add config-create}.options # -C + // bdep-new.options + // bdep-new-{project|package|subdirectory}.options + + // Use the project directory as a start directory in the + // package/subdirectory modes and the parent directory of the new project + // otherwise. + // + // Note that we will not validate the command arguments and let cmd_new() + // complain later in case of an error. + // + optional<dir_path> start_dir; + + auto output_parent_dir = [&o] () + { + return o.output_dir ().directory ().complete ().normalize (); + }; + + if (o.package () || o.subdirectory ()) + { + auto project_dir = [&o] () + { + return dir_path (o.directory ()).complete ().normalize (); + }; + + start_dir = o.output_dir_specified () ? output_parent_dir () : + o.directory_specified () ? project_dir () : + current_directory (); + + // Get the actual project directory. + // + project_package pp (find_project_package (*start_dir, + true /* ignore_not_found */)); + + if (!pp.project.empty ()) + start_dir = move (pp.project); + else if (!o.no_checks ()) + start_dir = nullopt; // Let cmd_new() fail. + } + else // New project. + { + start_dir = o.output_dir_specified () + ? output_parent_dir () + : current_directory (); + } + + default_options_files r {{path ("bdep.options")}, move (start_dir)}; + + auto add = [&r] (const string& n) + { + r.files.push_back (path ("bdep-" + n + ".options")); + }; + + if (o.config_add_specified () || o.config_create_specified ()) + { + add ("config"); + add ("config-add"); + } + + if (o.config_create_specified ()) + add ("config-create"); + + add ("new"); + + // Add the mode-specific options file. + // + add (o.subdirectory () ? "new-subdirectory" : + o.package () ? "new-package" : + "new-project"); + + return r; + } + + cmd_new_options + merge_options (const default_options<cmd_new_options>& defs, + const cmd_new_options& cmd) + { + // While validating/merging the default options, check for the "remote" + // hooks presence and prepare the prompt, if that's the case. + // + diag_record dr; + + auto verify = [&dr] (const default_options_entry<cmd_new_options>& e, + const cmd_new_options&) + { + const cmd_new_options& o (e.options); + + auto forbid = [&e] (const char* opt, bool specified) + { + if (specified) + fail (e.file) << opt << " in default options file"; + }; + + forbid ("--output-dir|-o", o.output_dir_specified ()); + forbid ("--directory|-d", o.directory_specified ()); + forbid ("--package", o.package ()); + forbid ("--subdirectory", o.subdirectory ()); + forbid ("--no-checks", o.no_checks ()); + forbid ("--config-add|-A", o.config_add_specified ()); + forbid ("--config-create|-C", o.config_create_specified ()); + forbid ("--wipe", o.wipe ()); // Dangerous. + + if (e.remote && o.post_hook_specified ()) + { + if (dr.empty ()) + dr << text << "remote post-creation hooks:"; + + dr << "\n " << e.file << ':'; + + const strings& hs (o.post_hook ()); + for (const string& h: hs) + dr << (hs.size () == 1 ? " " : "\n ") << h; + } + }; + + cmd_new_options r (merge_default_options (defs, cmd, verify)); + + if (!dr.empty ()) + { + dr.flush (); + + if (!yn_prompt ("execute? [y/n]")) + throw failed (); + } + + return r; + } } diff --git a/bdep/new.hxx b/bdep/new.hxx index c86b6ba..2513798 100644 --- a/bdep/new.hxx +++ b/bdep/new.hxx @@ -14,6 +14,13 @@ namespace bdep { int cmd_new (cmd_new_options&&, cli::group_scanner& args); + + default_options_files + options_files (const char* cmd, const cmd_new_options&, const strings& args); + + cmd_new_options + merge_options (const default_options<cmd_new_options>&, + const cmd_new_options&); } #endif // BDEP_NEW_HXX diff --git a/bdep/project.cxx b/bdep/project.cxx index 4d93d53..21f6f09 100644 --- a/bdep/project.cxx +++ b/bdep/project.cxx @@ -336,7 +336,7 @@ namespace bdep } else { - project_package p (find_project_package (path::current_directory ())); + project_package p (find_project_package (current_directory ())); r.project = move (p.project); diff --git a/bdep/release-parsers.hxx b/bdep/release-parsers.hxx index 607882f..8fec599 100644 --- a/bdep/release-parsers.hxx +++ b/bdep/release-parsers.hxx @@ -24,6 +24,12 @@ namespace bdep { static void parse (cmd_release_current_tag&, bool&, scanner&); + + static void + merge (cmd_release_current_tag& b, const cmd_release_current_tag& a) + { + b = a; + } }; } } diff --git a/bdep/release.cxx b/bdep/release.cxx index 81a6e3a..08cc61e 100644 --- a/bdep/release.cxx +++ b/bdep/release.cxx @@ -725,7 +725,7 @@ namespace bdep // project prj; { - // We publish all the packages in the project. We could have required a + // We release all the packages in the project. We could have required a // configuration and verified that they are all initialized, similar to // publish. But seeing that we don't need the configuration (unlike // publish), this feels like an unnecessary complication. We also don't @@ -859,7 +859,7 @@ namespace bdep for (const package& p: prj.packages) { - dr << " package: " << p.name << '\n' + dr << " package: " << p.name << '\n' << " current: " << p.current_version << '\n'; if (p.release_version) @@ -1292,7 +1292,7 @@ namespace bdep // Check if CWD is the project root and add -C if it's not. // - if (prj.path != path::current_directory()) + if (prj.path != current_directory()) { // Quote the directory if it contains spaces. // @@ -1317,4 +1317,50 @@ namespace bdep return 0; } + + default_options_files + options_files (const char*, const cmd_release_options& o, const strings&) + { + // bdep.options + // bdep-release.options + // bdep-release{version|revision|open|tag}.options + + default_options_files r { + {path ("bdep.options"), path ("bdep-release.options")}, + find_project (o.directory ())}; + + // Add the mode-specific options file. + // + r.files.push_back (path (o.revision () ? "bdep-release-revision.options" : + o.open () ? "bdep-release-open.options" : + o.tag () ? "bdep-release-tag.options" : + "bdep-release-version.options")); + + return r; + } + + cmd_release_options + merge_options (const default_options<cmd_release_options>& defs, + const cmd_release_options& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry<cmd_release_options>& e, + const cmd_release_options&) + { + const cmd_release_options& o (e.options); + + auto forbid = [&e] (const char* opt, bool specified) + { + if (specified) + fail (e.file) << opt << " in default options file"; + }; + + forbid ("--directory|-d", o.directory_specified ()); + forbid ("--revision", o.revision ()); + forbid ("--open", o.open ()); + forbid ("--tag", o.tag ()); + }); + } } diff --git a/bdep/release.hxx b/bdep/release.hxx index 1cf93c7..774d7d1 100644 --- a/bdep/release.hxx +++ b/bdep/release.hxx @@ -14,6 +14,15 @@ namespace bdep { int cmd_release (const cmd_release_options&, cli::scanner& args); + + default_options_files + options_files (const char* cmd, + const cmd_release_options&, + const strings& args); + + cmd_release_options + merge_options (const default_options<cmd_release_options>&, + const cmd_release_options&); } #endif // BDEP_RELEASE_HXX diff --git a/bdep/sync.cxx b/bdep/sync.cxx index cb85e98..ab2fb2b 100644 --- a/bdep/sync.cxx +++ b/bdep/sync.cxx @@ -861,4 +861,59 @@ namespace bdep return 0; } + + default_options_files + options_files (const char*, const cmd_sync_options& o, const strings&) + { + // bdep.options + // bdep-{sync|sync-implicit}.options + + default_options_files r {{path ("bdep.options")}, nullopt}; + + // Add bdep-sync-implicit.options for an implicit sync and + // bdep-sync.options otherwise. Omit the search start dir in the former + // case. + // + auto add = [&r] (const string& n) + { + r.files.push_back (path ("bdep-" + n + ".options")); + }; + + if (o.implicit () || o.hook_specified ()) + { + add ("sync-implicit"); + } + else + { + add ("sync"); + + r.start_dir = find_project (o); + } + + return r; + } + + cmd_sync_options + merge_options (const default_options<cmd_sync_options>& defs, + const cmd_sync_options& cmd) + { + return merge_default_options ( + defs, + cmd, + [] (const default_options_entry<cmd_sync_options>& e, + const cmd_sync_options&) + { + const cmd_sync_options& o (e.options); + + auto forbid = [&e] (const char* opt, bool specified) + { + if (specified) + fail (e.file) << opt << " in default options file"; + }; + + forbid ("--directory|-d", o.directory_specified ()); + forbid ("--implicit", o.implicit ()); + forbid ("--hook", o.hook_specified ()); + }); + } } diff --git a/bdep/sync.hxx b/bdep/sync.hxx index 2183021..5711a3f 100644 --- a/bdep/sync.hxx +++ b/bdep/sync.hxx @@ -43,6 +43,15 @@ namespace bdep const dir_path& cfg, const dir_path& prj = dir_path ()); + default_options_files + options_files (const char* cmd, + const cmd_sync_options&, + const strings& args); + + cmd_sync_options + merge_options (const default_options<cmd_sync_options>&, + const cmd_sync_options&); + // Note that the hook is installed into the bpkg-created configuration which // always uses the standard build file/directory naming scheme. // diff --git a/bdep/types-parsers.hxx b/bdep/types-parsers.hxx index 5cd4f65..c6e1cc6 100644 --- a/bdep/types-parsers.hxx +++ b/bdep/types-parsers.hxx @@ -25,6 +25,9 @@ namespace bdep { static void parse (url&, bool&, scanner&); + + static void + merge (url& b, const url& a) {b = a;} }; template <> @@ -32,6 +35,9 @@ namespace bdep { static void parse (path&, bool&, scanner&); + + static void + merge (path& b, const path& a) {b = a;} }; template <> @@ -39,6 +45,9 @@ namespace bdep { static void parse (dir_path&, bool&, scanner&); + + static void + merge (dir_path& b, const dir_path& a) {b = a;} }; } } diff --git a/bdep/types.hxx b/bdep/types.hxx index b449551..0ecc8ec 100644 --- a/bdep/types.hxx +++ b/bdep/types.hxx @@ -28,6 +28,7 @@ #include <libbutl/optional.mxx> #include <libbutl/fdstream.mxx> #include <libbutl/small-vector.mxx> +#include <libbutl/default-options.mxx> #include <libbutl/semantic-version.mxx> #include <libbutl/standard-version.mxx> @@ -112,6 +113,12 @@ namespace bdep using butl::fdopen_mode; using butl::fdstream_mode; + // <libbutl/default-options.mxx> + // + using butl::default_options_files; + using butl::default_options_entry; + using butl::default_options; + // <libbutl/semantic-version.mxx> // <libbutl/standard-version.mxx> // diff --git a/bdep/utility.cxx b/bdep/utility.cxx index 4407eed..9c8057e 100644 --- a/bdep/utility.cxx +++ b/bdep/utility.cxx @@ -82,6 +82,19 @@ namespace bdep bool stderr_term; + dir_path + current_directory () + { + try + { + return dir_path::current_directory (); + } + catch (const system_error& e) + { + fail << "unable to obtain current directory: " << e << endf; + } + } + bool exists (const path& f, bool ignore_error) { diff --git a/bdep/utility.hxx b/bdep/utility.hxx index c4d406c..133896f 100644 --- a/bdep/utility.hxx +++ b/bdep/utility.hxx @@ -114,6 +114,11 @@ namespace bdep // extern dir_path exec_dir; + // Path. + // + dir_path + current_directory (); + // Progress. // extern bool stderr_term; // True if stderr is a terminal. diff --git a/tests/new.testscript b/tests/new.testscript index 161fda1..9ac0b9f 100644 --- a/tests/new.testscript +++ b/tests/new.testscript @@ -701,6 +701,47 @@ status += -d prj } } + : default-options-files + : + { + : remote-post-hook + : + if $posix + { + $* -t empty prj 2>! &prj/***; + + mkdir prj/.build2; + + cat <<EOI >=prj/.build2/bdep-new-package.options; + --post-hook "echo .idea/ >>.gitignore" + EOI + + $* --package -t lib -d prj libprj <'y' 2>>~%EOE%; + remote post-creation hooks: + % .+/.build2/bdep-new-package.options: echo .idea/ >>.gitignore% + %execute\? \[y/n\] created new library package libprj in .+/prj/libprj/% + EOE + + $build prj/libprj/ $cxx 2>>~%EOE% + %(version\.in|c\+\+|ar|ld) .+%{7} + EOE + } + + : disallow-options + : + { + mkdir .build2; + + cat <<EOI >=.build2/bdep-new.options; + --package + EOI + + $* prj 2>>/~%EOE%d != 0 + %\.+/.build2/bdep-new.options: error: --package in default options file% + EOE + } + } + : post-hook : if $posix |