aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/default-options.mxx11
-rw-r--r--libbutl/default-options.txx122
-rw-r--r--tests/default-options/driver.cxx12
-rw-r--r--tests/default-options/testscript104
4 files changed, 194 insertions, 55 deletions
diff --git a/libbutl/default-options.mxx b/libbutl/default-options.mxx
index 403df47..0f4b194 100644
--- a/libbutl/default-options.mxx
+++ b/libbutl/default-options.mxx
@@ -79,11 +79,13 @@ LIBBUTL_MODEXPORT namespace butl
//
// - sys_dir
// - home_dir
+ // - extra_dir (can also be handled during the start/outer traversal)
// - start_dir and outer until home_dir or root (both excluding)
//
- // Except for sys_dir, the options files are looked for in the .build2/ and
- // .build2/local/ subdirectories of each directory. For sys_dir they are
- // looked for in the directory itself (e.g., /etc/build2/).
+ // Except for sys_dir and extra_dir, the options files are looked for in the
+ // .build2/ and .build2/local/ subdirectories of each directory. For
+ // sys_dir and extra_dir they are looked for in the directory itself (e.g.,
+ // /etc/build2/).
//
// Note that the search is stopped at the directory containing a file with
// --no-default-options.
@@ -97,10 +99,13 @@ LIBBUTL_MODEXPORT namespace butl
// sufficient ground to definitively conclude that the file is not remote;
// to be sure we would need to query the VCS or some such).
//
+ // Note that the extra directory options files are never considered remote.
+ //
template <typename O, typename S, typename U, typename F>
default_options<O>
load_default_options (const optional<dir_path>& sys_dir,
const optional<dir_path>& home_dir,
+ const optional<dir_path>& extra_dir,
const default_options_files&,
F&&);
diff --git a/libbutl/default-options.txx b/libbutl/default-options.txx
index 276fa63..5a1cc0d 100644
--- a/libbutl/default-options.txx
+++ b/libbutl/default-options.txx
@@ -20,10 +20,10 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
// options to the resulting list. Return false if --no-default-options is
// encountered.
//
- // Note that we check for the local/ subdirectory even if we don't think it
- // belongs to the remote directory; the user may move things around or it
- // could be a VCS we don't yet recognize and there doesn't seem to be any
- // harm in doing so.
+ // Note that by default we check for the local/ subdirectory even if we
+ // don't think it belongs to the remote directory; the user may move things
+ // around or it could be a VCS we don't yet recognize and there doesn't seem
+ // to be any harm in doing so.
//
// Also note that if the directory is remote, then for now the options files
// in both the directory itself and its local/ subdirectory are considered
@@ -35,8 +35,12 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
bool remote,
const small_vector<path, 2>& fs,
F&& fn,
- default_options<O>& def_ops)
+ default_options<O>& def_ops,
+ bool load_sub = true,
+ bool load_dir = true)
{
+ assert (load_sub || load_dir);
+
bool r (true);
auto load = [&fs, &fn, &def_ops, &r] (const dir_path& d, bool remote)
@@ -81,13 +85,13 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
dir_path ld (d / dir_path ("local"));
- if (options_dir_exists (ld))
+ if (load_sub && options_dir_exists (ld))
load (ld, remote);
// Don't load options from .build2/ if --no-default-options is encountered
// in .build2/local/.
//
- if (r)
+ if (load_dir && r)
load (d, remote);
return r;
@@ -97,17 +101,32 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
default_options<O>
load_default_options (const optional<dir_path>& sys_dir,
const optional<dir_path>& home_dir,
+ const optional<dir_path>& extra_dir,
const default_options_files& ofs,
F&& fn)
{
+ if (sys_dir)
+ assert (sys_dir->absolute () && sys_dir->normalized ());
+
+ if (home_dir)
+ assert (home_dir->absolute () && home_dir->normalized ());
+
+ if (extra_dir)
+ assert (extra_dir->absolute () && extra_dir->normalized ());
+
default_options<O> r;
- // Search for and parse the options files in the specified and outer
- // directories until root/home directory and in the system directory,
- // stopping if --no-default-options is encountered and reversing the
- // resulting options entry list in the end.
+ // Search for and parse the options files in the start and outer
+ // directories until root/home directory and in the extra and system
+ // directories, stopping if --no-default-options is encountered and
+ // reversing the resulting options entry list in the end.
//
- bool load (true);
+ // Note that the extra directory is handled either during the start/outer
+ // directory traversal, if it turns out to be a subdirectory of any of the
+ // traversed directories, or right after.
+ //
+ bool load (true);
+ bool load_extra (extra_dir && options_dir_exists (*extra_dir));
if (ofs.start)
{
@@ -129,7 +148,8 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
}
// If the directory is remote, then mark all the previously collected
- // local entries (that belong to its subdirectories) as remote too.
+ // local entries (that belong to its subdirectories but not to the
+ // extra directory) as remote too.
//
// @@ Note that currently the local/ subdirectory of a remote
// directory is considered remote (see above for details). When
@@ -144,7 +164,8 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
//
for (default_options_entry<O>& e: r)
{
- if (!e.remote)
+ if (!e.remote &&
+ (!extra_dir || e.file.directory () != *extra_dir))
{
e.remote = true;
@@ -162,12 +183,34 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
{
dir_path od (d / dir_path (".build2"));
- if (options_dir_exists (od))
+ // If the extra directory is a subdirectory of the current
+ // directory, then load it first, but don't load .build2/ or
+ // .build2/local/ if it matches any of them.
+ //
+ bool load_build2 (true);
+ bool load_build2_local (true);
+
+ if (load_extra && extra_dir->sub (d))
+ {
+ load = load_default_options_files<O, S, U> (*extra_dir,
+ false /* remote */,
+ ofs.files,
+ std::forward<F> (fn),
+ r);
+
+ load_extra = false;
+ load_build2 = *extra_dir != od;
+ load_build2_local = *extra_dir != od / dir_path ("local");
+ }
+
+ if (load && options_dir_exists (od))
load = load_default_options_files<O, S, U> (od,
remote,
ofs.files,
std::forward<F> (fn),
- r);
+ r,
+ load_build2_local,
+ load_build2);
}
if (!load && remote)
@@ -175,35 +218,32 @@ LIBBUTL_MODEXPORT namespace butl //@@ MOD Clang needs this for some reason.
}
}
- if (home_dir)
- {
- assert (home_dir->absolute () && home_dir->normalized ());
+ if (load && load_extra)
+ load = load_default_options_files<O, S, U> (*extra_dir,
+ false /* remote */,
+ ofs.files,
+ std::forward<F> (fn),
+ r);
- if (load)
- {
- dir_path d (*home_dir / dir_path (".build2"));
-
- if (options_dir_exists (d))
- load = load_default_options_files<O, S, U> (d,
- false /* remote */,
- ofs.files,
- std::forward<F> (fn),
- r);
- }
- }
-
- if (sys_dir)
+ if (load && home_dir)
{
- assert (sys_dir->absolute () && sys_dir->normalized ());
-
- if (load && options_dir_exists (*sys_dir))
- load_default_options_files<O, S, U> (*sys_dir,
- false /* remote */,
- ofs.files,
- std::forward<F> (fn),
- r);
+ dir_path d (*home_dir / dir_path (".build2"));
+
+ if (options_dir_exists (d))
+ load = load_default_options_files<O, S, U> (d,
+ false /* remote */,
+ ofs.files,
+ std::forward<F> (fn),
+ r);
}
+ if (load && sys_dir && options_dir_exists (*sys_dir))
+ load_default_options_files<O, S, U> (*sys_dir,
+ false /* remote */,
+ ofs.files,
+ std::forward<F> (fn),
+ r);
+
std::reverse (r.begin (), r.end ());
return r;
diff --git a/tests/default-options/driver.cxx b/tests/default-options/driver.cxx
index 106f70f..764ab44 100644
--- a/tests/default-options/driver.cxx
+++ b/tests/default-options/driver.cxx
@@ -35,7 +35,7 @@ using namespace std;
using namespace butl;
// Usage: argv[0] [-f <file>] [-d <start-dir>] [-s <sys-dir>] [-h <home-dir>]
-// [-e] <cmd-options>
+// [-x <extra-dir>] [-e] [-t] <cmd-options>
//
// Parse default options files, merge them with the command line options, and
// print the resulting options to STDOUT one per line. Note that the options
@@ -55,6 +55,9 @@ using namespace butl;
// -h
// Home directory.
//
+// -x
+// Extra directory.
+//
// -e
// Print the default options entries (rather than the merged options) to
// STDOUT one per line in the following format:
@@ -129,6 +132,7 @@ main (int argc, const char* argv[])
default_options_files fs;
optional<dir_path> sys_dir;
optional<dir_path> home_dir;
+ optional<dir_path> extra_dir;
vector<dir_path> dirs;
options cmd_ops;
bool print_entries (false);
@@ -158,6 +162,11 @@ main (int argc, const char* argv[])
assert (++i != argc);
home_dir = dir_path (argv[i]);
}
+ else if (op == "-x")
+ {
+ assert (++i != argc);
+ extra_dir = dir_path (argv[i]);
+ }
else if (op == "-e")
{
print_entries = true;
@@ -180,6 +189,7 @@ main (int argc, const char* argv[])
load_default_options<options, scanner, unknow_mode> (
sys_dir,
home_dir,
+ extra_dir,
fs,
[trace] (const path& f, bool remote, bool overwrite)
{
diff --git a/tests/default-options/testscript b/tests/default-options/testscript
index 89164d2..41badf3 100644
--- a/tests/default-options/testscript
+++ b/tests/default-options/testscript
@@ -167,17 +167,17 @@ end
+mkdir -p $work_dir/.build2 $cfg1/.build2 $cfg2/.build2 $cfg3/.build2
- +echo 'work' >=$work_dir/.build2/cfg
- +echo 'cfg1' >=$cfg1/.build2/cfg
- +echo 'cfg2' >=$cfg2/.build2/cfg
- +echo 'cfg3' >=$cfg3/.build2/cfg
+ +echo 'work' >=$work_dir/.build2/ops
+ +echo 'cfg1' >=$cfg1/.build2/ops
+ +echo 'cfg2' >=$cfg2/.build2/ops
+ +echo 'cfg3' >=$cfg3/.build2/ops
: exists
:
{
: single
:
- $* -f cfg -d $cfg3 -h $home_dir >>EOO
+ $* -f ops -d $cfg3 -h $home_dir >>EOO
work
cfg2
cfg3
@@ -185,20 +185,20 @@ end
: same
:
- $* -f cfg -d $cfg1 -d $cfg1 -h $home_dir >>EOO
+ $* -f ops -d $cfg1 -d $cfg1 -h $home_dir >>EOO
work
cfg1
EOO
: adjacent
:
- $* -f cfg -d $cfg1 -d $cfg2 -h $home_dir >>EOO
+ $* -f ops -d $cfg1 -d $cfg2 -h $home_dir >>EOO
work
EOO
: nested
:
- $* -f cfg -d $cfg2 -d $cfg3 -h $home_dir >>EOO
+ $* -f ops -d $cfg2 -d $cfg3 -h $home_dir >>EOO
work
cfg2
EOO
@@ -209,7 +209,7 @@ end
{
: home-reached
:
- $* -f cfg -d $cfg1 -d $cfg2 -h $work_dir >>EOO
+ $* -f ops -d $cfg1 -d $cfg2 -h $work_dir >>EOO
work
EOO
@@ -217,7 +217,91 @@ end
:
if ($cxx.target.class != 'windows')
{
- $* -f cfg -d $cfg1 -d /non-existent-directory/cfg2
+ $* -f ops -d $cfg1 -d /non-existent-directory/cfg2
}
}
}
+
+: extra-dir
+:
+{
+ : after-traversal
+ :
+ {
+ home_dir = $canonicalize([dir_path] $~/home);
+ mkdir -p $home_dir/.build2;
+ echo 'home' >=$home_dir/.build2/ops;
+
+ extra_dir = $canonicalize([dir_path] $home_dir/extra);
+ mkdir -p $extra_dir;
+ echo 'extra' >=$extra_dir/ops;
+
+ start_dir = $canonicalize([dir_path] $home_dir/start);
+ mkdir -p $start_dir/.build2;
+ echo 'start' >=$start_dir/.build2/ops;
+
+ $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d
+ %\.+/home/.build2/ops,home,false%
+ %\.+/home/extra/ops,extra,false%
+ %\.+/home/start/.build2/ops,start,false%
+ EOO
+ }
+
+ : inside-traversal
+ :
+ {
+ home_dir = $canonicalize([dir_path] $~/home);
+ mkdir -p $home_dir/.build2;
+ echo 'home' >=$home_dir/.build2/ops;
+
+ d = $home_dir/project/.build2;
+ mkdir -p $d;
+ echo 'project' >=$d/ops;
+
+ touch $home_dir/project/.git;
+
+ d = $home_dir/project/package/.build2;
+ mkdir -p $d;
+ echo 'package' >=$d/ops;
+
+ extra_dir = $canonicalize([dir_path] $home_dir/project/package/extra1);
+ mkdir -p $extra_dir;
+ echo 'extra1' >=$extra_dir/ops;
+
+ start_dir = $canonicalize([dir_path] $home_dir/project/package);
+
+ $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d;
+ %\.+/home/.build2/ops,home,false%
+ %\.+/home/project/.build2/ops,project,true%
+ %\.+/home/project/package/.build2/ops,package,true%
+ %\.+/home/project/package/extra1/ops,extra1,false%
+ EOO
+
+ extra_dir = $canonicalize([dir_path] $home_dir/project/package/.build2);
+
+ $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir/ >>/~%EOO%d;
+ %\.+/home/.build2/ops,home,false%
+ %\.+/home/project/.build2/ops,project,true%
+ %\.+/home/project/package/.build2/ops,package,false%
+ EOO
+
+ extra_dir = $canonicalize([dir_path] $home_dir/project/extra2);
+ mkdir -p $extra_dir;
+ echo 'extra2' >=$extra_dir/ops;
+
+ $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d;
+ %\.+/home/.build2/ops,home,false%
+ %\.+/home/project/.build2/ops,project,true%
+ %\.+/home/project/extra2/ops,extra2,false%
+ %\.+/home/project/package/.build2/ops,package,true%
+ EOO
+
+ extra_dir = $canonicalize([dir_path] $home_dir/project/.build2);
+
+ $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir/ >>/~%EOO%d
+ %\.+/home/.build2/ops,home,false%
+ %\.+/home/project/.build2/ops,project,false%
+ %\.+/home/project/package/.build2/ops,package,true%
+ EOO
+ }
+}