From 59014204d94e67d243cce45ff83ca85212237433 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 29 May 2023 06:47:04 +0200 Subject: Handle see-through groups with dynamic members in dist --- libbuild2/dist/operation.cxx | 122 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 15 deletions(-) (limited to 'libbuild2/dist/operation.cxx') diff --git a/libbuild2/dist/operation.cxx b/libbuild2/dist/operation.cxx index da96215..cd88eac 100644 --- a/libbuild2/dist/operation.cxx +++ b/libbuild2/dist/operation.cxx @@ -463,41 +463,89 @@ namespace build2 // Note that we are not showing progress here (e.g., "N targets to // distribute") since it will be useless (too fast). // - for (const auto& pt: ctx.targets) + auto see_through = [] (const target& t) { - file* ft (pt->is_a ()); - - if (ft == nullptr) // Not a file. - continue; + return ((t.type ().flags & target_type::flag::see_through) == + target_type::flag::see_through); + }; - if (ft->dir.sub (src_root)) + auto collect = [&trace, &dist_var, + &src_root, &out_root] (const file& ft) + { + if (ft.dir.sub (src_root)) { // Include unless explicitly excluded. // - if (const path* v = cast_null ((*ft)[dist_var])) + if (const path* v = cast_null (ft[dist_var])) { if (v->string () == "false") { - l5 ([&]{trace << "excluding " << *ft;}); - continue; + l5 ([&]{trace << "excluding " << ft;}); + return false; } } - files.push_back (ft); + return true; } - else if (ft->dir.sub (out_root)) + else if (ft.dir.sub (out_root)) { // Exclude unless explicitly included. // - if (const path* v = cast_null ((*ft)[dist_var])) + if (const path* v = cast_null (ft[dist_var])) + { + if (v->string () != "false") + { + l5 ([&]{trace << "including " << ft;}); + return true; + } + } + + return false; + } + else + return false; // Out of project. + }; + + for (const auto& pt: ctx.targets) + { + // Collect see-through groups if they are marked with dist=true. + // + // Note that while it's possible that only their certain members are + // marked as such (e.g., via a pattern), we will still require + // dist=true on the group itself (and potentially dist=false on some + // of its members) for such cases because we don't want to update + // every see-through group only to discover that most of them don't + // have anything to distribute. + // + if (see_through (*pt)) + { + if (const path* v = cast_null ((*pt)[dist_var])) { if (v->string () != "false") { - l5 ([&]{trace << "including " << *ft;}); - files.push_back (ft); + l5 ([&]{trace << "including group " << *pt;}); + files.push_back (pt.get ()); } } + + continue; } + + file* ft (pt->is_a ()); + + if (ft == nullptr) // Not a file. + continue; + + // Skip member of see-through groups since after dist_* their list + // can be incomplete (or even bogus, e.g., the "representative + // sample"). Instead, we will collect them during perfrom_update + // below. + // + if (ft->group != nullptr && see_through (*ft->group)) + continue; + + if (collect (*ft)) + files.push_back (ft); } // Make sure what we need to distribute is up to date. @@ -537,6 +585,50 @@ namespace build2 1 /* diag (failures only) */, prog /* progress */); + // Replace see-through groups (which now should have their members + // resolved) with members. + // + for (auto i (files.begin ()); i != files.end (); ) + { + const target& t (i->as ()); + if (see_through (t)) + { + group_view gv (t.group_members (a)); // Go directly. + + if (gv.members == nullptr) + fail << "unable to resolve see-through group " << t + << " members"; + + i = files.erase (i); // Drop the group itself. + + for (size_t j (0); j != gv.count; ++j) + { + if (const target* m = gv.members[j]) + { + if (const file* ft = m->is_a ()) + { + // Note that a rule may only link-up its members to groups + // if/when matched (for example, the cli.cxx{} group). It + // feels harmless for us to do the linking here. + // + if (ft->group == nullptr) + const_cast (ft)->group = &t; + else + assert (ft->group == &t); // Sanity check. + + if (collect (*ft)) + { + i = files.insert (i, ft); // Insert instead of the group. + i++; // Stay after the group. + } + } + } + } + } + else + ++i; + } + if (op_update.operation_post != nullptr) op_update.operation_post (ctx, {}, true /* inner */); @@ -585,7 +677,7 @@ namespace build2 for (size_t i (0), n (files.size ()); i != n; ++i) { - const file& t (*files[i].as ().is_a ()); + const file& t (files[i].as ().as ()); // Only files. // Figure out where this file is inside the target directory. // -- cgit v1.1