diff options
-rw-r--r-- | libbuild2/algorithm.cxx | 260 | ||||
-rw-r--r-- | libbuild2/algorithm.hxx | 14 |
2 files changed, 151 insertions, 123 deletions
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index b0e8eb0..e15fcbc 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -2324,102 +2324,104 @@ namespace build2 return execute_prerequisites (a, t); } - target_state - perform_clean_extra (action a, const file& ft, - const clean_extras& extras, - const clean_adhoc_extras& adhoc_extras) + static target_state + clean_extra (context& ctx, + const path& fp, + const clean_extras& es, + path& ep, bool& ed) { - // Clean the extras first and don't print the commands at verbosity level - // below 3. Note the first extra file/directory that actually got removed - // for diagnostics below. - // - // Note that dry-run is taken care of by the filesystem functions. - // - target_state er (target_state::unchanged); - bool ed (false); - path ep; + assert (!fp.empty ()); // Must be assigned. - context& ctx (ft.ctx); + target_state er (target_state::unchanged); - auto clean_extra = [&er, &ed, &ep, &ctx] (const file& f, - const path* fp, - const clean_extras& es) + for (const char* e: es) { - for (const char* e: es) - { - size_t n; - if (e == nullptr || (n = strlen (e)) == 0) - continue; + size_t n; + if (e == nullptr || (n = strlen (e)) == 0) + continue; - path p; - bool d; + path p; + bool d; - if (path::traits_type::absolute (e)) - { - p = path (e); - d = p.to_directory (); - } - else - { - if ((d = (e[n - 1] == '/'))) - --n; + if (path::traits_type::absolute (e)) + { + p = path (e); + d = p.to_directory (); + } + else + { + if ((d = (e[n - 1] == '/'))) + --n; - if (fp == nullptr) - { - fp = &f.path (); - assert (!fp->empty ()); // Must be assigned. - } + p = fp; + for (; *e == '-'; ++e) + p = p.base (); - p = *fp; - for (; *e == '-'; ++e) - p = p.base (); + p.append (e, n); + } - p.append (e, n); - } + target_state r (target_state::unchanged); - target_state r (target_state::unchanged); + if (d) + { + dir_path dp (path_cast<dir_path> (p)); - if (d) + switch (rmdir_r (ctx, dp, true, 3)) { - dir_path dp (path_cast<dir_path> (p)); - - switch (rmdir_r (ctx, dp, true, 3)) + case rmdir_status::success: { - case rmdir_status::success: - { - r = target_state::changed; - break; - } - case rmdir_status::not_empty: - { - if (verb >= 3) - text << dp << " is current working directory, not removing"; - break; - } - case rmdir_status::not_exist: + r = target_state::changed; break; } + case rmdir_status::not_empty: + { + if (verb >= 3) + text << dp << " is current working directory, not removing"; + break; + } + case rmdir_status::not_exist: + break; } - else - { - if (rmfile (ctx, p, 3)) - r = target_state::changed; - } - - if (r == target_state::changed && ep.empty ()) - { - ed = d; - ep = move (p); - } + } + else + { + if (rmfile (ctx, p, 3)) + r = target_state::changed; + } - er |= r; + if (r == target_state::changed && ep.empty ()) + { + ed = d; + ep = move (p); } - }; + + er |= r; + } + + return er; + } + + target_state + perform_clean_extra (action a, const file& ft, + const clean_extras& extras, + const clean_adhoc_extras& adhoc_extras) + { + context& ctx (ft.ctx); + + // Clean the extras first and don't print the commands at verbosity level + // below 3. Note the first extra file/directory that actually got removed + // for diagnostics below. + // + // Note that dry-run is taken care of by the filesystem functions. + // + target_state er (target_state::unchanged); + bool ed (false); + path ep; const path& fp (ft.path ()); if (!fp.empty () && !extras.empty ()) - clean_extra (ft, nullptr, extras); + er |= clean_extra (ctx, fp, extras, ep, ed); target_state tr (target_state::unchanged); @@ -2454,7 +2456,7 @@ namespace build2 })); if (i != adhoc_extras.end ()) - clean_extra (*mf, mp, i->extras); + er |= clean_extra (ctx, *mp, i->extras, ep, ed); } if (!clean) @@ -2521,29 +2523,19 @@ namespace build2 } target_state - perform_clean (action a, const target& t) + perform_clean_group_extra (action a, const mtime_target& g, + const clean_extras& extras) { - const file& f (t.as<file> ()); - assert (!f.path ().empty ()); - return perform_clean_extra (a, f, {}); - } + context& ctx (g.ctx); - target_state - perform_clean_depdb (action a, const target& t) - { - const file& f (t.as<file> ()); - assert (!f.path ().empty ()); - return perform_clean_extra (a, f, {".d"}); - } + target_state er (target_state::unchanged); + bool ed (false); + path ep; - target_state - perform_clean_group (action a, const target& xg) - { - const mtime_target& g (xg.as<mtime_target> ()); + if (!extras.empty ()) + er |= clean_extra (ctx, g.dir / path (g.name), extras, ep, ed); - // Similar logic to perform_clean_extra() above. - // - target_state r (target_state::unchanged); + target_state tr (target_state::unchanged); if (cast_true<bool> (g[g.ctx.var_clean])) { @@ -2552,53 +2544,75 @@ namespace build2 if (const target* m = gv.members[gv.count - 1]) { if (rmfile (m->as<file> ().path (), *m)) - r |= target_state::changed; + tr |= target_state::changed; } } } g.mtime (timestamp_nonexistent); - r |= reverse_execute_prerequisites (a, g); - return r; + if (tr != target_state::changed && er == target_state::changed) + { + if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3) + { + if (ed) + text << "rm -r " << path_cast<dir_path> (ep); + else + text << "rm " << ep; + } + } + + tr |= reverse_execute_prerequisites (a, g); + + tr |= er; + return tr; } target_state - perform_clean_group_depdb (action a, const target& g) + perform_clean (action a, const target& t) { - context& ctx (g.ctx); + const file& f (t.as<file> ()); + assert (!f.path ().empty ()); + return perform_clean_extra (a, f, {}); + } - // The same twisted target state merging logic as in perform_clean_extra(). - // - target_state er (target_state::unchanged); - path ep; + target_state + perform_clean_depdb (action a, const target& t) + { + const file& f (t.as<file> ()); + assert (!f.path ().empty ()); + return perform_clean_extra (a, f, {".d"}); + } - group_view gv (g.group_members (a)); - if (gv.count != 0) + target_state + perform_clean_group (action a, const target& t) + { + return perform_clean_group_extra (a, t.as<mtime_target> (), {}); + } + + target_state + perform_clean_group_depdb (action a, const target& t) + { + path d; + clean_extras extras; { - for (size_t i (0); i != gv.count; ++i) + group_view gv (t.group_members (a)); + if (gv.count != 0) { - if (const target* m = gv.members[i]) + for (size_t i (0); i != gv.count; ++i) { - ep = m->as<file> ().path () + ".d"; - break; + if (const target* m = gv.members[i]) + { + d = m->as<file> ().path () + ".d"; + break; + } } - } - assert (!ep.empty ()); - if (rmfile (ctx, ep, 3)) - er = target_state::changed; - } - - target_state tr (perform_clean_group (a, g)); - - if (tr != target_state::changed && er == target_state::changed) - { - if (verb > (ctx.current_diag_noise ? 0 : 1) && verb < 3) - text << "rm " << ep; + assert (!d.empty ()); + extras.push_back (d.string ().c_str ()); + } } - tr |= er; - return tr; + return perform_clean_group_extra (a, t.as<mtime_target> (), extras); } } diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index c767f5a..8a6eb65 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -840,6 +840,20 @@ namespace build2 return perform_clean_extra (a, f, clean_extras (e)); } + // Similar to perform_clean_group() but with extras similar to + // perform_clean_extra(). Note that the extras are derived from the group + // "path" (g.dir / g.name). + // + LIBBUILD2_SYMEXPORT target_state + perform_clean_group_extra (action, const mtime_target&, const clean_extras&); + + inline target_state + perform_clean_group_extra (action a, const mtime_target& g, + initializer_list<const char*> e) + { + return perform_clean_group_extra (a, g, clean_extras (e)); + } + // Update/clean a backlink issuing appropriate diagnostics at appropriate // levels depending on the overload and the changed argument. // |