aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-08-16 22:39:07 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-08-17 13:07:36 +0300
commitbf2cf8cd53361826e51e01c2904f6fb4cb7502dc (patch)
tree534dc598757f42e6daff0107f4bfe533d6bf27a5
parent3712363ddf1be71b38321d2dde57d88f01a28afb (diff)
Add support for default options files
-rw-r--r--build2/b-options.cxx230
-rw-r--r--build2/b-options.hxx10
-rw-r--r--build2/b-options.ixx6
-rw-r--r--build2/b.cli5
-rw-r--r--build2/b.cxx51
-rw-r--r--build2/buildfile2
-rw-r--r--build2/types-parsers.hxx6
-rw-r--r--libbuild2/utility.cxx10
8 files changed, 312 insertions, 8 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
index 4c8e63b..9ad7429 100644
--- a/build2/b-options.cxx
+++ b/build2/b-options.cxx
@@ -476,6 +476,12 @@ namespace build2
xs = true;
}
+
+ static void
+ merge (X& b, const X& a)
+ {
+ b = a;
+ }
};
template <>
@@ -487,6 +493,12 @@ namespace build2
s.next ();
x = true;
}
+
+ static void
+ merge (bool& b, const bool&)
+ {
+ b = true;
+ }
};
template <>
@@ -504,6 +516,12 @@ namespace build2
xs = true;
}
+
+ static void
+ merge (std::string& b, const std::string& a)
+ {
+ b = a;
+ }
};
template <typename X>
@@ -518,6 +536,12 @@ namespace build2
c.push_back (x);
xs = true;
}
+
+ static void
+ merge (std::vector<X>& b, const std::vector<X>& a)
+ {
+ b.insert (b.end (), a.begin (), a.end ());
+ }
};
template <typename X>
@@ -532,6 +556,12 @@ namespace build2
c.insert (x);
xs = true;
}
+
+ static void
+ merge (std::set<X>& b, const std::set<X>& a)
+ {
+ b.insert (a.begin (), a.end ());
+ }
};
template <typename K, typename V>
@@ -580,6 +610,15 @@ namespace build2
xs = true;
}
+
+ static void
+ merge (std::map<K, V>& b, const std::map<K, V>& a)
+ {
+ for (typename std::map<K, V>::const_iterator i (a.begin ());
+ i != a.end ();
+ ++i)
+ b[i->first] = i->second;
+ }
};
template <typename X, typename T, T X::*M>
@@ -644,6 +683,7 @@ namespace build2
pager_specified_ (false),
pager_option_ (),
pager_option_specified_ (false),
+ no_default_options_ (),
help_ (),
version_ ()
{
@@ -712,6 +752,191 @@ namespace build2
return r;
}
+ void options::
+ merge (const options& a)
+ {
+ CLI_POTENTIALLY_UNUSED (a);
+
+ if (a.v_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->v_, a.v_);
+ }
+
+ if (a.V_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->V_, a.V_);
+ }
+
+ if (a.quiet_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->quiet_, a.quiet_);
+ }
+
+ if (a.verbose_specified_)
+ {
+ ::build2::cl::parser< uint16_t>::merge (
+ this->verbose_, a.verbose_);
+ this->verbose_specified_ = true;
+ }
+
+ if (a.stat_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->stat_, a.stat_);
+ }
+
+ if (a.dump_specified_)
+ {
+ ::build2::cl::parser< std::set<string>>::merge (
+ this->dump_, a.dump_);
+ this->dump_specified_ = true;
+ }
+
+ if (a.progress_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->progress_, a.progress_);
+ }
+
+ if (a.no_progress_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_progress_, a.no_progress_);
+ }
+
+ if (a.jobs_specified_)
+ {
+ ::build2::cl::parser< size_t>::merge (
+ this->jobs_, a.jobs_);
+ this->jobs_specified_ = true;
+ }
+
+ if (a.max_jobs_specified_)
+ {
+ ::build2::cl::parser< size_t>::merge (
+ this->max_jobs_, a.max_jobs_);
+ this->max_jobs_specified_ = true;
+ }
+
+ if (a.queue_depth_specified_)
+ {
+ ::build2::cl::parser< size_t>::merge (
+ this->queue_depth_, a.queue_depth_);
+ this->queue_depth_specified_ = true;
+ }
+
+ if (a.max_stack_specified_)
+ {
+ ::build2::cl::parser< size_t>::merge (
+ this->max_stack_, a.max_stack_);
+ this->max_stack_specified_ = true;
+ }
+
+ if (a.serial_stop_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->serial_stop_, a.serial_stop_);
+ }
+
+ if (a.dry_run_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->dry_run_, a.dry_run_);
+ }
+
+ if (a.match_only_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->match_only_, a.match_only_);
+ }
+
+ if (a.structured_result_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->structured_result_, a.structured_result_);
+ }
+
+ if (a.mtime_check_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->mtime_check_, a.mtime_check_);
+ }
+
+ if (a.no_mtime_check_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_mtime_check_, a.no_mtime_check_);
+ }
+
+ if (a.no_column_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_column_, a.no_column_);
+ }
+
+ if (a.no_line_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_line_, a.no_line_);
+ }
+
+ if (a.buildfile_specified_)
+ {
+ ::build2::cl::parser< path>::merge (
+ this->buildfile_, a.buildfile_);
+ this->buildfile_specified_ = true;
+ }
+
+ if (a.config_guess_specified_)
+ {
+ ::build2::cl::parser< path>::merge (
+ this->config_guess_, a.config_guess_);
+ this->config_guess_specified_ = true;
+ }
+
+ if (a.config_sub_specified_)
+ {
+ ::build2::cl::parser< path>::merge (
+ this->config_sub_, a.config_sub_);
+ this->config_sub_specified_ = true;
+ }
+
+ if (a.pager_specified_)
+ {
+ ::build2::cl::parser< string>::merge (
+ this->pager_, a.pager_);
+ this->pager_specified_ = true;
+ }
+
+ if (a.pager_option_specified_)
+ {
+ ::build2::cl::parser< strings>::merge (
+ this->pager_option_, a.pager_option_);
+ this->pager_option_specified_ = true;
+ }
+
+ if (a.no_default_options_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_default_options_, a.no_default_options_);
+ }
+
+ if (a.help_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->help_, a.help_);
+ }
+
+ if (a.version_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->version_, a.version_);
+ }
+ }
+
::build2::cl::usage_para options::
print_usage (::std::ostream& os, ::build2::cl::usage_para p)
{
@@ -899,6 +1124,9 @@ namespace build2
<< " this option to specify multiple pager options." << ::std::endl;
os << std::endl
+ << "\033[1m--no-default-options\033[0m Don't load default options files." << ::std::endl;
+
+ os << std::endl
<< "\033[1m--help\033[0m Print usage information and exit." << ::std::endl;
os << std::endl
@@ -995,6 +1223,8 @@ namespace build2
_cli_options_map_["--pager-option"] =
&::build2::cl::thunk< options, strings, &options::pager_option_,
&options::pager_option_specified_ >;
+ _cli_options_map_["--no-default-options"] =
+ &::build2::cl::thunk< options, bool, &options::no_default_options_ >;
_cli_options_map_["--help"] =
&::build2::cl::thunk< options, bool, &options::help_ >;
_cli_options_map_["--version"] =
diff --git a/build2/b-options.hxx b/build2/b-options.hxx
index 3e10901..297e6a4 100644
--- a/build2/b-options.hxx
+++ b/build2/b-options.hxx
@@ -422,6 +422,12 @@ namespace build2
::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
+ // Merge options from the specified instance appending/overriding
+ // them as if they appeared after options in this instance.
+ //
+ void
+ merge (const options&);
+
// Option accessors.
//
const bool&
@@ -533,6 +539,9 @@ namespace build2
pager_option_specified () const;
const bool&
+ no_default_options () const;
+
+ const bool&
help () const;
const bool&
@@ -593,6 +602,7 @@ namespace build2
bool pager_specified_;
strings pager_option_;
bool pager_option_specified_;
+ bool no_default_options_;
bool help_;
bool version_;
};
diff --git a/build2/b-options.ixx b/build2/b-options.ixx
index a8dd01c..ab5af3f 100644
--- a/build2/b-options.ixx
+++ b/build2/b-options.ixx
@@ -477,6 +477,12 @@ namespace build2
}
inline const bool& options::
+ no_default_options () const
+ {
+ return this->no_default_options_;
+ }
+
+ inline const bool& options::
help () const
{
return this->help_;
diff --git a/build2/b.cli b/build2/b.cli
index 4ab397b..f0ddb93 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -622,6 +622,11 @@ namespace build2
specify multiple pager options."
}
+ bool --no-default-options
+ {
+ "Don't load default options files."
+ }
+
bool --help {"Print usage information and exit."}
bool --version {"Print version and exit."}
};
diff --git a/build2/b.cxx b/build2/b.cxx
index 8965d64..15844dc 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -19,8 +19,9 @@
#include <exception> // terminate(), set_terminate(), terminate_handler
#include <libbutl/pager.mxx>
-#include <libbutl/fdstream.mxx> // stderr_fd(), fdterm()
-#include <libbutl/backtrace.mxx> // backtrace()
+#include <libbutl/fdstream.mxx> // stderr_fd(), fdterm()
+#include <libbutl/backtrace.mxx> // backtrace()
+#include <libbutl/default-options.mxx>
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
@@ -225,6 +226,18 @@ main (int argc, char* argv[])
//
try
{
+ // 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 = [] ()
+ {
+ return ops.verbose_specified ()
+ ? ops.verbose ()
+ : ops.V () ? 3 : ops.v () ? 2 : ops.quiet () ? 0 : 1;
+ };
+
// We want to be able to specify options, vars, and buildspecs in any
// order (it is really handy to just add -v at the end of the command
// line).
@@ -349,6 +362,36 @@ main (int argc, char* argv[])
args += ')';
}
+ // Handle default options files.
+ //
+ if (!ops.no_default_options ()) // Command line option.
+ try
+ {
+ ops = merge_default_options (
+ load_default_options<options,
+ cl::argv_file_scanner,
+ cl::unknown_mode> (
+ nullopt /* sys_dir */,
+ path::home_directory (), // The home variable is not assigned yet.
+ default_options_files {{path ("b.options")},
+ nullopt /* start_dir */},
+ [&trace, &verbosity] (const path& f, bool remote)
+ {
+ if (verbosity () >= 3)
+ trace << "loading " << (remote ? "remote " : "local ") << f;
+ }),
+ ops);
+ }
+ catch (const pair<path, system_error>& e)
+ {
+ fail << "unable to load default options files: " << e.first << ": "
+ << e.second;
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to obtain home directory: " << e;
+ }
+
// Validate options.
//
if (ops.progress () && ops.no_progress ())
@@ -364,9 +407,7 @@ main (int argc, char* argv[])
// Initialize the diagnostics state.
//
- init_diag ((ops.verbose_specified ()
- ? ops.verbose ()
- : ops.V () ? 3 : ops.v () ? 2 : ops.quiet () ? 0 : 1),
+ init_diag (verbosity (),
(ops.progress () ? optional<bool> (true) :
ops.no_progress () ? optional<bool> (false) : nullopt),
ops.no_line (),
diff --git a/build2/buildfile b/build2/buildfile
index d3b937f..d8b045a 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -90,7 +90,7 @@ if $cli.configured
--include-prefix build2 --guard-prefix BUILD2 \
--cxx-prologue "#include <build2/types-parsers.hxx>" \
--cli-namespace build2::cl --generate-file-scanner --keep-separator \
---generate-parse --generate-specifier
+--generate-parse --generate-merge --generate-specifier
# Usage options.
#
diff --git a/build2/types-parsers.hxx b/build2/types-parsers.hxx
index beea977..db55c05 100644
--- a/build2/types-parsers.hxx
+++ b/build2/types-parsers.hxx
@@ -24,6 +24,9 @@ namespace build2
{
static void
parse (path&, bool&, scanner&);
+
+ static void
+ merge (path& b, const path& a) {b = a;}
};
template <>
@@ -31,6 +34,9 @@ namespace build2
{
static void
parse (dir_path&, bool&, scanner&);
+
+ static void
+ merge (dir_path& b, const dir_path& a) {b = a;}
};
}
}
diff --git a/libbuild2/utility.cxx b/libbuild2/utility.cxx
index 506e88e..79545cc 100644
--- a/libbuild2/utility.cxx
+++ b/libbuild2/utility.cxx
@@ -143,7 +143,6 @@ namespace build2
else if (rb.sub (home))
return "~/" + rb.leaf (home).representation ();
}
-
#endif
return move (rb).representation ();
@@ -515,6 +514,13 @@ namespace build2
fail << "invalid current working directory: " << e;
}
- home = dir_path::home_directory ();
+ try
+ {
+ home = dir_path::home_directory ();
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to obtain home directory: " << e;
+ }
}
}