From 79a760af92146a63e337c4399ec57134f56d8886 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 9 Apr 2019 09:00:29 +0200 Subject: Add dry-run support to install/uninstall rules --- build2/filesystem.hxx | 2 +- build2/install/rule.cxx | 51 +++++++++++++++++--------- build2/install/rule.hxx | 2 +- build2/version/utility.cxx | 91 ++++++++++++++++++++++++---------------------- 4 files changed, 82 insertions(+), 64 deletions(-) diff --git a/build2/filesystem.hxx b/build2/filesystem.hxx index 2044141..91ee418 100644 --- a/build2/filesystem.hxx +++ b/build2/filesystem.hxx @@ -15,7 +15,7 @@ // Compared to the libbutl's versions, these handle errors and issue // diagnostics. Some of them also print the corresponding command line // equivalent at the specified verbosity level. Note that most of such -// functions also handle the dry_run flag. +// functions also respect the dry_run flag. // namespace build2 { diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx index a30cbd3..85bd501 100644 --- a/build2/install/rule.cxx +++ b/build2/install/rule.cxx @@ -690,15 +690,25 @@ namespace build2 // install -d // - // If verbose is false, then only print the command at verbosity level 2 - // or higher. - // static void install_d (const scope& rs, const install_dir& base, const dir_path& d, bool verbose = true) { + // Here is the problem: if this is a dry-run, then we will keep showing + // the same directory creation commands over and over again (because we + // don't actually create them). There are two alternative ways to solve + // this: actually create the directories or simply don't show anything. + // While we use the former approach during update (see mkdir() in + // filesystem), here it feels like we really shouldn't be touching the + // destination filesystem. Plus, not showing anything will be symmetric + // with uninstall since the directories won't be empty (because we don't + // actually uninstall any files). + // + if (dry_run) + return; + dir_path chd (chroot_path (rs, d)); try @@ -760,9 +770,6 @@ namespace build2 // install / // install // - // If verbose is false, then only print the command at verbosity level 2 - // or higher. - // static void install_f (const scope& rs, const install_dir& base, @@ -809,7 +816,8 @@ namespace build2 else if (verb && verbose) text << "install " << t; - run (pp, args); + if (!dry_run) + run (pp, args); } void file_rule:: @@ -844,7 +852,8 @@ namespace build2 else if (verb && verbose) text << "install " << rell << " -> " << target; - run (pp, args); + if (!dry_run) + run (pp, args); } target_state file_rule:: @@ -952,15 +961,17 @@ namespace build2 // itself unless base == dir. Return false if nothing has been removed // (i.e., the directories do not exist or are not empty). // - // If verbose is false, then only print the command at verbosity level 2 - // or higher. - // static bool uninstall_d (const scope& rs, const install_dir& base, const dir_path& d, bool verbose) { + // See install_d() for the rationale. + // + if (dry_run) + return false; + dir_path chd (chroot_path (rs, d)); // Figure out if we should try to remove this directory. Note that if @@ -1086,13 +1097,16 @@ namespace build2 if (verb >= 2) text << "rm " << relf; - try + if (!dry_run) { - try_rmfile (f); - } - catch (const system_error& e) - { - fail << "unable to remove file " << f << ": " << e; + try + { + try_rmfile (f); + } + catch (const system_error& e) + { + fail << "unable to remove file " << f << ": " << e; + } } } else @@ -1112,7 +1126,8 @@ namespace build2 if (verb >= 2) print_process (args); - run (pp, args); + if (!dry_run) + run (pp, args); } return true; diff --git a/build2/install/rule.hxx b/build2/install/rule.hxx index ec4b9bf..526683d 100644 --- a/build2/install/rule.hxx +++ b/build2/install/rule.hxx @@ -154,7 +154,7 @@ namespace build2 // Installation/uninstallation "commands". // // If verbose is false, then only print the command at verbosity level 2 - // or higher. + // or higher. Note that these functions respect the dry_run flag. // Install a symlink: base/link -> target. // diff --git a/build2/version/utility.cxx b/build2/version/utility.cxx index 4222fff..6c4d43e 100644 --- a/build2/version/utility.cxx +++ b/build2/version/utility.cxx @@ -18,61 +18,64 @@ namespace build2 auto_rmfile fixup_manifest (const path& in, path out, const standard_version& v) { - auto_rmfile r (move (out)); + auto_rmfile r (move (out), !dry_run /* active */); - try + if (!dry_run) { - permissions perm (path_permissions (in)); - - ifdstream ifs (in); - manifest_parser p (ifs, in.string ()); + try + { + permissions perm (path_permissions (in)); - auto_fd ofd (fdopen (r.path, - fdopen_mode::out | - fdopen_mode::create | - fdopen_mode::exclusive | - fdopen_mode::binary, - perm)); + ifdstream ifs (in); + manifest_parser p (ifs, in.string ()); - ofdstream ofs (move (ofd)); - manifest_serializer s (ofs, r.path.string ()); + auto_fd ofd (fdopen (r.path, + fdopen_mode::out | + fdopen_mode::create | + fdopen_mode::exclusive | + fdopen_mode::binary, + perm)); - manifest_name_value nv (p.next ()); - assert (nv.name.empty () && nv.value == "1"); // We just loaded it. - s.next (nv.name, nv.value); - - for (nv = p.next (); !nv.empty (); nv = p.next ()) - { - if (nv.name == "version") - nv.value = v.string (); + ofdstream ofs (move (ofd)); + manifest_serializer s (ofs, r.path.string ()); + manifest_name_value nv (p.next ()); + assert (nv.name.empty () && nv.value == "1"); // We just loaded it. s.next (nv.name, nv.value); - } - s.next (nv.name, nv.value); // End of manifest. - s.next (nv.name, nv.value); // End of stream. + for (nv = p.next (); !nv.empty (); nv = p.next ()) + { + if (nv.name == "version") + nv.value = v.string (); - ofs.close (); - ifs.close (); + s.next (nv.name, nv.value); + } - return r; - } - catch (const manifest_parsing& e) - { - location l (&in, e.line, e.column); - fail (l) << e.description << endf; - } - catch (const manifest_serialization& e) - { - location l (&r.path); - fail (l) << e.description << endf; - } - catch (const io_error& e) - { - fail << "io error: " << e << - info << "while reading " << in << - info << "while writing " << r.path << endf; + s.next (nv.name, nv.value); // End of manifest. + s.next (nv.name, nv.value); // End of stream. + + ofs.close (); + ifs.close (); + } + catch (const manifest_parsing& e) + { + location l (&in, e.line, e.column); + fail (l) << e.description; + } + catch (const manifest_serialization& e) + { + location l (&r.path); + fail (l) << e.description; + } + catch (const io_error& e) + { + fail << "io error: " << e << + info << "while reading " << in << + info << "while writing " << r.path; + } } + + return r; } } } -- cgit v1.1