diff options
-rw-r--r-- | libbutl/default-options.mxx | 11 | ||||
-rw-r--r-- | libbutl/default-options.txx | 122 | ||||
-rw-r--r-- | tests/default-options/driver.cxx | 12 | ||||
-rw-r--r-- | tests/default-options/testscript | 104 |
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 + } +} |