* Refactoring: move fetchInput out of hydra_scheduler into a separate
[?]
Oct 26, 2009, 3:39 PM
OOQ2D3KCLFPYNAN253PHWLBQMB6OMO2KYQWQXLTP65SQAYZWQ5LACDependencies
- [2]
Q24QXGSM* Don't do pretty printing for large logs, because the XSLT processing - [3]
WRIU3S5E* UI for cloning builds (not functional yet). - [4]
4D4U5IPY* Allow jobsets to be disabled. - [5]
RWIBJ5L4* Autoflush stdout. - [6]
7ZHHVD6Q* Inputs of type "build" must now be declared explicitly. - [7]
FDE3BJAP* Refactoring. - [8]
NI5BVF2V* In job inputs of type "build", allow the project and jobset names of - [9]
6BLUKEQ2* Caching of "path" inputs, and fake a revision number for those. - [10]
N22GPKYT* Put info about logs / build products in the DB. - [11]
M552HLIA* Support variant builds. - [12]
PHX2HIVG* Store info about the build inputs in the build record. - [13]
CS7T2XFI - [14]
FPK5LF53* Put the project-related actions in a separate controller. Put the - [15]
XBU2ODSP* More renaming. - [16]
5NO7NCKT* Refactoring. - [17]
CMU3YKOU* Store the release name. - [18]
ECBA3GQO* Make the schema class names match the case of the SQL table names. - [19]
YAPITGB3* Boolean inputs. - [20]
ODNCGFQ5* Improved the navigation bar: don't include all projects (since that - [21]
AS2OXLRM* Editing releases. - [22]
ZVTSOVHN* Support Subversion checkouts. - [23]
X27GNHDV* Basic job info in the database. - [24]
A52HEFHQ* Allow builds to be restarted (if they failed with a transient error, - [25]
EBUKGUD5* Ordering by timestamp isn't a good idea here since a newer revision - [26]
T7AHGVGM - [27]
3HZY24CX* Make jobsets viewable under - [28]
H7CNGK4O* Log evaluation errors etc. in the DB. - [29]
3E6IP3R3* Add the name of the jobset to ReleaseSetJobs, otherwise we can't - [30]
AFTXA575* $HYDRA_DATA environment variable. - [31]
IN272KZW* Automatically keep all builds in the latest successful release in - [32]
TLZ2SPBR - [33]
POPU2ATH* hydra_scheduler: use eval-jobs. - [34]
HJLYC753* Adding input value alternatives. - [35]
JK2QWPH6 - [36]
NLJJZVHO* Use ->update({...}) properly. - [37]
F2G7Z2XK* Doh. - [38]
LZO3C2KI* Hack around those SQLite timeouts: just retry the transaction. - [*]
LBNVQXUB* Build the /build stuff in a separate controller. - [*]
D5QIOJGP* Move everything up one directory. - [*]
2GK5DOU7* Downloading closures.
Change contents
- edit in src/lib/Hydra/Controller/Build.pm at line 8
use Hydra::Helper::AddBuilds; - edit in src/lib/Hydra/Controller/Build.pm at line 406
my ($nixExprPath, $nixExprInput) = Hydra::Controller::Jobset::nixExprPathFromParams $c; - edit in src/lib/Hydra/Controller/Build.pm at line 409
my $jobName = trim $c->request->params->{"jobname"};error($c, "Invalid job name: $jobName") if $jobName !~ /^$jobNameRE$/;foreach my $param (keys %{$c->request->params}) {next unless $param =~ /^input-(\w+)-name$/;my $baseName = $1;my ($inputName, $inputType) =Hydra::Controller::Jobset::checkInput($c, $baseName);my $inputValue = Hydra::Controller::Jobset::checkInputValue($c, $inputType, $c->request->params->{"input-$baseName-value"});eval {fetchInput($c->model('DB'), $build->project, $build->jobset,$inputName, $inputType, $inputValue);};error($c, $@) if $@;} - edit in src/lib/Hydra/Controller/Jobset.pm at line 96
}sub nixExprPathFromParams {my ($c) = @_;# The Nix expression path must be relative and can't contain ".." elements.my $nixExprPath = trim $c->request->params->{"nixexprpath"};error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/;my $nixExprInput = trim $c->request->params->{"nixexprinput"};error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/;return ($nixExprPath, $nixExprInput);}sub checkInput {my ($c, $baseName) = @_;my $inputName = trim $c->request->params->{"input-$baseName-name"};error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;my $inputType = trim $c->request->params->{"input-$baseName-type"};error($c, "Invalid input type: $inputType") unless$inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||$inputType eq "string" || $inputType eq "path" || $inputType eq "boolean" ||$inputType eq "build";return ($inputName, $inputType); - edit in src/lib/Hydra/Controller/Jobset.pm at line 129
sub checkInputValue {my ($c, $type, $value) = @_;$value = trim $value;error($c, "Invalid Boolean value: $value") if$type eq "boolean" && !($value eq "true" || $value eq "false");return $value;} - replacement in src/lib/Hydra/Controller/Jobset.pm at line 144
# The Nix expression path must be relative and can't contain ".." elements.my $nixExprPath = trim $c->request->params->{"nixexprpath"};error($c, "Invalid Nix expression path: $nixExprPath") if $nixExprPath !~ /^$relPathRE$/;my $nixExprInput = trim $c->request->params->{"nixexprinput"};error($c, "Invalid Nix expression input name: $nixExprInput") unless $nixExprInput =~ /^\w+$/;my ($nixExprPath, $nixExprInput) = nixExprPathFromParams $c; - replacement in src/lib/Hydra/Controller/Jobset.pm at line 159
my $baseName2 = $1;next if $baseName2 eq "template";print STDERR "GOT INPUT: $baseName2\n";my $baseName = $1;next if $baseName eq "template"; - replacement in src/lib/Hydra/Controller/Jobset.pm at line 162
my $inputName = trim $c->request->params->{"input-$baseName2-name"};error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;my ($inputName, $inputType) = checkInput($c, $baseName); - edit in src/lib/Hydra/Controller/Jobset.pm at line 164
my $inputType = trim $c->request->params->{"input-$baseName2-type"};error($c, "Invalid input type: $inputType") unless$inputType eq "svn" || $inputType eq "cvs" || $inputType eq "tarball" ||$inputType eq "string" || $inputType eq "path" || $inputType eq "boolean" ||$inputType eq "build"; - replacement in src/lib/Hydra/Controller/Jobset.pm at line 167
if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entryif ($baseName =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry - replacement in src/lib/Hydra/Controller/Jobset.pm at line 173
$input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];$input = ($jobset->jobsetinputs->search({name => $baseName}))[0]; - replacement in src/lib/Hydra/Controller/Jobset.pm at line 181
my $values = $c->request->params->{"input-$baseName2-values"};my $values = $c->request->params->{"input-$baseName-values"}; - replacement in src/lib/Hydra/Controller/Jobset.pm at line 186
print STDERR "VALUE: $value\n";my $value = trim $value;error($c, "Invalid Boolean value: $value") if$inputType eq "boolean" && !($value eq "true" || $value eq "false");$value = checkInputValue($c, $inputType, $value); - file addition: AddBuilds.pm[41.339]
package Hydra::Helper::AddBuilds;use strict;use POSIX qw(strftime);use Hydra::Helper::Nix;our @ISA = qw(Exporter);our @EXPORT = qw(fetchInput);sub getStorePathHash {my ($storePath) = @_;my $hash = `nix-store --query --hash $storePath`or die "cannot get hash of $storePath";chomp $hash;die unless $hash =~ /^sha256:(.*)$/;$hash = $1;$hash = `nix-hash --to-base16 --type sha256 $hash`or die "cannot convert hash";chomp $hash;return $hash;}sub parseJobName {# Parse a job specification of the form `<project>:<jobset>:<job># [attrs]'. The project, jobset and attrs may be omitted. The# attrs have the form `name = "value"'.my ($s) = @_;our $key;our %attrs = ();# hm, maybe I should stop programming Perl before it's too late...$s =~ / ^ (?: (?: ([\w\-]+) : )? ([\w\-]+) : )? ([\w\-]+) \s*(\[ \s* (([\w]+) (?{ $key = $^N; }) \s* = \s* \"([\w\-]+) (?{ $attrs{$key} = $^N; }) \"\s* )* \])? $/xor die "invalid job specifier `$s'";return ($1, $2, $3, \%attrs);}sub attrsToSQL {my ($attrs, $id) = @_;my $query = "1 = 1";foreach my $name (keys %{$attrs}) {my $value = $attrs->{$name};$name =~ /^[\w\-]+$/ or die;$value =~ /^[\w\-]+$/ or die;# !!! Yes, this is horribly injection-prone... (though# name/value are filtered above). Should use SQL::Abstract,# but it can't deal with subqueries. At least we should use# placeholders.$query .= " and exists (select 1 from buildinputs where build = $id and name = '$name' and value = '$value')";}return $query;}sub fetchInput {my ($db, $project, $jobset, $name, $type, $value) = @_;if ($type eq "path") {my $uri = $value;my $timestamp = time;my $sha256;my $storePath;# Some simple caching: don't check a path more than once every N seconds.(my $cachedInput) = $db->resultset('CachedPathInputs')->search({srcpath => $uri, lastseen => {">", $timestamp - 60}},{rows => 1, order_by => "lastseen DESC"});if (defined $cachedInput && isValidPath($cachedInput->storepath)) {$storePath = $cachedInput->storepath;$sha256 = $cachedInput->sha256hash;$timestamp = $cachedInput->timestamp;} else {print STDERR "copying input ", $name, " from $uri\n";$storePath = `nix-store --add "$uri"`or die "Cannot copy path $uri to the Nix store.\n";chomp $storePath;$sha256 = getStorePathHash $storePath;($cachedInput) = $db->resultset('CachedPathInputs')->search({srcpath => $uri, sha256hash => $sha256});# Path inputs don't have a natural notion of a "revision",# so we simulate it by using the timestamp that we first# saw this path have this SHA-256 hash. So if the# contents of the path changes, we get a new "revision",# but if it doesn't change (or changes back), we don't get# a new "revision".if (!defined $cachedInput) {txn_do($db, sub {$db->resultset('CachedPathInputs')->create({ srcpath => $uri, timestamp => $timestamp, lastseen => $timestamp, sha256hash => $sha256, storepath => $storePath});});} else {$timestamp = $cachedInput->timestamp;txn_do($db, sub {$cachedInput->update({lastseen => time});});}}return{ type => $type, uri => $uri, storePath => $storePath, sha256hash => $sha256, revision => strftime "%Y%m%d%H%M%S", gmtime($timestamp)};}elsif ($type eq "svn") {my $uri = $value;my $sha256;my $storePath;# First figure out the last-modified revision of the URI.my @cmd = (["svn", "ls", "-v", "--depth", "empty", $uri],"|", ["sed", 's/^ *\([0-9]*\).*/\1/']);my $stdout; my $stderr;die "Cannot get head revision of Subversion repository at `$uri':\n$stderr"unless IPC::Run::run(@cmd, \$stdout, \$stderr);my $revision = $stdout; chomp $revision;die unless $revision =~ /^\d+$/;(my $cachedInput) = $db->resultset('CachedSubversionInputs')->search({uri => $uri, revision => $revision});if (defined $cachedInput && isValidPath($cachedInput->storepath)) {$storePath = $cachedInput->storepath;$sha256 = $cachedInput->sha256hash;} else {# Then download this revision into the store.print STDERR "checking out Subversion input ", $name, " from $uri revision $revision\n";$ENV{"NIX_HASH_ALGO"} = "sha256";$ENV{"PRINT_PATH"} = "1";(my $res, $stdout, $stderr) = captureStdoutStderr("nix-prefetch-svn", $uri, $revision);die "Cannot check out Subversion repository `$uri':\n$stderr" unless $res;($sha256, $storePath) = split ' ', $stdout;txn_do($db, sub {$db->resultset('CachedSubversionInputs')->create({ uri => $uri, revision => $revision, sha256hash => $sha256, storepath => $storePath});});}return{ type => $type, uri => $uri, storePath => $storePath, sha256hash => $sha256, revision => $revision};}elsif ($type eq "build") {my ($projectName, $jobsetName, $jobName, $attrs) = parseJobName($value);$projectName ||= $project->name;$jobsetName ||= $jobset->name;# Pick the most recent successful build of the specified job.(my $prevBuild) = $db->resultset('Builds')->search({ finished => 1, project => $projectName, jobset => $jobsetName, job => $jobName, buildStatus => 0 },{ join => 'resultInfo', order_by => "me.id DESC", rows => 1, where => \ attrsToSQL($attrs, "me.id") });if (!defined $prevBuild || !isValidPath($prevBuild->outpath)) {print STDERR "input `", $name, "': no previous build available\n";return undef;}#print STDERR "input `", $name, "': using build ", $prevBuild->id, "\n";my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";my $versionRE = "(?:[A-Za-z0-9\.\-]+)";my $relName = ($prevBuild->resultInfo->releasename or $prevBuild->nixname);my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/;return{ type => "build", storePath => $prevBuild->outpath, id => $prevBuild->id, version => $version};}elsif ($type eq "string") {die unless defined $value;return {type => $type, value => $value};}elsif ($type eq "boolean") {die unless defined $value && ($value eq "true" || $value eq "false");return {type => $type, value => $value};}else {die "Input `" . $name . "' has unknown type `$type'.";}} - replacement in src/lib/Hydra/Helper/CatalystUtils.pm at line 14
$pathCompRE $relPathRE $relNameRE$pathCompRE $relPathRE $relNameRE $jobNameRE - replacement in src/lib/Hydra/Helper/CatalystUtils.pm at line 135
Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:\/$pathCompRE)*)";Readonly::Scalar our $relNameRE =>"(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:/$pathCompRE)*)";Readonly::Scalar our $relNameRE => "(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";Readonly::Scalar our $attrNameRE => "(?:[A-Za-z_][A-Za-z0-9_]*)";Readonly::Scalar our $jobNameRE => "(?:$attrNameRE(?:\\.$attrNameRE)*)"; - edit in src/lib/Hydra/Helper/Nix.pm at line 276
- replacement in src/root/clone-build.tt at line 31
<td><tt>[% input.name %]</tt></td><td><tt>[% input.name %]<input type="hidden" [% HTML.attributes(name => "input-$input.name-name" value => input.name) %] /></tt></td> - edit in src/script/hydra_scheduler.pl at line 8
use Hydra::Helper::AddBuilds; - edit in src/script/hydra_scheduler.pl at line 10
use POSIX qw(strftime); - edit in src/script/hydra_scheduler.pl at line 24[4.2174]→[4.1826:2182](∅→∅),[4.6685]→[4.1826:2182](∅→∅),[4.2182]→[4.120:1360](∅→∅),[4.1360]→[4.2182:2186](∅→∅),[4.2182]→[4.2182:2186](∅→∅),[4.2186]→[4.290:310](∅→∅),[4.310]→[4.133:180](∅→∅),[4.180]→[4.6736:6765](∅→∅),[4.338]→[4.6736:6765](∅→∅),[4.5316]→[4.6736:6765](∅→∅),[4.6736]→[4.6736:6765](∅→∅),[4.6792]→[4.6792:6820](∅→∅),[4.6820]→[4.2707:2738](∅→∅),[4.2738]→[4.1598:1755](∅→∅),[4.1755]→[4.5207:5279](∅→∅),[4.5279]→[4.1827:2026](∅→∅),[4.1827]→[4.1827:2026](∅→∅),[4.2134]→[4.2134:2564](∅→∅),[4.2564]→[4.5280:5353](∅→∅),[4.5353]→[4.2637:3113](∅→∅),[4.2637]→[4.2637:3113](∅→∅),[4.3113]→[4.1292:1326](∅→∅),[4.1326]→[4.5354:5418](∅→∅),[4.3147]→[4.5354:5418](∅→∅),[4.5418]→[4.3211:3573](∅→∅),[4.3211]→[4.3211:3573](∅→∅),[4.3573]→[4.1327:1361](∅→∅),[4.1361]→[4.1004:1066](∅→∅),[4.3607]→[4.1004:1066](∅→∅),[4.1066]→[4.3699:3744](∅→∅),[4.3699]→[4.3699:3744](∅→∅),[4.3744]→[4.339:354](∅→∅),[4.354]→[4.2232:2324](∅→∅),[4.2232]→[4.2232:2324](∅→∅),[4.2324]→[4.3745:3851](∅→∅),[4.3851]→[4.2380:2395](∅→∅),[4.2380]→[4.2380:2395](∅→∅),[4.2395]→[4.7065:7071](∅→∅),[4.3626]→[4.7065:7071](∅→∅),[4.5438]→[4.7065:7071](∅→∅),[4.7065]→[4.7065:7071](∅→∅),[4.7071]→[4.3345:3909](∅→∅),[4.3909]→[4.5419:5497](∅→∅),[4.5497]→[4.3987:4690](∅→∅),[4.3987]→[4.3987:4690](∅→∅),[4.4690]→[4.7071:7072](∅→∅),[4.7071]→[4.7071:7072](∅→∅),[4.7072]→[4.4691:4748](∅→∅),[4.4748]→[4.1362:1392](∅→∅),[4.1392]→[4.5498:5564](∅→∅),[4.4778]→[4.5498:5564](∅→∅),[4.5564]→[4.4844:5062](∅→∅),[4.4844]→[4.4844:5062](∅→∅),[4.5062]→[4.355:372](∅→∅),[4.372]→[4.5107:5292](∅→∅),[4.5107]→[4.5107:5292](∅→∅),[4.5292]→[4.181:213](∅→∅),[4.213]→[4.1361:1527](∅→∅),[4.1527]→[4.255:386](∅→∅),[4.255]→[4.255:386](∅→∅),[4.386]→[4.1528:1784](∅→∅),[4.71]→[4.585:658](∅→∅),[4.74]→[4.585:658](∅→∅),[4.1784]→[4.585:658](∅→∅),[4.585]→[4.585:658](∅→∅),[4.658]→[4.1785:1871](∅→∅),[4.1871]→[4.729:765](∅→∅),[4.729]→[4.729:765](∅→∅),[4.765]→[4.1872:1961](∅→∅),[4.1961]→[4.765:1222](∅→∅),[4.765]→[4.765:1222](∅→∅),[4.1222]→[4.5292:5297](∅→∅),[4.5292]→[4.5292:5297](∅→∅),[4.5297]→[4.5439:5511](∅→∅),[4.7072]→[4.5439:5511](∅→∅),[4.5511]→[4.373:427](∅→∅),[4.427]→[4.5586:5597](∅→∅),[4.5586]→[4.5586:5597](∅→∅),[4.5597]→[4.2224:2350](∅→∅),[4.2350]→[4.428:482](∅→∅),[4.482]→[4.2425:2436](∅→∅),[4.2425]→[4.2425:2436](∅→∅),[4.2436]→[4.7072:7083](∅→∅),[4.5597]→[4.7072:7083](∅→∅),[4.7072]→[4.7072:7083](∅→∅),[4.7083]→[4.5298:5367](∅→∅),[4.5367]→[4.7152:7158](∅→∅),[4.7152]→[4.7152:7158](∅→∅),[4.7158]→[4.3635:3637](∅→∅),[4.3635]→[4.3635:3637](∅→∅),[4.3637]→[4.7159:7161](∅→∅)
sub getStorePathHash {my ($storePath) = @_;my $hash = `nix-store --query --hash $storePath`or die "cannot get hash of $storePath";chomp $hash;die unless $hash =~ /^sha256:(.*)$/;$hash = $1;$hash = `nix-hash --to-base16 --type sha256 $hash`or die "cannot convert hash";chomp $hash;return $hash;}sub parseJobName {# Parse a job specification of the form `<project>:<jobset>:<job># [attrs]'. The project, jobset and attrs may be omitted. The# attrs have the form `name = "value"'.my ($s) = @_;our $key;our %attrs = ();# hm, maybe I should stop programming Perl before it's too late...$s =~ / ^ (?: (?: ([\w\-]+) : )? ([\w\-]+) : )? ([\w\-]+) \s*(\[ \s* (([\w]+) (?{ $key = $^N; }) \s* = \s* \"([\w\-]+) (?{ $attrs{$key} = $^N; }) \"\s* )* \])? $/xor die "invalid job specifier `$s'";return ($1, $2, $3, \%attrs);}sub attrsToSQL {my ($attrs, $id) = @_;my $query = "1 = 1";foreach my $name (keys %{$attrs}) {my $value = $attrs->{$name};$name =~ /^[\w\-]+$/ or die;$value =~ /^[\w\-]+$/ or die;# !!! Yes, this is horribly injection-prone... (though# name/value are filtered above). Should use SQL::Abstract,# but it can't deal with subqueries. At least we should use# placeholders.$query .= " and exists (select 1 from buildinputs where build = $id and name = '$name' and value = '$value')";}return $query;}sub fetchInputAlt {my ($project, $jobset, $input, $alt) = @_;my $type = $input->type;if ($type eq "path") {my $uri = $alt->value;my $timestamp = time;my $sha256;my $storePath;# Some simple caching: don't check a path more than once every N seconds.(my $cachedInput) = $db->resultset('CachedPathInputs')->search({srcpath => $uri, lastseen => {">", $timestamp - 60}},{rows => 1, order_by => "lastseen DESC"});if (defined $cachedInput && isValidPath($cachedInput->storepath)) {$storePath = $cachedInput->storepath;$sha256 = $cachedInput->sha256hash;$timestamp = $cachedInput->timestamp;} else {print "copying input ", $input->name, " from $uri\n";$storePath = `nix-store --add "$uri"`or die "cannot copy path $uri to the Nix store";chomp $storePath;$sha256 = getStorePathHash $storePath;($cachedInput) = $db->resultset('CachedPathInputs')->search({srcpath => $uri, sha256hash => $sha256});# Path inputs don't have a natural notion of a "revision",# so we simulate it by using the timestamp that we first# saw this path have this SHA-256 hash. So if the# contents of the path changes, we get a new "revision",# but if it doesn't change (or changes back), we don't get# a new "revision".if (!defined $cachedInput) {txn_do($db, sub {$db->resultset('CachedPathInputs')->create({ srcpath => $uri, timestamp => $timestamp, lastseen => $timestamp, sha256hash => $sha256, storepath => $storePath});});} else {$timestamp = $cachedInput->timestamp;txn_do($db, sub {$cachedInput->update({lastseen => time});});}}return{ type => $type, uri => $uri, storePath => $storePath, sha256hash => $sha256, revision => strftime "%Y%m%d%H%M%S", gmtime($timestamp)};}elsif ($type eq "svn") {my $uri = $alt->value;my $sha256;my $storePath;# First figure out the last-modified revision of the URI.my @cmd = (["svn", "ls", "-v", "--depth", "empty", $uri],"|", ["sed", 's/^ *\([0-9]*\).*/\1/']);my $stdout; my $stderr;die "cannot get head revision of Subversion repository at `$uri':\n$stderr"unless IPC::Run::run(@cmd, \$stdout, \$stderr);my $revision = $stdout; chomp $revision;die unless $revision =~ /^\d+$/;(my $cachedInput) = $db->resultset('CachedSubversionInputs')->search({uri => $uri, revision => $revision});if (defined $cachedInput && isValidPath($cachedInput->storepath)) {$storePath = $cachedInput->storepath;$sha256 = $cachedInput->sha256hash;} else {# Then download this revision into the store.print "checking out Subversion input ", $input->name, " from $uri revision $revision\n";$ENV{"NIX_HASH_ALGO"} = "sha256";$ENV{"PRINT_PATH"} = "1";(my $res, $stdout, $stderr) = captureStdoutStderr("nix-prefetch-svn", $uri, $revision);die "cannot check out Subversion repository `$uri':\n$stderr" unless $res;($sha256, $storePath) = split ' ', $stdout;txn_do($db, sub {$db->resultset('CachedSubversionInputs')->create({ uri => $uri, revision => $revision, sha256hash => $sha256, storepath => $storePath});});}return{ type => $type, uri => $uri, storePath => $storePath, sha256hash => $sha256, revision => $revision};}elsif ($type eq "build") {my ($projectName, $jobsetName, $jobName, $attrs) = parseJobName($alt->value);$projectName ||= $project->name;$jobsetName ||= $jobset->name;# Pick the most recent successful build of the specified job.(my $prevBuild) = $db->resultset('Builds')->search({ finished => 1, project => $projectName, jobset => $jobsetName, job => $jobName, buildStatus => 0 },{ join => 'resultInfo', order_by => "me.id DESC", rows => 1, where => \ attrsToSQL($attrs, "me.id") });if (!defined $prevBuild || !isValidPath($prevBuild->outpath)) {print STDERR "input `", $input->name, "': no previous build available\n";return undef;}#print STDERR "input `", $input->name, "': using build ", $prevBuild->id, "\n";my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";my $versionRE = "(?:[A-Za-z0-9\.\-]+)";my $relName = ($prevBuild->resultInfo->releasename or $prevBuild->nixname);my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/;return{ type => "build", storePath => $prevBuild->outpath, id => $prevBuild->id, version => $version};}elsif ($type eq "string") {die unless defined $alt->value;return {type => $type, value => $alt->value};}elsif ($type eq "boolean") {die unless defined $alt->value && ($alt->value eq "true" || $alt->value eq "false");return {type => $type, value => $alt->value};}else {die "input `" . $input->name . "' has unknown type `$type'";}} - replacement in src/script/hydra_scheduler.pl at line 28
my $info = fetchInputAlt($project, $jobset, $input, $alt);my $info = fetchInput($db, $project, $jobset, $input->name, $input->type, $alt->value);