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 NAME
Hydra::Schema::AggregateMembers
=cut
use 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 aggregate
data_type: 'integer'
is_foreign_key: 1
is_nullable: 0
=head2 member
data_type: 'integer'
is_foreign_key: 1
is_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 aggregate
Type: belongs_to
Related 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 member
Type: belongs_to
Related 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 regeneration
1;
=head2 aggregatemembers_aggregates
Type: has_many
Related object: L<Hydra::Schema::AggregateMembers>
=cut
__PACKAGE__->has_many(
"aggregatemembers_aggregates",
"Hydra::Schema::AggregateMembers",
{ "foreign.aggregate" => "self.id" },
undef,
);
=head2 aggregatemembers_members
Type: has_many
Related 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 members
Type: many_to_many
Composing 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)
);