3XTHEUMP2ZOMPQWE3S5QWHIHCEJNEXGDPQB3JUVZFPS3RFMY455QC QNDXPVCIRJRPFTYNRDCQC5KORSYB5FPX7IAM6UGACWCU6HWYT6CAC OOQ2D3KCLFPYNAN253PHWLBQMB6OMO2KYQWQXLTP65SQAYZWQ5LAC TIOBBINAK6IEDTCFBP67QDP3U7BHPVJOHBD6FEHASSSIQGNLCUXAC LBNVQXUBEZ45SOTGVXK5UEZXIAIZTJLWZNUYFI4JZ6J65N3KPDVQC WRIU3S5EO3RB3IM5PUDNHLOOMUPD5UKWNUL4YMAKD3C6O4KELJCAC POPU2ATH2HHBTGHKRAV3EY2K55P664IARI3YJGLDKVJ6PQPXBQ4AC N22GPKYTOLZLBGTGDATQDVZ4R5APZEAOIA7L32X4UXBH4XNI7MWAC AFTXA575C6JTVLVXTYJUKQGPLBO3NFORLO5XDSPHNL44HXLRH4TAC H7CNGK4OJNRYZQGPLBGR72DULLEPFQ5UISF5J24D7IMA7SYW5LGQC JK2QWPH6EOQXGCADV7C5HSYRVWC5M53LAKVN26EMTLY65IKU3AEQC X27GNHDV5KPZ5GSH6DCAJMNCEMZLCP7M43JWF2X3O5QWXMOX273AC FDE3BJAPDEP3BYT5A5GEGLNXPPZLA2KTGXB4ZNYRP4LJ7IFRKYXAC BTOXLRG37PPI4MPXMVGZP2GJVUHV5LFMR3EMIWZMRZEJGV23M72QC S6OISBQ3HPFHAAQ5ENG7N3MNGOPNEJPIFKSSA5N4G6KJQTQBSSLQC XNCWZ7OTIBIGWKAV7ZWCNO6QGQGAWRCZYK4HZMYPURJ7CLMRXUHAC LZO3C2KIACZ3HN72RBGWWIT5ED4RJMYKI3SAHXT6RIUPHDFL3STQC IXCUNELFZBXTEZKZJXJFP3AFPRHCWJ4NEQC2FSKTOYIZDP74O3RQC S5PV6IIMKJ7PGWIFLLXERHYF3BCP2UEGFRZEZLD6UUBLVEZXJLUAC CVDK3XJKQJVLCNJM5E5K2T7ZIIIBN3WLEK3ADBGQEPAOJ6FZTPNQC ZP3M3JWRIBVLWAZNFP3WGGDYQ3QSTZ4D7SN67IUDMDHJOMC6XUJAC 7YBYT2LQML2PKEO6UO4444AGSASS664UCDXW2YO3ALB7THQHCEBQC L2E6EVE2RVFVDCUNRJ4CZYSQNS2DZUA5DTBETHBDUQUV2KQQRAOQC KOTB7BKVML6T6S5ZNTQ6456FMGCRZCP3E3KVWCOW7T6SPRHC53LAC AHTEIK7GGPHUC3AXIJ2NX4TI3RLX65XYKGAIIC6MC2S6I6QPWTAAC 6BLUKEQ2M5RGWMPXPYIFIEVEUBV4PYAZ75S2WSBIATMRGYFMQZHQC TLZ2SPBRX274EUS73SUUCOFYQUXB76S3F4AOSJXDYXIMMS7JIHEAC 2T42QGZDK23C5V4ZHO4R7EBJESIQ62GKWDBWVX7OBEE3YVBUNUFAC BVOPAMLSAU4UTV3DUX53OYDMXP2SETAQVUKAYE2OTCVVN4RD7LLQC 7ZHHVD6QVZCR7OHF3OIS52DF7ZIQDIS27OXCKOGMFDO2CTIOGI5AC YAPITGB3ENS6PXRBFC647ESCQUYG442DKHUPM46PJKCKTMHWGVXAC A63IHCMXH3F4V56HDXJLJVVHKXRSJCJMT2PWXXI2IW3J734J6SGQC SHZLOM5M2NVH2J7CJJMS562EV5NPCTNWQ5P3K2SSL2YFYUI7PMIQC M552HLIAP52D42AVXVC5SGROAYN2TBCEUZOXESWEMBBUX7G3U6TAC $c->flash->{buildMsg} = "Build XXX added to the queue.";
my ($jobs, $nixExprInput) = evalJobs($inputInfo, $nixExprInputName, $nixExprPath);my $job;foreach my $j (@{$jobs->{job}}) {print STDERR $j->{jobName}, "\n";if ($j->{jobName} eq $jobName) {error($c, "Nix expression returned multiple builds for job $jobName.")if $job;$job = $j;}}error($c, "Nix expression did not return a job named $jobName.") unless $job;my %currentBuilds;my $newBuild = checkBuild($c->model('DB'), $build->project, $build->jobset,$inputInfo, $nixExprInput, $job, \%currentBuilds);error($c, "This build has already been performed.") unless $newBuild;$c->flash->{buildMsg} = "Build " . $newBuild->id . " added to the queue.";
}sub inputsToArgs {my ($inputInfo) = @_;my @res = ();foreach my $input (keys %{$inputInfo}) {foreach my $alt (@{$inputInfo->{$input}}) {given ($alt->{type}) {when ("string") {push @res, "--argstr", $input, $alt->{value};}when ("boolean") {push @res, "--arg", $input, $alt->{value};}when (["svn", "path", "build"]) {push @res, "--arg", $input, ("{ outPath = builtins.storePath " . $alt->{storePath} . "" .(defined $alt->{revision} ? "; rev = \"" . $alt->{revision} . "\"" : "") .(defined $alt->{version} ? "; version = \"" . $alt->{version} . "\"" : "") .";}");}}}}return @res;}sub captureStdoutStderr {my $stdin = ""; my $stdout; my $stderr;my $res = IPC::Run::run(\@_, \$stdin, \$stdout, \$stderr);return ($res, $stdout, $stderr);
sub evalJobs {my ($inputInfo, $nixExprInputName, $nixExprPath) = @_;my $nixExprInput = $inputInfo->{$nixExprInputName}->[0]or die "Cannot find the input containing the job expression.\n";die "Multiple alternatives for the input containing the Nix expression are not supported.\n"if scalar @{$inputInfo->{$nixExprInputName}} != 1;my $nixExprFullPath = $nixExprInput->{storePath} . "/" . $nixExprPath;(my $res, my $jobsXml, my $stderr) = captureStdoutStderr("hydra_eval_jobs", $nixExprFullPath, "--gc-roots-dir", getGCRootsDir,inputsToArgs($inputInfo));die "Cannot evaluate the Nix expression containing the jobs:\n$stderr" unless $res;print STDERR "$stderr";my $jobs = XMLin($jobsXml,ForceArray => ['error', 'job', 'arg'],KeyAttr => [],SuppressEmpty => '')or die "cannot parse XML output";return ($jobs, $nixExprInput);}# Check whether to add the build described by $buildInfo.sub checkBuild {my ($db, $project, $jobset, $inputInfo, $nixExprInput, $buildInfo, $currentBuilds) = @_;my $jobName = $buildInfo->{jobName};my $drvPath = $buildInfo->{drvPath};my $outPath = $buildInfo->{outPath};my $priority = 100;$priority = int($buildInfo->{schedulingPriority})if $buildInfo->{schedulingPriority} =~ /^\d+$/;my $build;txn_do($db, sub {# Update the last evaluation time in the database.my $job = $jobset->jobs->update_or_create({ name => $jobName, lastevaltime => time});$job->update({firstevaltime => time})unless defined $job->firstevaltime;# Don't add a build that has already been scheduled for this# job, or has been built but is still a "current" build for# this job. Note that this means that if the sources of a job# are changed from A to B and then reverted to A, three builds# will be performed (though the last one will probably use the# cached result from the first). This ensures that the builds# with the highest ID will always be the ones that we want in# the channels.# !!! Checking $outPath doesn't take meta-attributes into# account. For instance, do we want a new build to be# scheduled if the meta.maintainers field is changed?my @previousBuilds = $job->builds->search({outPath => $outPath, isCurrent => 1});if (scalar(@previousBuilds) > 0) {print STDERR "already scheduled/built\n";$currentBuilds->{$_->id} = 1 foreach @previousBuilds;return;}# Nope, so add it.$build = $job->builds->create({ finished => 0, timestamp => time(), description => $buildInfo->{description}, longdescription => $buildInfo->{longDescription}, license => $buildInfo->{license}, homepage => $buildInfo->{homepage}, maintainers => $buildInfo->{maintainers}, nixname => $buildInfo->{nixName}, drvpath => $drvPath, outpath => $outPath, system => $buildInfo->{system}, iscurrent => 1, nixexprinput => $jobset->nixexprinput, nixexprpath => $jobset->nixexprpath});print STDERR "added to queue as build ", $build->id, "\n";$currentBuilds->{$build->id} = 1;$build->create_related('buildschedulinginfo',{ priority => $priority, busy => 0, locker => ""});my %inputs;$inputs{$jobset->nixexprinput} = $nixExprInput;foreach my $arg (@{$buildInfo->{arg}}) {$inputs{$arg->{name}} = $inputInfo->{$arg->{name}}->[$arg->{altnr}]|| die "invalid input";}foreach my $name (keys %inputs) {my $input = $inputs{$name};$build->buildinputs_builds->create({ name => $name, type => $input->{type}, uri => $input->{uri}, revision => $input->{revision}, value => $input->{value}, dependency => $input->{id}, path => $input->{storePath} || "" # !!! temporary hack, sha256hash => $input->{sha256hash}});}});return $build;};
# Check whether to add the build described by $buildInfo.sub checkBuild {my ($project, $jobset, $inputInfo, $nixExprInput, $buildInfo, $currentBuilds) = @_;my $jobName = $buildInfo->{jobName};my $drvPath = $buildInfo->{drvPath};my $outPath = $buildInfo->{outPath};my $priority = 100;$priority = int($buildInfo->{schedulingPriority})if $buildInfo->{schedulingPriority} =~ /^\d+$/;txn_do($db, sub {# Update the last evaluation time in the database.my $job = $jobset->jobs->update_or_create({ name => $jobName, lastevaltime => time});
$job->update({firstevaltime => time})unless defined $job->firstevaltime;# Don't add a build that has already been scheduled for this# job, or has been built but is still a "current" build for# this job. Note that this means that if the sources of a job# are changed from A to B and then reverted to A, three builds# will be performed (though the last one will probably use the# cached result from the first). This ensures that the builds# with the highest ID will always be the ones that we want in# the channels.# !!! Checking $outPath doesn't take meta-attributes into# account. For instance, do we want a new build to be# scheduled if the meta.maintainers field is changed?my @previousBuilds = $job->builds->search({outPath => $outPath, isCurrent => 1});if (scalar(@previousBuilds) > 0) {print "already scheduled/built\n";$currentBuilds->{$_->id} = 1 foreach @previousBuilds;return;}# Nope, so add it.my $build = $job->builds->create({ finished => 0, timestamp => time(), description => $buildInfo->{description}, longdescription => $buildInfo->{longDescription}, license => $buildInfo->{license}, homepage => $buildInfo->{homepage}, maintainers => $buildInfo->{maintainers}, nixname => $buildInfo->{nixName}, drvpath => $drvPath, outpath => $outPath, system => $buildInfo->{system}, iscurrent => 1, nixexprinput => $jobset->nixexprinput, nixexprpath => $jobset->nixexprpath});
print "added to queue as build ", $build->id, "\n";$currentBuilds->{$build->id} = 1;$build->create_related('buildschedulinginfo',{ priority => $priority, busy => 0, locker => ""});my %inputs;$inputs{$jobset->nixexprinput} = $nixExprInput;foreach my $arg (@{$buildInfo->{arg}}) {$inputs{$arg->{name}} = $inputInfo->{$arg->{name}}->[$arg->{altnr}]|| die "invalid input";}foreach my $name (keys %inputs) {my $input = $inputs{$name};$build->buildinputs_builds->create({ name => $name, type => $input->{type}, uri => $input->{uri}, revision => $input->{revision}, value => $input->{value}, dependency => $input->{id}, path => $input->{storePath} || "" # !!! temporary hack, sha256hash => $input->{sha256hash}});}});};
sub inputsToArgs {my ($inputInfo) = @_;my @res = ();foreach my $input (keys %{$inputInfo}) {foreach my $alt (@{$inputInfo->{$input}}) {given ($alt->{type}) {when ("string") {push @res, "--argstr", $input, $alt->{value};}when ("boolean") {push @res, "--arg", $input, $alt->{value};}when (["svn", "path", "build"]) {push @res, "--arg", $input, ("{ outPath = builtins.storePath " . $alt->{storePath} . "" .(defined $alt->{revision} ? "; rev = \"" . $alt->{revision} . "\"" : "") .(defined $alt->{version} ? "; version = \"" . $alt->{version} . "\"" : "") .";}");}}}}return @res;}
my $nixExprInput = $inputInfo->{$jobset->nixexprinput}->[0]or die "cannot find the input containing the job expression";die "multiple alternatives for the input containing the Nix expression are not supported"if scalar @{$inputInfo->{$jobset->nixexprinput}} != 1;my $nixExprPath = $nixExprInput->{storePath} . "/" . $jobset->nixexprpath;(my $res, my $jobsXml, my $stderr) = captureStdoutStderr("hydra_eval_jobs", $nixExprPath, "--gc-roots-dir", getGCRootsDir,inputsToArgs($inputInfo));die "cannot evaluate the Nix expression containing the jobs:\n$stderr" unless $res;print STDERR "$stderr";
my ($jobs, $nixExprInput) = evalJobs($inputInfo, $jobset->nixexprinput, $jobset->nixexprpath);
my $jobs = XMLin($jobsXml,ForceArray => ['error', 'job', 'arg'],KeyAttr => [],SuppressEmpty => '')or die "cannot parse XML output";