aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-08-12 14:56:03 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-08-13 16:52:16 +0300
commitedab35e216bc3839915129e54f98160428634283 (patch)
tree51c1ae471e39aca817038f16d33cc25be4998369
parent54c937f78562fc6a5d2ea01c8747c62ccea980cb (diff)
Add support for default options files
-rw-r--r--bdep/bdep.cxx106
-rw-r--r--bdep/buildfile2
-rw-r--r--bdep/ci-parsers.cxx6
-rw-r--r--bdep/ci-parsers.hxx3
-rw-r--r--bdep/config.cxx66
-rw-r--r--bdep/config.hxx9
-rw-r--r--bdep/diagnostics.hxx19
-rw-r--r--bdep/help.cxx18
-rw-r--r--bdep/help.hxx6
-rw-r--r--bdep/init.cxx54
-rw-r--r--bdep/init.hxx9
-rw-r--r--bdep/new-parsers.cxx35
-rw-r--r--bdep/new-parsers.hxx9
-rw-r--r--bdep/new.cxx137
-rw-r--r--bdep/new.hxx7
-rw-r--r--bdep/project.cxx2
-rw-r--r--bdep/release-parsers.hxx6
-rw-r--r--bdep/release.cxx52
-rw-r--r--bdep/release.hxx9
-rw-r--r--bdep/sync.cxx55
-rw-r--r--bdep/sync.hxx9
-rw-r--r--bdep/types-parsers.hxx9
-rw-r--r--bdep/types.hxx7
-rw-r--r--bdep/utility.cxx13
-rw-r--r--bdep/utility.hxx5
-rw-r--r--tests/new.testscript41
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