For presentation purposes, we need to know what builds are part of an aggregate build. So at evaluation time, look at the "members" attribute, find the corresponding builds in the eval, and create a mapping in the AggregateMembers table.
FTPCV25MOLQUNR5CAR453W7T7QTUZRLPLEOSDZ5HSDFAXQZVHOYQC LZVO64YG43JD7YMZSCTZNOBS5ROZA4FMPKJW2YOMHX2V5PTGBVWQC PHNLYPKB5SJJAHAICS6QEMRNCREPG7SC2MQRLTQMQLWGXM427S3QC FANTYCR7X2TYLJKGO3E5CU4PVXPSOMQZELEFQCZ6E7GEJOPYXQUAC HVXL2XUZTOWJPESBHBFD74B4QXNMG5SX4LOXDLPJ7732IU4SUYWQC A63IHCMXH3F4V56HDXJLJVVHKXRSJCJMT2PWXXI2IW3J734J6SGQC 4N5APGRGHTKFMEJ7THSJX6TSYYAP3BUZQG73AJBKCQLXOOEHPATQC 3XTHEUMP2ZOMPQWE3S5QWHIHCEJNEXGDPQB3JUVZFPS3RFMY455QC LBNVQXUBEZ45SOTGVXK5UEZXIAIZTJLWZNUYFI4JZ6J65N3KPDVQC PMNWRTGJ4GVSMSSAWSUD57B26PCRAHMZIQ5SIWJIK7A74ENKEQLAC KQS7DSKJHTEHALCPTXMWRX2IBOVC5BWU7RWJ4GP5A2JJSBR7HPKAC OOQ2D3KCLFPYNAN253PHWLBQMB6OMO2KYQWQXLTP65SQAYZWQ5LAC YFPZ46YK4BOI6VH2H3F757UEGEYONURUAEDAYEIBLRY33PLSSO4AC CQTN62OHT4DY35E2MJEG7GFTVNEE5KRDMV6ASBQLBHN7BUDK7WHAC RXVJFQ5AV3WME4HDVBPSRCALQTXROT4KQPOQVO6KTWTBNZIZZGPAC JOYONH2KARKK2Z72WQW6DZ4B6WT47Z4VHOHGL7KM3B6RT3CBAMLQC INNOEHO6CTW75YEEGNLUKISQEMOAE4P2C2SEVHEKOVIFHADWY4OAC D5QIOJGPKQJIYBUCSC3MFJ3TXLPNZ2XMI37GXMFRVRFWWR2VMTFAC JM3DPYOMVNMCL5GMEYC3Y4NDRGTNIFBBFTPGPVT66GPENVPU7EVQC J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC RFE6T5LGBFFNEPHZOPF4UNMFC2L4CGD5TPAMOXDLRPH3TZJ43UBAC SJLEZFC472OWVCR7WEUUYNS6BJDDR77SHWADKDCPIS2INMTPTIVAC L2E6EVE2RVFVDCUNRJ4CZYSQNS2DZUA5DTBETHBDUQUV2KQQRAOQC AHTEIK7GGPHUC3AXIJ2NX4TI3RLX65XYKGAIIC6MC2S6I6QPWTAAC N22GPKYTOLZLBGTGDATQDVZ4R5APZEAOIA7L32X4UXBH4XNI7MWAC S6OISBQ3HPFHAAQ5ENG7N3MNGOPNEJPIFKSSA5N4G6KJQTQBSSLQC AZCCANUBA5NBQCU5EHKCNDLEUS5VPXSSVZVUKGKGJLUNYIGSJAYQC G2T4WAHINIIKTEKR4JBIRXO5IEKO7MPYD7U5PQ4AIX3WL54EPP3AC /* If this is an aggregate, then get its members. */Bindings::iterator a = v.attrs->find(state.symbols.create("_hydraAggregate"));if (a != v.attrs->end() && state.forceBool(*a->value)) {Bindings::iterator a = v.attrs->find(state.symbols.create("members"));if (a == v.attrs->end())throw EvalError("derivation must have a ‘members’ attribute");PathSet context;state.coerceToString(*a->value, context, true, false);PathSet drvs;foreach (PathSet::iterator, i, context)if (i->at(0) == '!') {size_t index = i->find("!", 1);drvs.insert(string(*i, index + 1));}xmlAttrs["members"] = concatStringsSep(" ", drvs);}
use utf8;package Hydra::Schema::AggregateMembers;# Created by DBIx::Class::Schema::Loader# DO NOT MODIFY THE FIRST PART OF THIS FILE=head1 NAMEHydra::Schema::AggregateMembers=cutuse strict;use warnings;use base 'DBIx::Class::Core';=head1 COMPONENTS LOADED=over 4=item * L<Hydra::Component::ToJSON>=back=cut__PACKAGE__->load_components("+Hydra::Component::ToJSON");=head1 TABLE: C<AggregateMembers>=cut__PACKAGE__->table("AggregateMembers");=head1 ACCESSORS=head2 aggregatedata_type: 'integer'is_foreign_key: 1is_nullable: 0=head2 memberdata_type: 'integer'is_foreign_key: 1is_nullable: 0=cut__PACKAGE__->add_columns("aggregate",{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },"member",{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },);=head1 PRIMARY KEY=over 4=item * L</aggregate>=item * L</member>=back=cut__PACKAGE__->set_primary_key("aggregate", "member");=head1 RELATIONS=head2 aggregateType: belongs_toRelated object: L<Hydra::Schema::Builds>=cut__PACKAGE__->belongs_to("aggregate","Hydra::Schema::Builds",{ id => "aggregate" },{ is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },);=head2 memberType: belongs_toRelated object: L<Hydra::Schema::Builds>=cut__PACKAGE__->belongs_to("member","Hydra::Schema::Builds",{ id => "member" },{ is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },);# Created by DBIx::Class::Schema::Loader v0.07033 @ 2013-08-13 22:17:52# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jHJtO2baXiprv0OcWCLZ+w# You can replace this text with custom code or comments, and it will be preserved on regeneration1;
=head2 aggregatemembers_aggregatesType: has_manyRelated object: L<Hydra::Schema::AggregateMembers>=cut__PACKAGE__->has_many("aggregatemembers_aggregates","Hydra::Schema::AggregateMembers",{ "foreign.aggregate" => "self.id" },undef,);=head2 aggregatemembers_membersType: has_manyRelated object: L<Hydra::Schema::AggregateMembers>=cut__PACKAGE__->has_many("aggregatemembers_members","Hydra::Schema::AggregateMembers",{ "foreign.member" => "self.id" },undef,);
# Created by DBIx::Class::Schema::Loader v0.07033 @ 2013-06-13 01:54:50# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:isCEXACY/PwkvgKHcXvAIg
__PACKAGE__->many_to_many("aggregates", "aggregatemembers_members", "aggregate");=head2 membersType: many_to_manyComposing rels: L</aggregatemembers_members> -> member=cut__PACKAGE__->many_to_many("members", "aggregatemembers_members", "member");
while (my ($id, $new) = each %buildIds) {$ev->jobsetevalmembers->create({ build => $id, isnew => $new });
# Create JobsetEvalMembers mappings.my %drvPathToId;while (my ($id, $x) = each %buildMap) {$ev->jobsetevalmembers->create({ build => $id, isnew => $x->{new} });$drvPathToId{$x->{drvPath}} = $id;}# Create AggregateMembers mappings.foreach my $job (@{$jobs->{job}}) {next unless $job->{members};my $id = $drvPathToId{$job->{drvPath}} or die;foreach my $drvPath (split / /, $job->{members}) {my $member = $drvPathToId{$drvPath};if (defined $member) {$db->resultset('AggregateMembers')->update_or_create({aggregate => $id, member => $member});} else {warn "aggregate job ‘$job->{jobName}’ has a member ‘$drvPath’ that doesn't correspond to a Hydra build\n";}}
create table AggregateMembers (aggregate integer not null references Builds(id) on delete cascade,member integer not null references Builds(id) on delete cascade,primary key (aggregate, member));