From 0dc03d406a9958adb27ff49f568685f6e80f01ce Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Feb 2018 10:29:03 +0200 Subject: Add progress to dist meta-operation --- build2/b.cxx | 12 ++++----- build2/config/operation.cxx | 13 +++++---- build2/diagnostics.hxx | 16 +++++++++++ build2/dist/operation.cxx | 65 +++++++++++++++++++++++++++++++++++++-------- build2/operation.cxx | 17 ++++++------ build2/operation.hxx | 17 +++++++++--- 6 files changed, 103 insertions(+), 37 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index 945d375..ad54922 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -1255,10 +1255,10 @@ main (int argc, char* argv[]) uint16_t diag (ops.structured_result () ? 0 : 1); if (mif->match != nullptr) - mif->match (mparams, a, tgs, diag); + mif->match (mparams, a, tgs, diag, true /* progress */); if (mif->execute != nullptr && !ops.match_only ()) - mif->execute (mparams, a, tgs, diag); + mif->execute (mparams, a, tgs, diag, true /* progress */); } if (mif->operation_post != nullptr) @@ -1279,10 +1279,10 @@ main (int argc, char* argv[]) uint16_t diag (ops.structured_result () ? 0 : 2); if (mif->match != nullptr) - mif->match (mparams, a, tgs, diag); + mif->match (mparams, a, tgs, diag, true /* progress */); if (mif->execute != nullptr && !ops.match_only ()) - mif->execute (mparams, a, tgs, diag); + mif->execute (mparams, a, tgs, diag, true /* progress */); } if (post_oid != 0) @@ -1304,10 +1304,10 @@ main (int argc, char* argv[]) uint16_t diag (ops.structured_result () ? 0 : 1); if (mif->match != nullptr) - mif->match (mparams, a, tgs, diag); + mif->match (mparams, a, tgs, diag, true /* progress */); if (mif->execute != nullptr && !ops.match_only ()) - mif->execute (mparams, a, tgs, diag); + mif->execute (mparams, a, tgs, diag, true /* progress */); } if (mif->operation_post != nullptr) diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx index a284f65..65592c5 100644 --- a/build2/config/operation.cxx +++ b/build2/config/operation.cxx @@ -348,13 +348,14 @@ namespace build2 } static void - configure_match (const values&, action, action_targets&, uint16_t) + configure_match (const values&, action, action_targets&, uint16_t, bool) { // Don't match anything -- see execute (). } static void - configure_execute (const values&, action a, action_targets& ts, uint16_t) + configure_execute (const values&, action a, action_targets& ts, + uint16_t, bool) { // Match rules to configure every operation supported by each // project. Note that we are not calling operation_pre/post() @@ -497,7 +498,7 @@ namespace build2 } static void - disfigure_match (const values&, action, action_targets&, uint16_t) + disfigure_match (const values&, action, action_targets&, uint16_t, bool) { } @@ -595,10 +596,8 @@ namespace build2 } static void - disfigure_execute (const values&, - action a, - action_targets& ts, - uint16_t diag) + disfigure_execute (const values&, action a, action_targets& ts, + uint16_t diag, bool) { tracer trace ("disfigure_execute"); diff --git a/build2/diagnostics.hxx b/build2/diagnostics.hxx index b9757d6..5ec2ef0 100644 --- a/build2/diagnostics.hxx +++ b/build2/diagnostics.hxx @@ -143,6 +143,22 @@ namespace build2 os.iword (stream_verb_index) = static_cast (v.value_) + 1; } + // Progress reporting. + // + using butl::diag_progress; + using butl::diag_progress_lock; + + // Return true if progress is to be shown. The max_verb argument is the + // maximum verbosity level that this type of progress should be shown by + // default. + // + inline bool + show_progress (uint16_t max_verb) + { + return ops.progress () || + (stderr_term && verb >= 1 && verb <= max_verb && !ops.no_progress ()); + } + // Diagnostic facility, base infrastructure. // using butl::diag_stream_lock; diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx index dfba163..c8cc60d 100644 --- a/build2/dist/operation.cxx +++ b/build2/dist/operation.cxx @@ -54,7 +54,8 @@ namespace build2 } static void - dist_execute (const values&, action, action_targets& ts, uint16_t) + dist_execute (const values&, action, action_targets& ts, + uint16_t, bool prog) { tracer trace ("dist_execute"); @@ -128,7 +129,8 @@ namespace build2 // Skip aliases (e.g., update-for-install). In fact, one can argue // the default update should be sufficient since it is assumed to // update all prerequisites and we no longer support ad hoc stuff - // like test.input. + // like test.input. Though here we are using the dist meta-operation, + // not perform. // if (oif->id != id) continue; @@ -142,13 +144,17 @@ namespace build2 const operation_info* poif (rs->operations[pid]); set_current_oif (*poif, oif); action a (dist_id, poif->id, oif->id); - match (params, a, ts, 1 /* diag (failures only) */); + match (params, a, ts, + 1 /* diag (failures only) */, + false /* progress */); } } set_current_oif (*oif); action a (dist_id, oif->id); - match (params, a, ts, 1 /* diag (failures only) */); + match (params, a, ts, + 1 /* diag (failures only) */, + false /* progress */); if (oif->post != nullptr) { @@ -157,7 +163,9 @@ namespace build2 const operation_info* poif (rs->operations[pid]); set_current_oif (*poif, oif); action a (dist_id, poif->id, oif->id); - match (params, a, ts, 1 /* diag (failures only) */); + match (params, a, ts, + 1 /* diag (failures only) */, + false /* progress */); } } } @@ -214,6 +222,9 @@ namespace build2 // Collect the files. We want to take the snapshot of targets since // updating some of them may result in more targets being entered. // + // Note that we are not showing progress here (e.g., "N targets to + // distribute") since it will be useless (too fast). + // action_targets files; const variable& dist_var (var_pool["dist"]); @@ -279,8 +290,13 @@ namespace build2 action a (perform_id, update_id); - mo_perform.match (params, a, files, 1 /* diag (failures only) */); - mo_perform.execute (params, a, files, 1 /* diag (failures only) */); + mo_perform.match (params, a, files, + 1 /* diag (failures only) */, + prog /* progress */); + + mo_perform.execute (params, a, files, + 1 /* diag (failures only) */, + prog /* progress */); if (mo_perform.operation_post != nullptr) mo_perform.operation_post (params, update_id); @@ -293,8 +309,6 @@ namespace build2 // Clean up the target directory. // - // @@ Not for incremental dist? - // if (build2::rmdir_r (td) == rmdir_status::not_empty) fail << "unable to clean target directory " << td; @@ -304,9 +318,12 @@ namespace build2 // module& mod (*rs->modules.lookup (module::name)); - for (const action_target& at: files) + prog = prog && show_progress (1 /* max_verb */); + size_t prog_percent (0); + + for (size_t i (0), n (files.size ()); i != n; ++i) { - const file& t (*at.as_target ().is_a ()); + const file& t (*files[i].as_target ().is_a ()); // Figure out where this file is inside the target directory. // @@ -365,6 +382,32 @@ namespace build2 if (path_match (pat.leaf ().string (), t.path ().leaf ().string ())) cb.function (r, *srs, cb.data); } + + if (prog) + { + // Note that this is not merely an optimization since if stderr is + // not a terminal, we print real lines for progress. + // + size_t p ((i * 100) / n); + + if (prog_percent != p) + { + prog_percent = p; + + diag_progress_lock pl; + diag_progress = ' '; + diag_progress += to_string (prog_percent); + diag_progress += "% of targets distributed"; + } + } + } + + // Clear the progress if shown. + // + if (prog) + { + diag_progress_lock pl; + diag_progress.clear (); } // Archive if requested. diff --git a/build2/operation.cxx b/build2/operation.cxx index eaacc6d..dabebcc 100644 --- a/build2/operation.cxx +++ b/build2/operation.cxx @@ -112,7 +112,7 @@ namespace build2 } void - match (const values&, action a, action_targets& ts, uint16_t diag) + match (const values&, action a, action_targets& ts, uint16_t diag, bool prog) { tracer trace ("match"); @@ -126,8 +126,8 @@ namespace build2 // string what; // Note: must outlive monitor_guard. scheduler::monitor_guard mg; - if (ops.progress () || - (stderr_term && verb >= 1 && verb <= 2 && !ops.no_progress ())) + + if (prog && show_progress (2 /* max_verb */)) { size_t incr (stderr_term ? 1 : 10); // Scale depending on output type. @@ -240,7 +240,8 @@ namespace build2 } void - execute (const values&, action a, action_targets& ts, uint16_t diag) + execute (const values&, action a, action_targets& ts, + uint16_t diag, bool prog) { tracer trace ("execute"); @@ -265,12 +266,10 @@ namespace build2 string what; // Note: must outlive monitor_guard. scheduler::monitor_guard mg; - if (ops.progress () || (stderr_term && verb == 1 && !ops.no_progress ())) + if (prog && show_progress (1 /* max_verb */)) { size_t init (target_count.load (memory_order_relaxed)); - size_t incr (init / 100); // 1%. - if (incr == 0) - incr = 1; + size_t incr (init > 100 ? init / 100 : 1); // 1%. if (init != incr) { @@ -476,7 +475,7 @@ namespace build2 } static void - info_execute (const values&, action, action_targets& ts, uint16_t) + info_execute (const values&, action, action_targets& ts, uint16_t, bool) { for (size_t i (0); i != ts.size (); ++i) { diff --git a/build2/operation.hxx b/build2/operation.hxx index 27f2356..fd8ca0c 100644 --- a/build2/operation.hxx +++ b/build2/operation.hxx @@ -293,8 +293,15 @@ namespace build2 // 1 - failures only (for pre-operations). // 2 - all (for normal operations). // - void (*match) (const values&, action, action_targets&, uint16_t diag); - void (*execute) (const values&, action, action_targets&, uint16_t diag); + // The false progress argument can be used to suppress progress. If it is + // true, then whether the progress is shown is meta operation-specific (in + // other words, you can suppress it but not force it). + // + void (*match) (const values&, action, action_targets&, + uint16_t diag, bool progress); + + void (*execute) (const values&, action, action_targets&, + uint16_t diag, bool progress); // Start of operation and meta-operation batches. // @@ -333,14 +340,16 @@ namespace build2 action_targets&); void - match (const values&, action, action_targets&, uint16_t diag); + match (const values&, action, action_targets&, + uint16_t diag, bool prog); // Execute the action on the list of targets. This is the default // implementation that does just that while issuing appropriate // diagnostics (unless quiet). // void - execute (const values&, action, const action_targets&, uint16_t diag); + execute (const values&, action, const action_targets&, + uint16_t diag, bool prog); extern const meta_operation_info mo_noop; extern const meta_operation_info mo_perform; -- cgit v1.1