diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2022-11-16 07:52:11 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2022-11-16 07:52:11 +0200 |
commit | f80c8ff7ff3b1eef22a3c90943f324d45d855b97 (patch) | |
tree | f44a25aa71de05e11c417dcc01cc3f6b9eca97ee | |
parent | 44b0a5989f76570fc19dc41314f31c4fa9c2039b (diff) |
Initial low verbosity diagnostics rework
28 files changed, 664 insertions, 124 deletions
diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx index 8208ab7..e4960c9 100644 --- a/libbuild2/adhoc-rule-buildscript.cxx +++ b/libbuild2/adhoc-rule-buildscript.cxx @@ -1496,7 +1496,7 @@ namespace build2 { if (verb == 1) { - // @@ TODO (and in default_action() below): + // @@ DIAG (and in default_action() below): // // - we are printing target, not source (like in most other places) // @@ -1521,7 +1521,7 @@ namespace build2 false /* leave */)); if (verb == 1) - text << diag; + text << diag; // @@ DIAG } if (exec_body) @@ -1625,7 +1625,7 @@ namespace build2 { if (verb == 1) { - // @@ TODO: as above (execute_update_file()). + // @@ DIAG: as above (execute_update_file()). // text << *script.diag_name << ' ' << t; } @@ -1643,7 +1643,7 @@ namespace build2 !exec_body /* leave */)); if (verb == 1) - text << diag; + text << diag; // @@ DIAG } if (exec_body) diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx index 8230fd8..5c08a09 100644 --- a/libbuild2/adhoc-rule-cxx.cxx +++ b/libbuild2/adhoc-rule-cxx.cxx @@ -326,6 +326,17 @@ namespace build2 if (!create && (create = !check_sig (bf, psig))) rmdir_r (ctx, pd, false, verbosity); // Never dry-run. + auto diag = [verbosity] (const path& f) + { + if (verb >= verbosity) + { + if (verb >= 2) + text << "cat >" << f; + else if (verb) + print_diag ("save", f); + } + }; + path of; ofdstream ofs; @@ -356,8 +367,7 @@ namespace build2 // of = path (pd / "rule.cxx"); - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << of; + diag (of); ofs.open (of); @@ -487,8 +497,7 @@ namespace build2 // of = bf; - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << of; + diag (of); ofs.open (of); @@ -560,8 +569,7 @@ namespace build2 entry_time et (file_time (of)); - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << of; + diag (of); ofs.open (of); diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index 8f399dd..045024b 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -1637,12 +1637,12 @@ namespace build2 case mode::overwrite: c = l.to_directory () ? "cp -r" : "cp"; break; } - // Note: 'ln foo/ bar/' means a different thing. + // Note: 'ln foo/ bar/' means a different thing (and below). // if (verb >= 2) text << c << ' ' << p.string () << ' ' << l.string (); else - text << c << ' ' << f << " -> " << d; + print_diag (c, f, d); } } @@ -1682,10 +1682,15 @@ namespace build2 case mode::overwrite: c = l.to_directory () ? "cp -r" : "cp"; break; } + // Note: 'ln foo/ bar/' means a different thing (and above) so strip + // trailing directory separator (but keep as path for relative). + // if (verb >= 2) text << c << ' ' << p.string () << ' ' << l.string (); else - text << c << ' ' << p.string () << " -> " << d; + print_diag (c, + p.to_directory () ? path (p.string ()) : p, + d); } } @@ -1737,6 +1742,8 @@ namespace build2 const path& p, const path& l, backlink_mode om, uint16_t verbosity) { + assert (verbosity >= 2); + using mode = backlink_mode; bool d (l.to_directory ()); @@ -1872,6 +1879,11 @@ namespace build2 // // Note that here the dry-run mode is handled by the filesystem functions. + // Note that if we ever need to support level 1 for some reason, maybe + // consider showing the target, for example, `unlink exe{hello} <- dir/`? + // + assert (v >= 2); + using mode = backlink_mode; if (l.to_directory ()) @@ -2898,7 +2910,7 @@ namespace build2 target_state noop_action (action a, const target& t) { - text << "noop action triggered for " << diag_doing (a, t); + error << "noop action triggered for " << diag_doing (a, t); assert (false); // We shouldn't be called (see set_recipe()). return target_state::unchanged; } @@ -2998,7 +3010,7 @@ namespace build2 case rmdir_status::not_empty: { if (verb >= 3) - text << dp << " is current working directory, not removing"; + info << dp << " is current working directory, not removing"; break; } case rmdir_status::not_exist: @@ -3108,6 +3120,9 @@ namespace build2 // Now clean the primary target and its prerequisited in the reverse order // of update: first remove the file, then clean the prerequisites. // + // @@ DIAG: we print removal of individual ad hoc members above instead + // of as group at once ({hxx, cxx}{...}). + // if (clean && !fp.empty () && rmfile (fp, ft)) tr = target_state::changed; @@ -3129,10 +3144,20 @@ namespace build2 { if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3) { - if (ed) - text << "rm -r " << path_cast<dir_path> (ep); - else - text << "rm " << ep; + if (verb >= 2) + { + if (ed) + text << "rm -r " << path_cast<dir_path> (ep); + else + text << "rm " << ep; + } + else if (verb) + { + if (ed) + print_diag ("rm -r", path_cast<dir_path> (ep)); + else + print_diag ("rm", ep); + } } } @@ -3165,6 +3190,8 @@ namespace build2 { if (const target* m = gv.members[gv.count - 1]) { + // @@ DIAG: do we want to show removal of group or each member? + // if (rmfile (m->as<file> ().path (), *m)) tr |= target_state::changed; } @@ -3177,10 +3204,20 @@ namespace build2 { if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3) { - if (ed) - text << "rm -r " << path_cast<dir_path> (ep); - else - text << "rm " << ep; + if (verb >= 2) + { + if (ed) + text << "rm -r " << path_cast<dir_path> (ep); + else + text << "rm " << ep; + } + else if (verb) + { + if (ed) + print_diag ("rm -r", path_cast<dir_path> (ep)); + else + print_diag ("rm", ep); + } } } diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index 756c3fe..e9245f4 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -930,6 +930,8 @@ namespace build2 // Update/clean a backlink issuing appropriate diagnostics at appropriate // levels depending on the overload and the changed argument. // + // Note that these functions assume (target.leaf() == link.leaf ()). + // enum class backlink_mode { link, // Make a symbolic link if possible, hard otherwise. @@ -952,6 +954,8 @@ namespace build2 bool changed, backlink_mode = backlink_mode::link); + // Note: verbosite should be 2 or greater. + // LIBBUILD2_SYMEXPORT void update_backlink (context&, const path& target, @@ -959,6 +963,8 @@ namespace build2 backlink_mode = backlink_mode::link, uint16_t verbosity = 3); + // Note: verbosite should be 2 or greater. + // LIBBUILD2_SYMEXPORT void clean_backlink (context&, const path& link, diff --git a/libbuild2/bash/rule.hxx b/libbuild2/bash/rule.hxx index 5bd7fa7..444d176 100644 --- a/libbuild2/bash/rule.hxx +++ b/libbuild2/bash/rule.hxx @@ -29,7 +29,7 @@ namespace build2 class LIBBUILD2_BASH_SYMEXPORT in_rule: public in::rule { public: - in_rule (): rule ("bash.in 1", "bash.in", '@', false /* strict */) {} + in_rule (): rule ("bash.in 1", "bash", '@', false /* strict */) {} virtual bool match (action, target&, const string&, match_extra&) const override; diff --git a/libbuild2/bin/def-rule.cxx b/libbuild2/bin/def-rule.cxx index b4fbe0f..2879ca9 100644 --- a/libbuild2/bin/def-rule.cxx +++ b/libbuild2/bin/def-rule.cxx @@ -720,8 +720,12 @@ namespace build2 const char*& arg (*(args.end () - 2)); + // We could print the prerequisite if it's a single obj{}/libu{} (with + // the latter being the common case). But it doesn't feel like that's + // worth the variability and the associated possibility of confusion. + // if (verb == 1) - text << "def " << t; + print_diag ("def", t); diag_buffer dbuf (ctx); diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index 2534058..5693334 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -7247,7 +7247,7 @@ namespace build2 // @@ TODO: why don't we print env (here and/or below)? Also link rule. // if (verb == 1) - text << x_name << ' ' << s; + print_diag (x_name, s, t); else if (verb == 2) print_process (args); diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx index 0b4d1e1..5118332 100644 --- a/libbuild2/cc/install-rule.cxx +++ b/libbuild2/cc/install-rule.cxx @@ -271,9 +271,9 @@ namespace build2 const scope& rs (t.root_scope ()); auto& lp (t.data<install_match_data> (perform_uninstall_id).libs_paths); - auto rm = [&rs, &id] (const path& l) + auto rm = [&rs, &id] (const path& f, const path& l) { - return uninstall_f (rs, id, nullptr, l.leaf (), 2 /* verbosity */); + return uninstall_l (rs, id, f.leaf (), l.leaf (), 2 /* verbosity */); }; const path& lk (lp.link); @@ -281,10 +281,12 @@ namespace build2 const path& so (lp.soname); const path& in (lp.interm); - if (!lk.empty ()) r = rm (lk) || r; - if (!ld.empty ()) r = rm (ld) || r; - if (!so.empty ()) r = rm (so) || r; - if (!in.empty ()) r = rm (in) || r; + const path* f (lp.real); + + if (!in.empty ()) {r = rm (*f, in) || r; f = ∈} + if (!so.empty ()) {r = rm (*f, so) || r; f = &so;} + if (!ld.empty ()) {r = rm (*f, ld) || r; f = &ld;} + if (!lk.empty ()) {r = rm (*f, lk) || r; } } return r; diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index c2ba8e7..24dc373 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -3825,7 +3825,7 @@ namespace build2 } if (verb == 1) - text << (lt.static_library () ? "ar " : "ld ") << t; + print_diag (lt.static_library () ? "ar" : "ld", t); else if (verb == 2) print_process (args); diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx index 87515e3..eae328e 100644 --- a/libbuild2/cc/pkgconfig.cxx +++ b/libbuild2/cc/pkgconfig.cxx @@ -1399,10 +1399,10 @@ namespace build2 // Note that generation can take some time if we have a large number of // prerequisite libraries. // - if (verb) - text << "pc " << *t; - else if (verb >= 2) + if (verb >= 2) text << "cat >" << p; + else if (verb) + print_diag ("pc", g, *t); if (ctx.dry_run) return; diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx index 3dd8729..34ed402 100644 --- a/libbuild2/config/operation.cxx +++ b/libbuild2/config/operation.cxx @@ -61,8 +61,10 @@ namespace build2 path f (src_root / rs.root_extra->out_root_file); - if (verb) - text << (verb >= 2 ? "cat >" : "save ") << f; + if (verb >= 2) + text << "cat >" << f; + else if (verb) + print_diag ("save", f); try { @@ -566,8 +568,10 @@ namespace build2 if (f.string () == "-") fn.name = "<stdout>"; - if (verb) - text << (verb >= 2 ? "cat >" : "save ") << fn; + if (verb >= 2) + text << "cat >" << fn; + else if (verb) + print_diag ("save", fn); try { @@ -678,7 +682,7 @@ namespace build2 // if (out_root != src_root) { - mkdir_p (out_root / rs.root_extra->build_dir); + mkdir_p (out_root / rs.root_extra->build_dir, 1); mkdir (out_root / rs.root_extra->bootstrap_dir, 2); } @@ -1402,7 +1406,8 @@ namespace build2 string ("config"), /* config_module */ nullopt, /* config_file */ true, /* buildfile */ - "the create meta-operation"); + "the create meta-operation", + 1 /* verbosity */); save_config (ctx, d); } diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx index 110641a..fda24f7 100644 --- a/libbuild2/diagnostics.cxx +++ b/libbuild2/diagnostics.cxx @@ -47,6 +47,138 @@ namespace build2 // const int stream_verb_index = ostream::xalloc (); + // print_{do,undo}() + // + void + print_diag_impl (const char* p, target_key* l, target_key&& r, const char* c) + { + // @@ Print directly to diag_stream (and below)? Won't we be holding + // the lock longer? + + diag_record dr (text); + + dr << p << ' '; + + if (l != nullptr) + { + // Omit the @.../ qualification in either lhs or rhs if it's implied by + // the other. + // + // @@ Shouldn't we, strictly speaking, also check that they belong to + // the same project? Though it would be far-fetched to use another + // project's target from src. Or maybe not. + // + if (!l->out->empty ()) + { + if (r.out->empty ()) + l->out = &empty_dir_path; + } + else if (!r.out->empty ()) + r.out = &empty_dir_path; + + dr << *l << ' ' << (c == nullptr ? "->" : c) << ' '; + } + + dr << r; + } + + // Note: these can't be inline since need the target class definition. + // + void + print_diag (const char* p, const target& l, const target& r, const char* c) + { + target_key lk (l.key ()); + print_diag_impl (p, &lk, r.key (), c); + } + + void + print_diag (const char* p, target_key&& l, const target& r, const char* c) + { + print_diag_impl (p, &l, r.key (), c); + } + + void + print_diag (const char* p, const target& l, target_key&& r, const char* c) + { + target_key lk (l.key ()); + print_diag_impl (p, &lk, move (r), c); + } + + void + print_diag (const char* p, const string& l, const target& r, const char* c) + { + return print_diag (p, l, r.key (), c); + } + + void + print_diag (const char* p, const string& l, target_key&& r, const char* c) + { + text << p << ' ' + << l << (l.empty () ? "" : " ") + << (c == nullptr ? "->" : c) << ' ' + << r; + } + + void + print_diag (const char* p, const target& r) + { + print_diag_impl (p, nullptr, r.key (), nullptr); + } + + void + print_diag (const char* p, const dir_path& r) + { + text << p << ' ' << r; + } + + void + print_diag (const char* p, const path_name_view& r) + { + text << p << ' ' << r; + } + + void + print_diag (const char* p, const target& l, const dir_path& r, const char* c) + { + // @@ TODO: out qualification stripping: only do if p.out is subdir of t + // (also below)? + + text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + + void + print_diag (const char* p, + const target& l, const path_name_view& r, + const char* c) + { + text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + + void + print_diag (const char* p, const path& l, const dir_path& r, const char* c) + { + text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + + void + print_diag (const char* p, + const path& l, const path_name_view& r, + const char* c) + { + text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + + void + print_diag (const char* p, + const string& l, const path_name_view& r, + const char* c) + { + text << p << ' ' + << l << (l.empty () ? "" : " ") + << (c == nullptr ? "->" : c) << ' ' + << r; + } + // print_process() // void diff --git a/libbuild2/diagnostics.hxx b/libbuild2/diagnostics.hxx index 2505e2d..a4509e4 100644 --- a/libbuild2/diagnostics.hxx +++ b/libbuild2/diagnostics.hxx @@ -21,6 +21,171 @@ namespace build2 // class failed: public std::exception {}; + // Print low-verbosity recipe diagnostics in the forms: + // + // <prog> <l-target> <comb> <r-target> + // <prog> <r-target> + // + // Where <prog> is an abbreviated/generalized program name, such as c++ + // (rather than g++ or clang++) or yacc (rather than bison or byacc), + // <l-target> is typically the "main" prerequisite target, such as the C++ + // source file to compile, <r-target> is typically the target being + // produced, and <comb> is the combiner, typically "->". + // + // The second form (without <l-target> and <comb>) should be used when there + // is no natural "main" prerequisite, for example, for linking as well as + // for programs that act upon the target, such as mkdir, rm, test, etc. + // + // Note also that these functions omit the @.../ qualification in either + // <l-target> or <r-target> if it's implied by the other. + // + // For example: + // + // mkdir fsdir{details/} + // c++ cxx{hello} -> obje{hello} + // ld exe{hello} + // + // test exe{hello} + testscript + // + // install exe{hello} -> /usr/bin/ + // uninstall exe{hello} <- /usr/bin/ + // + // rm exe{hello} + // rm obje{hello} + // rmdir fsdir{details/} + // + // Examples of target groups: + // + // cli cli{foo} -> {hxx cxx}{foo} + // + // thrift thrift{foo} -> {hxx cxx}{foo-types} + // -> {hxx cxx}{foo-stubs} + // + // Potentially we could also support target groups for <l-target>: + // + // tool {hxx cxx}{foo} -> {hxx cxx}{foo-types} + // + // tool {hxx cxx}{foo-types} + // {hxx cxx}{foo-stubs} -> {hxx cxx}{foo-insts} + // {hxx cxx}{foo-impls} + // + // Note: see GH issue #40 for additional background and rationale. + // + // If <comb> is not specified, then "->" is used by default. + + // prog target -> target + // + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const target& l, const target& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + target_key&& l, const target& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const target& l, target_key&& r, + const char* comb = nullptr); + + void + print_diag (const char* prog, + target_key&& l, target_key&& r, + const char* comb = nullptr); + + // prog string -> target + // + // Use these versions if, for example, input information is passed as an + // argument. + // + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const string& l, const target& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const string& l, target_key&& r, + const char* comb = nullptr); + + // prog target + // + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, const target&); + + void + print_diag (const char* prog, target_key&&); + + // prog path + // + // Special versions for cases like mkdir/rmdir, save, etc. + // + // Note: use path_name("-") if the result is written to stdout. + // + void + print_diag (const char* prog, const path&); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, const dir_path&); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, const path_name_view&); + + // Special versions for ln, cp, rm, install/unistall, dist, etc. + // + // Note: use path_name ("-") if the result is written to stdout. + + // target -> path + // + void + print_diag (const char* prog, + const target& l, const path& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const target& l, const dir_path& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const target& l, const path_name_view& r, + const char* comb = nullptr); + + // path -> path + // + void + print_diag (const char* prog, + const path& l, const path& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const path& l, const dir_path& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const path& l, const path_name_view& r, + const char* comb = nullptr); + + // string -> path + // + // Use this version if, for example, input information is passed as an + // argument. + // + void + print_diag (const char* prog, + const string& l, const path& r, + const char* comb = nullptr); + + LIBBUILD2_SYMEXPORT void + print_diag (const char* prog, + const string& l, const path_name_view& r, + const char* comb = nullptr); + // Print process commmand line. If the number of elements is specified (or // the const cstrings& version is used), then it will print the piped multi- // process command line, if present. In this case, the expected format is as @@ -770,4 +935,6 @@ namespace build2 } } +#include <libbuild2/diagnostics.ixx> + #endif // LIBBUILD2_DIAGNOSTICS_HXX diff --git a/libbuild2/diagnostics.ixx b/libbuild2/diagnostics.ixx new file mode 100644 index 0000000..7c1a432 --- /dev/null +++ b/libbuild2/diagnostics.ixx @@ -0,0 +1,44 @@ +// file : libbuild2/diagnostics.ixx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +namespace build2 +{ + LIBBUILD2_SYMEXPORT void + print_diag_impl (const char*, target_key*, target_key&&, const char*); + + inline void + print_diag (const char* p, target_key&& l, target_key&& r, const char* c) + { + print_diag_impl (p, &l, move (r), c); + } + + inline void + print_diag (const char* p, target_key& r) + { + print_diag_impl (p, nullptr, move (r), nullptr); + } + + inline void + print_diag (const char* p, const path& r) + { + print_diag (p, path_name (&r)); + } + + inline void + print_diag (const char* p, const target& l, const path& r, const char* c) + { + print_diag (p, l, path_name (&r), c); + } + + inline void + print_diag (const char* p, const path& l, const path& r, const char* c) + { + print_diag (p, l, path_name (&r), c); + } + + inline void + print_diag (const char* p, const string& l, const path& r, const char* c) + { + print_diag (p, l, path_name (&r), c); + } +} diff --git a/libbuild2/dist/operation.cxx b/libbuild2/dist/operation.cxx index 078a8e2..c7ce7f2 100644 --- a/libbuild2/dist/operation.cxx +++ b/libbuild2/dist/operation.cxx @@ -239,6 +239,8 @@ namespace build2 const string& dist_package (cast<string> (l)); const process_path& dist_cmd (cast<process_path> (rs.vars["dist.cmd"])); + dir_path td (dist_root / dir_path (dist_package)); + // We used to print 'dist <target>' at verbosity level 1 but that has // proven to be just noise. Though we still want to print something // since otherwise, once the progress line is cleared, we may end up @@ -248,7 +250,7 @@ namespace build2 // (e.g., output directory creation) in all the operations below. // if (verb == 1) - text << "dist " << dist_package; + print_diag ("dist", src_root, td); // Get the list of files to distribute. // @@ -496,8 +498,6 @@ namespace build2 // auto_project_env penv (rs); - dir_path td (dist_root / dir_path (dist_package)); - // Clean up the target directory. // if (rmdir_r (ctx, td, true, 2) == rmdir_status::not_empty) @@ -802,7 +802,7 @@ namespace build2 // path ap (dir / an); if (exists (ap, false)) - rmfile (ctx, ap); + rmfile (ctx, ap, 3 /* verbosity */); // Use zip for .zip archives. Also recognize and handle a few well-known // tar.xx cases (in case tar doesn't support -a or has other issues like @@ -932,7 +932,7 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << args[0] << ' ' << ap; + print_diag (args[0], dir / dir_path (pkg), ap); process apr; process cpr; @@ -986,7 +986,7 @@ namespace build2 // path cp (dir / cn); if (exists (cp, false)) - rmfile (ctx, cp); + rmfile (ctx, cp, 3 /* verbosity */); auto_rmfile c_rm; // Note: must come first. auto_fd c_fd; @@ -1025,7 +1025,7 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << args[0] << ' ' << cp; + print_diag (args[0], ap, cp); // Note that to only get the archive name (without the directory) in // the output we have to run from the archive's directory. @@ -1058,7 +1058,7 @@ namespace build2 if (verb >= 2) text << "cat >" << cp; else if (verb) - text << e << "sum " << cp; + print_diag ((e + "sum").c_str (), ap, cp); string c; try diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index 8666520..3ded45e 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -3299,13 +3299,23 @@ namespace build2 // mkdir (d / std_build_dir, verbosity); + auto diag = [verbosity] (const path& f) + { + if (verb >= verbosity) + { + if (verb >= 2) + text << "cat >" << f; + else if (verb) + print_diag ("save", f); + } + }; + // Write build/bootstrap.build. // { path f (d / std_bootstrap_file); - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + diag (f); try { @@ -3351,8 +3361,7 @@ namespace build2 { path f (d / std_root_file); - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + diag (f); try { @@ -3400,8 +3409,7 @@ namespace build2 { path f (d / std_build_dir / "config.build"); // std_config_file - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + diag (f); try { @@ -3426,8 +3434,7 @@ namespace build2 { path f (d / std_buildfile_file); - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; + diag (f); try { diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx index be7ea81..f5eb3f9 100644 --- a/libbuild2/file.hxx +++ b/libbuild2/file.hxx @@ -493,7 +493,7 @@ namespace build2 const optional<string>& config_file, // Ad hoc config.build contents. bool buildfile, // Create root buildfile. const char* who, // Who is creating it. - uint16_t verbosity = 1); // Diagnostic verbosity. + uint16_t verbosity); // Diagnostic verbosity. } #include <libbuild2/file.ixx> diff --git a/libbuild2/filesystem.cxx b/libbuild2/filesystem.cxx index 2e3309d..32895c4 100644 --- a/libbuild2/filesystem.cxx +++ b/libbuild2/filesystem.cxx @@ -15,7 +15,12 @@ namespace build2 touch (context& ctx, const path& p, bool create, uint16_t v) { if (verb >= v) - text << "touch " << p; + { + if (verb >= 2) + text << "touch " << p; + else if (verb) + print_diag ("touch", p); + } if (ctx.dry_run) return; @@ -59,7 +64,12 @@ namespace build2 catch (const system_error& e) { if (verb >= v) - text << "mkdir " << d; + { + if (verb >= 2) + text << "mkdir " << d; + else if (verb) + print_diag ("mkdir", d); + } fail << "unable to create directory " << d << ": " << e << endf; } @@ -67,7 +77,12 @@ namespace build2 if (ms == mkdir_status::success) { if (verb >= v) - text << "mkdir " << d; + { + if (verb >= 2) + text << "mkdir " << d; + else if (verb) + print_diag ("mkdir", d); + } } return ms; @@ -88,7 +103,12 @@ namespace build2 catch (const system_error& e) { if (verb >= v) - text << "mkdir -p " << d; + { + if (verb >= 2) + text << "mkdir -p " << d; + else if (verb) + print_diag ("mkdir -p", d); + } fail << "unable to create directory " << d << ": " << e << endf; } @@ -96,7 +116,12 @@ namespace build2 if (ms == mkdir_status::success) { if (verb >= v) - text << "mkdir -p " << d; + { + if (verb >= 2) + text << "mkdir -p " << d; + else if (verb) + print_diag ("mkdir -p", d); + } } return ms; @@ -106,7 +131,12 @@ namespace build2 mvfile (const path& f, const path& t, uint16_t v) { if (verb >= v) - text << "mv " << f << ' ' << t; + { + if (verb >= 2) + text << "mv " << f << ' ' << t; + else if (verb) + print_diag ("mv", f, t); + } try { @@ -129,7 +159,15 @@ namespace build2 auto print = [&p, v] () { if (verb >= v) - text << "rm " << p.string (); + { + // Note: strip trailing directory separator (but keep as path for + // relative). + // + if (verb >= 2) + text << "rm " << p.string (); + else if (verb) + print_diag ("rm", p.to_directory () ? path (p.string ()) : p); + } }; rmfile_status rs; @@ -166,7 +204,12 @@ namespace build2 return rmdir_status::not_exist; if (verb >= v) - text << "rmdir -r " << d; + { + if (verb >= 2) + text << "rmdir -r " << d; + else if (verb) + print_diag ("rmdir -r", d); + } if (!ctx.dry_run) { diff --git a/libbuild2/filesystem.hxx b/libbuild2/filesystem.hxx index 565e832..2998cec 100644 --- a/libbuild2/filesystem.hxx +++ b/libbuild2/filesystem.hxx @@ -73,10 +73,10 @@ namespace build2 using mkdir_status = butl::mkdir_status; LIBBUILD2_SYMEXPORT fs_status<mkdir_status> - mkdir (const dir_path&, uint16_t verbosity = 1); + mkdir (const dir_path&, uint16_t verbosity); LIBBUILD2_SYMEXPORT fs_status<mkdir_status> - mkdir_p (const dir_path&, uint16_t verbosity = 1); + mkdir_p (const dir_path&, uint16_t verbosity); // Rename a file (or file symlink) overwriting the destination if exists. // @@ -166,7 +166,7 @@ namespace build2 // LIBBUILD2_SYMEXPORT fs_status<mkdir_status> mkdir_buildignore (context&, - const dir_path&, const path&, uint16_t verbosity = 1); + const dir_path&, const path&, uint16_t verbosity); // Return true if the directory is empty or only contains the .buildignore // file. Fail if the directory doesn't exist. diff --git a/libbuild2/filesystem.txx b/libbuild2/filesystem.txx index 7404532..7e3a773 100644 --- a/libbuild2/filesystem.txx +++ b/libbuild2/filesystem.txx @@ -1,8 +1,6 @@ // file : libbuild2/filesystem.txx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <type_traits> // is_base_of - #include <libbuild2/diagnostics.hxx> namespace build2 @@ -24,7 +22,7 @@ namespace build2 if (verb >= 2) text << "rm " << f; else if (verb) - text << "rm " << t; + print_diag ("rm", t); // T can be target or path. } }; @@ -65,7 +63,7 @@ namespace build2 if (verb >= 2) text << "rmdir " << d; else if (verb) - text << (std::is_base_of<dir_path, T>::value ? "rmdir " : "rm ") << t; + print_diag ("rmdir", t); // T can be target or dir_path. } }; @@ -94,7 +92,7 @@ namespace build2 { if (verb >= v && verb >= 2) { - text << d << " is " + info << d << " is " << (w ? "current working directory" : "not empty") << ", not removing"; } diff --git a/libbuild2/in/rule.cxx b/libbuild2/in/rule.cxx index 07c11c6..74bc2a7 100644 --- a/libbuild2/in/rule.cxx +++ b/libbuild2/in/rule.cxx @@ -326,7 +326,7 @@ namespace build2 } } - text << program_ << ' ' << ik; + print_diag (program_.c_str (), move (ik), t); } // Read and process the file, one line at a time, while updating depdb. diff --git a/libbuild2/install/rule.cxx b/libbuild2/install/rule.cxx index 8fd180c..36a06fa 100644 --- a/libbuild2/install/rule.cxx +++ b/libbuild2/install/rule.cxx @@ -845,7 +845,7 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << "install " << chd; + print_diag ("install -d", chd); // See also `install -l` below. } run (ctx, @@ -901,7 +901,12 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << "install " << t; + { + if (name.empty ()) + print_diag ("install", t, chd); + else + print_diag ("install", t, chd / name); + } } if (!ctx.dry_run) @@ -919,7 +924,9 @@ namespace build2 { context& ctx (rs.ctx); - path rell (relative (chroot_path (rs, base.dir))); + dir_path chd (chroot_path (rs, base.dir)); + + path rell (relative (chd)); rell /= link; // We can create a symlink directly without calling ln. This, however, @@ -946,7 +953,13 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << "install " << rell << " -> " << target; + { + // Without a flag it's unclear (unlike with ln) that we are creating + // a link. FreeBSD install(1) has the -l flag with the appropriate + // semantics. For consistency, we also pass -d above. + // + print_diag ("install -l", target, chd / link); + } } if (!ctx.dry_run) @@ -966,7 +979,7 @@ namespace build2 if (verb >= 2) text << "ln -sf " << target.string () << ' ' << rell.string (); else if (verb) - text << "install " << rell << " -> " << target; + print_diag ("install -l", target, chd / link); } if (!ctx.dry_run) @@ -1152,7 +1165,7 @@ namespace build2 if (verb >= 2) text << "rmdir " << reld; else if (verb) - text << "uninstall " << reld; + print_diag ("uninstall -d", chd); } try @@ -1182,7 +1195,7 @@ namespace build2 if (verb >= 2) print_process (args); else if (verb) - text << "uninstall " << reld; + print_diag ("uninstall -d", chd); } diag_buffer dbuf (rs.ctx); @@ -1218,42 +1231,16 @@ namespace build2 return r; } - bool file_rule:: - uninstall_f (const scope& rs, - const install_dir& base, - const file* t, - const path& name, - uint16_t verbosity) + static void + uninstall_f_impl (const scope& rs, + const install_dir& base, + const path& f, + uint16_t verbosity) { context& ctx (rs.ctx); - assert (t != nullptr || !name.empty ()); - path f (chroot_path (rs, base.dir) / - (name.empty () ? t->path ().leaf () : name)); - - try - { - // Note: don't follow symlinks so if the target is a dangling symlinks - // we will proceed to removing it. - // - if (!file_exists (f, false)) // May throw (e.g., EACCES). - return false; - } - catch (const system_error& e) - { - fail << "invalid installation path " << f << ": " << e; - } - path relf (relative (f)); - if (verb >= verbosity && verb == 1) - { - if (t != nullptr) - text << "uninstall " << *t; - else - text << "uninstall " << relf; - } - // The same story as with uninstall -d (on Windows rm is also from // MSYS2/Cygwin). // @@ -1300,7 +1287,86 @@ namespace build2 pp, args, verb >= verbosity ? 1 : verb_never /* finish_verbosity */); } + } + + bool file_rule:: + uninstall_f (const scope& rs, + const install_dir& base, + const file* t, + const path& name, + uint16_t verbosity) + { + assert (t != nullptr || !name.empty ()); + + dir_path chd (chroot_path (rs, base.dir)); + path f (chd / (name.empty () ? t->path ().leaf () : name)); + + try + { + // Note: don't follow symlinks so if the target is a dangling symlinks + // we will proceed to removing it. + // + if (!file_exists (f, false)) // May throw (e.g., EACCES). + return false; + } + catch (const system_error& e) + { + fail << "invalid installation path " << f << ": " << e; + } + + if (verb >= verbosity && verb == 1) + { + if (t != nullptr) + { + if (name.empty ()) + print_diag ("uninstall ", *t, chd, "<-"); + else + print_diag ("uninstall ", *t, f, "<-"); + } + else + print_diag ("uninstall ", f); + } + + uninstall_f_impl (rs, base, f, verbosity); + return true; + } + + bool file_rule:: + uninstall_l (const scope& rs, + const install_dir& base, + const path& /*target*/, + const path& link, + uint16_t verbosity) + { + dir_path chd (chroot_path (rs, base.dir)); + path f (chd / link); + + try + { + // Note: don't follow symlinks so if the target is a dangling symlinks + // we will proceed to removing it. + // + if (!file_exists (f, false)) // May throw (e.g., EACCES). + return false; + } + catch (const system_error& e) + { + fail << "invalid installation path " << f << ": " << e; + } + + if (verb >= verbosity && verb == 1) + { + // It's dubious showing the link target path adds anything useful + // here. + // +#if 0 + print_diag ("uninstall -l", target, f, "<-"); +#else + print_diag ("uninstall -l", f); +#endif + } + uninstall_f_impl (rs, base, f, verbosity); return true; } diff --git a/libbuild2/install/rule.hxx b/libbuild2/install/rule.hxx index ad9d6e7..98d2d0d 100644 --- a/libbuild2/install/rule.hxx +++ b/libbuild2/install/rule.hxx @@ -233,6 +233,19 @@ namespace build2 const path& name, uint16_t verbosity = 1); + // Uninstall (remove) a symlink. + // + // This is essentially unistall_f() but with better low-verbosity + // diagnostics. + // + static bool + uninstall_l (const scope& rs, + const install_dir& base, + const path& target, + const path& link, + uint16_t verbosity = 1); + + // Uninstall (remove) an empty directory. // // uninstall -d <dir> diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 210f1ef..e5d5248 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -240,7 +240,7 @@ namespace build2 if (verb >= 2) text << "mkdir " << d; else if (verb && t.ctx.current_diag_noise) - text << "mkdir " << t; + print_diag ("mkdir", t); }; // Note: ignoring the dry_run flag. diff --git a/libbuild2/test/rule.cxx b/libbuild2/test/rule.cxx index 8a754e5..5cdd8fb 100644 --- a/libbuild2/test/rule.cxx +++ b/libbuild2/test/rule.cxx @@ -540,11 +540,19 @@ namespace build2 if (verb) { - diag_record dr (text); - dr << "test " << ts; - - if (!t.is_a<alias> ()) - dr << ' ' << t; + // If the target is an alias, then testscript itself is the + // target. + // + if (t.is_a<alias> ()) + print_diag ("test", ts); + else + { + // In this case the test is really a combination of the target + // and testscript and using "->" feels off. Also, let's list the + // testscript after the target even though its a source. + // + print_diag ("test", t, ts, "+"); + } } res.push_back (ctx.dry_run @@ -1247,7 +1255,7 @@ namespace build2 if (verb >= 2) print_process (args); // Note: prints the whole pipeline. else if (verb) - text << "test " << tt; + print_diag ("test", tt); if (!ctx.dry_run) { diff --git a/libbuild2/version/rule.hxx b/libbuild2/version/rule.hxx index 2903dbf..0bdc090 100644 --- a/libbuild2/version/rule.hxx +++ b/libbuild2/version/rule.hxx @@ -20,7 +20,7 @@ namespace build2 class in_rule: public in::rule { public: - in_rule (): rule ("version.in 2", "version.in") {} + in_rule (): rule ("version.in 2", "version") {} virtual bool match (action, target&) const override; diff --git a/tests/cc/modules/modules.testscript b/tests/cc/modules/modules.testscript index 681238a..8762885 100644 --- a/tests/cc/modules/modules.testscript +++ b/tests/cc/modules/modules.testscript @@ -354,7 +354,7 @@ $* test --verbose 1 <<EOI 2>>EOE; exe{test}: cxx{driver} {mxx}{foo-core} exe{test}: test.arguments = two EOI - c++ cxx{driver} + c++ cxx{driver} -> obje{driver} ld exe{test} test exe{test} EOE diff --git a/tests/test/simple/generated/testscript b/tests/test/simple/generated/testscript index 878120a..49ddbbd 100644 --- a/tests/test/simple/generated/testscript +++ b/tests/test/simple/generated/testscript @@ -193,7 +193,7 @@ EOI file{input}: in{input} $src_root/manifest #@@ in module file{output}: in{output} $src_root/manifest #@@ in module EOI - %version\.in in\{.+\}%{2} + %version in\{.+\} -> .+%{2} test dir{./} error: test dir{./} failed % error: process .+driver.* terminated: execution timeout expired% |