* Refactoring: move fetchInput out of hydra_scheduler into a separate

[?]
Oct 26, 2009, 3:39 PM
OOQ2D3KCLFPYNAN253PHWLBQMB6OMO2KYQWQXLTP65SQAYZWQ5LAC

Dependencies

  • [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
    [40.156]
    [2.0]
    use Hydra::Helper::AddBuilds;
  • edit in src/lib/Hydra/Controller/Build.pm at line 406
    [3.409]
    [3.409]
    my ($nixExprPath, $nixExprInput) = Hydra::Controller::Jobset::nixExprPathFromParams $c;
  • edit in src/lib/Hydra/Controller/Build.pm at line 409
    [3.410]
    [3.410]
    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
    [4.1463]
    [4.1463]
    }
    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
    [4.1467]
    [4.1467]
    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
    [4.1668][4.1668:2074]()
    # 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+$/;
    [4.1668]
    [4.2074]
    my ($nixExprPath, $nixExprInput) = nixExprPathFromParams $c;
  • replacement in src/lib/Hydra/Controller/Jobset.pm at line 159
    [4.2461][4.2461:2579]()
    my $baseName2 = $1;
    next if $baseName2 eq "template";
    print STDERR "GOT INPUT: $baseName2\n";
    [4.2461]
    [4.2579]
    my $baseName = $1;
    next if $baseName eq "template";
  • replacement in src/lib/Hydra/Controller/Jobset.pm at line 162
    [4.2580][4.2580:2750]()
    my $inputName = trim $c->request->params->{"input-$baseName2-name"};
    error($c, "Invalid input name: $inputName") unless $inputName =~ /^[[:alpha:]]\w*$/;
    [4.2580]
    [4.2750]
    my ($inputName, $inputType) = checkInput($c, $baseName);
  • edit in src/lib/Hydra/Controller/Jobset.pm at line 164
    [4.2751][4.2751:3097]()
    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
    [4.3166][4.3166:3259]()
    if ($baseName2 =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
    [4.3166]
    [4.3259]
    if ($baseName =~ /^\d+$/) { # numeric base name is auto-generated, i.e. a new entry
  • replacement in src/lib/Hydra/Controller/Jobset.pm at line 173
    [4.3447][4.3447:3526]()
    $input = ($jobset->jobsetinputs->search({name => $baseName2}))[0];
    [4.3447]
    [4.3526]
    $input = ($jobset->jobsetinputs->search({name => $baseName}))[0];
  • replacement in src/lib/Hydra/Controller/Jobset.pm at line 181
    [4.3808][4.3808:3879]()
    my $values = $c->request->params->{"input-$baseName2-values"};
    [4.3808]
    [4.3879]
    my $values = $c->request->params->{"input-$baseName-values"};
  • replacement in src/lib/Hydra/Controller/Jobset.pm at line 186
    [4.4048][4.4048:4272]()
    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");
    [4.4048]
    [4.4272]
    $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* )* \])? $
    /x
    or 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
    [4.9780][4.1375:1413]()
    $pathCompRE $relPathRE $relNameRE
    [4.9780]
    [4.180]
    $pathCompRE $relPathRE $relNameRE $jobNameRE
  • replacement in src/lib/Hydra/Helper/CatalystUtils.pm at line 135
    [4.294][4.294:367](),[4.367][4.1414:1484]()
    Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:\/$pathCompRE)*)";
    Readonly::Scalar our $relNameRE =>"(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";
    [4.294]
    [4.367]
    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
    [4.3661][4.3661:3666]()
  • replacement in src/root/clone-build.tt at line 31
    [3.1633][3.1633:1678]()
    <td><tt>[% input.name %]</tt></td>
    [3.1633]
    [3.1678]
    <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
    [4.1770]
    [4.1980]
    use Hydra::Helper::AddBuilds;
  • edit in src/script/hydra_scheduler.pl at line 10
    [4.1994][4.1573:1597]()
    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* )* \])? $
    /x
    or 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
    [4.646][4.1269:1340]()
    my $info = fetchInputAlt($project, $jobset, $input, $alt);
    [4.646]
    [4.1340]
    my $info = fetchInput($db, $project, $jobset, $input->name, $input->type, $alt->value);