* Refactoring.

[?]
Feb 25, 2009, 2:34 PM
5NO7NCKTMM5ZW7JYOETUFOSWK2ACTXWDZGJAFXZN6L3OF6BFTNOQC

Dependencies

  • [2] FSE6N6S3 * Make HEAD requests work when doing Nix closure downloads.
  • [3] EYNG4EL4 * Regenerate the bindings from a clean sqlite database.
  • [4] IN272KZW * Automatically keep all builds in the latest successful release in
  • [5] LBNVQXUB * Build the /build stuff in a separate controller.
  • [6] IWVA2P2Y * Generate manifests on demand. Next step: generate NAR archives on
  • [7] UVMFS73T * Some jQuery / CSS hackery.
  • [8] AFTXA575 * $HYDRA_DATA environment variable.
  • [9] GC4LTHDI * Check the owner.
  • [10] FHF6IZJQ * Basic release management: releases are now dynamically computed as
  • [11] L5VIEXSC * Allow downloading of build products.
  • [12] SHBLLAVH * More global substitution.
  • [13] JLDUSNUO * Unify rendering of finished and scheduled builds.
  • [14] ZNFDFJHG * Provide a redirect to the latest successful release in a release set
  • [15] NYC3LZKH * Generate NAR archives on the fly. Necessary for producing channels
  • [16] UHANDRAR * Closure downloads: don't include the product number; it's not needed.
  • [17] DR4F6YUT
  • [18] LQNBKF3D
  • [19] LQ5QEDVV
  • [20] 5IK6NYKF
  • [21] MOCEUXZA * Support serving products that are directories (such as manuals or
  • [22] J5UVLXOK * Start of a basic Catalyst web interface.
  • [23] RU7AQO7U * Role-based access control. Only admins can create projects. Only
  • [24] 2AUODJBT
  • [25] 2GK5DOU7 * Downloading closures.
  • [26] K5BEBWKM
  • [27] Y35C6GHH * One-click installs.
  • [28] JD27RBKM
  • [29] JFZNAYJX * Showing releases.
  • [30] BA46C5LN * Pretty-print the logs.
  • [31] SMM4HQTP * Put actions related to builds under /build (e.g. /log/<buildid>
  • [32] KOTB7BKV
  • [33] IK53RV4V
  • [34] 2AIIYGI5 * Show job status and all builds for a project.
  • [35] G6HJY2V4
  • [36] GCHNNFZP
  • [*] PKPWUHUX * Idem.

Change contents

  • file addition: Base (d--r------)
    [38.35]
  • file addition: Controller (d--r------)
    [0.1]
  • file addition: Nix.pm (----------)
    [0.19]
    package Hydra::Base::Controller::Nix;
    use strict;
    use warnings;
    use parent 'Catalyst::Controller';
    use Hydra::Helper::Nix;
    use Hydra::Helper::CatalystUtils;
    sub closure : Chained('nix') PathPart {
    my ($self, $c) = @_;
    $c->stash->{current_view} = 'Hydra::View::NixClosure';
    # !!! quick hack; this is to make HEAD requests return the right
    # MIME type. This is set in the view as well, but the view isn't
    # called for HEAD requests. There should be a cleaner solution...
    $c->response->content_type('application/x-nix-export');
    }
    sub manifest : Chained('nix') PathPart Args(0) {
    my ($self, $c) = @_;
    $c->stash->{current_view} = 'Hydra::View::NixManifest';
    }
    1;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 5
    [5.63][5.63:98]()
    use parent 'Catalyst::Controller';
    [5.63]
    [5.98]
    use base 'Hydra::Base::Controller::Nix';
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 21
    [5.466][5.466:622]()
    if (!defined $c->stash->{build}) {
    error($c, "Build with ID $id doesn't exist.");
    $c->response->status(404);
    return;
    }
    [5.466]
    [5.622]
    notFound($c, "Build with ID $id doesn't exist.")
    if !defined $c->stash->{build};
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 49
    [5.1288][5.1288:1372]()
    return error($c, "Build doesn't have a build step $stepnr.") if !defined $step;
    [5.1288]
    [5.1372]
    notFound($c, "Build doesn't have a build step $stepnr.") if !defined $step;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 62
    [5.1642][5.1642:1747]()
    return error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->resultInfo->logfile;
    [5.1642]
    [5.1747]
    error($c, "Build didn't produce a log.") if !defined $c->stash->{build}->resultInfo->logfile;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 89
    [5.2485][5.2485:2572]()
    return error($c, "Build doesn't have a product $productnr.") if !defined $product;
    [5.2485]
    [5.2572]
    notFound($c, "Build doesn't have a product $productnr.") if !defined $product;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 91
    [5.2573][5.2573:2671]()
    return error($c, "Product " . $product->path . " has disappeared.") unless -e $product->path;
    [5.2573]
    [5.2671]
    error($c, "Product " . $product->path . " has disappeared.") unless -e $product->path;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 95
    [5.2728][5.2728:2809]()
    return error($c, "Invalid filename $elem.") if $elem !~ /^$pathCompRE$/;
    [5.2728]
    [5.2809]
    error($c, "Invalid filename $elem.") if $elem !~ /^$pathCompRE$/;
  • replacement in src/Hydra/lib/Hydra/Controller/Build.pm at line 108
    [5.3175][5.3175:3258]()
    if (!-e $path) {
    return error($c, "File $path does not exist.");
    }
    [5.3175]
    [5.3258]
    notFound($c, "File $path does not exist.") if !-e $path;
  • edit in src/Hydra/lib/Hydra/Controller/Build.pm at line 111
    [5.3293]
    [5.3293]
    }
    sub nix : Chained('build') PathPart('nix') CaptureArgs(0) {
    my ($self, $c) = @_;
    my $build = $c->stash->{build};
    error($c, "Build cannot be downloaded as a closure or Nix package.")
    if !$build->buildproducts->find({type => "nix-build"});
    error($c, "Path " . $build->outpath . " is no longer available.")
    unless isValidPath($build->outpath);
    $c->stash->{name} = $build->nixname;
    $c->stash->{storePaths} = [$build->outpath];
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 5
    [6.873][6.873:908]()
    use parent 'Catalyst::Controller';
    [6.873]
    [6.86]
    use base 'Catalyst::Controller';
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 155
    [6.233][6.233:315]()
    return error($c, "Project $projectName doesn't exist.") if !defined $project;
    [6.233]
    [6.315]
    notFound($c, "Project $projectName doesn't exist.") if !defined $project;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 228
    [6.928][6.928:1028]()
    return error($c, "Only the project owner or the administrator can perform this operation.")
    [6.928]
    [3.0]
    error($c, "Only the project owner or the administrator can perform this operation.")
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 250
    [6.237][6.1513:1571](),[6.1513][6.1513:1571]()
    else { return error($c, "Unknown subcommand."); }
    [6.237]
    [6.1571]
    else { error($c, "Unknown subcommand."); }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 270
    [6.546][6.546:642]()
    return error($c, "Only the project owner or the administrator can perform this operation.")
    [6.546]
    [3.102]
    error($c, "Only the project owner or the administrator can perform this operation.")
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 274
    [6.788][6.788:1412]()
    eval {
    my $releaseSetName = $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $releaseSetName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid.
    my $releaseSet = $project->releasesets->create({name => $releaseSetName});
    updateReleaseSet($c, $releaseSet);
    return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
    });
    };
    if ($@) {
    return error($c, $@);
    }
    [6.788]
    [6.1412]
    my $releaseSetName = $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $releaseSetName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid.
    my $releaseSet = $project->releasesets->create({name => $releaseSetName});
    updateReleaseSet($c, $releaseSet);
    return $c->res->redirect($c->uri_for("/releases", $projectName, $releaseSet->name));
    });
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 299
    [4.538][6.859:957](),[6.2877][6.859:957]()
    return error($c, "This release set has no successful releases yet.") if !defined $latest;
    [4.538]
    [6.958]
    error($c, "This release set has no successful releases yet.") if !defined $latest;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 307
    [6.2602][6.2602:2687]()
    return error($c, "Release $releaseId doesn't exist.") if !defined $primaryBuild;
    [6.2602]
    [6.2687]
    error($c, "Release $releaseId doesn't exist.") if !defined $primaryBuild;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 445
    [6.2984][6.1146:1228](),[6.189][6.1146:1228]()
    return error($c, "Project $projectName doesn't exist.") if !defined $project;
    [6.2984]
    [6.561]
    notFound($c, "Project $projectName doesn't exist.") if !defined $project;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 466
    [6.228][6.228:328]()
    return error($c, "Only the project owner or the administrator can perform this operation.")
    [6.228]
    [3.200]
    error($c, "Only the project owner or the administrator can perform this operation.")
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 488
    [6.1081][6.1081:1146]()
    return error($c, "Unknown subcommand $subcommand.");
    [6.1081]
    [6.1146]
    error($c, "Unknown subcommand $subcommand.");
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 504
    [6.421][6.421:486]()
    return error($c, "Only administrators can create projects.")
    [6.421]
    [6.486]
    error($c, "Only administrators can create projects.")
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 508
    [6.1388][6.1388:1403](),[6.1403][3.302:366](),[3.366][6.1462:1649](),[6.1462][6.1462:1649](),[6.1649][3.367:586](),[3.586][6.1782:1993](),[6.1782][6.1782:1993]()
    eval {
    my $projectName = trim $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $projectName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid. Idem for the owner.
    my $project = $c->model('DB::Projects')->create(
    {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
    updateProject($c, $project);
    });
    return $c->res->redirect($c->uri_for("/project", $projectName));
    };
    if ($@) {
    return error($c, $@);
    }
    [6.1388]
    [6.1993]
    my $projectName = trim $c->request->params->{name};
    $c->model('DB')->schema->txn_do(sub {
    # Note: $projectName is validated in updateProject,
    # which will abort the transaction if the name isn't
    # valid. Idem for the owner.
    my $project = $c->model('DB::Projects')->create(
    {name => $projectName, displayname => "", owner => trim $c->request->params->{owner}});
    updateProject($c, $project);
    });
    return $c->res->redirect($c->uri_for("/project", $projectName));
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 531
    [6.3050][6.1323:1405](),[6.2241][6.1323:1405]()
    return error($c, "Project $projectName doesn't exist.") if !defined $project;
    [6.3050]
    [6.2332]
    notFound($c, "Project $projectName doesn't exist.") if !defined $project;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 543
    [6.467][6.1558:1592](),[6.1558][6.1558:1592](),[6.1592][6.76:107]()
    error($c, "Page not found.");
    $c->response->status(404);
    [6.467]
    [6.2593]
    notFound($c, "Page not found.");
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 545
    [6.2595][6.0:2](),[6.75][6.75:96](),[6.96][6.21:56]()
    sub closure :Local {
    my ($self, $c, $buildId) = @_;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 546
    [6.146][6.146:186](),[6.186][6.57:131]()
    my $build = getBuild($c, $buildId);
    return error($c, "Build $buildId doesn't exist.") if !defined $build;
  • edit in src/Hydra/lib/Hydra/Controller/Root.pm at line 547
    [6.440][6.132:270](),[6.270][6.119:120](),[6.119][6.119:120](),[6.120][6.271:385](),[6.112][6.260:261](),[6.243][6.260:261](),[6.385][6.260:261](),[6.260][6.260:261](),[6.261][6.244:303](),[6.303][6.386:432](),[6.432][6.373:414](),[6.373][6.373:414](),[6.414][2.52:435](),[6.414][6.498:500](),[2.435][6.498:500](),[6.486][6.498:500](),[6.808][6.498:500](),[6.498][6.498:500](),[6.500][6.0:59](),[6.59][6.229:230](),[6.500][6.229:230](),[6.230][6.60:182](),[6.182][6.0:5](),[6.5][6.0:119](),[6.182][6.0:119](),[6.119][6.183:291](),[6.231][6.183:291](),[6.291][6.6:8]()
    return error($c, "Build $buildId cannot be downloaded as a closure.")
    if !$build->buildproducts->find({type => "nix-build"});
    return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
    $c->stash->{current_view} = 'Hydra::View::NixClosure';
    $c->stash->{storePath} = $build->outpath;
    $c->stash->{name} = $build->nixname;
    # !!! quick hack; this is to make HEAD requests return the right
    # MIME type. This is set in the view as well, but the view isn't
    # called for HEAD requests. There should be a cleaner solution...
    $c->response->content_type('application/x-nix-export');
    $c->response->header('Content-Disposition' => 'attachment; filename=' . $c->stash->{name} . '.closure.gz');
    }
    sub manifest :Local {
    my ($self, $c, $buildId) = @_;
    my $build = getBuild($c, $buildId);
    return error($c, "Build with ID $buildId doesn't exist.") if !defined $build;
    return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
    $c->stash->{current_view} = 'Hydra::View::NixManifest';
    $c->stash->{storePath} = $build->outpath;
    }
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 551
    [6.104][6.104:178]()
    return error($c, "Build $buildId doesn't exist.") if !defined $build;
    [6.104]
    [6.121]
    notFound($c, "Build $buildId doesn't exist.") if !defined $build;
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 553
    [6.122][6.179:257]()
    return error($c, "Build $buildId cannot be downloaded as a Nix package.")
    [6.122]
    [6.257]
    error($c, "Build $buildId cannot be downloaded as a Nix package.")
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 556
    [6.322][6.322:436]()
    return error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
    [6.322]
    [6.436]
    error($c, "Path " . $build->outpath . " is no longer available.") unless isValidPath($build->outpath);
  • replacement in src/Hydra/lib/Hydra/Controller/Root.pm at line 570
    [6.293][6.213:307]()
    return error($c, "Path " . $path . " is no longer available.") unless isValidPath($path);
    [6.293]
    [6.307]
    error($c, "Path " . $path . " is no longer available.") unless isValidPath($path);
  • replacement in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 7
    [5.3561][5.3561:3595]()
    our @EXPORT = qw(getBuild error);
    [5.3561]
    [5.3595]
    our @EXPORT = qw(getBuild error notFound);
  • edit in src/Hydra/lib/Hydra/Helper/CatalystUtils.pm at line 24
    [5.3787]
    [5.3787]
    sub notFound {
    my ($c, $msg) = @_;
    $c->response->status(404);
    error($c, $msg);
    }
  • replacement in src/Hydra/lib/Hydra/View/NixClosure.pm at line 8
    [6.847][6.847:874]()
    my ( $self, $c ) = @_;
    [6.847]
    [6.874]
    my ($self, $c) = @_;
  • edit in src/Hydra/lib/Hydra/View/NixClosure.pm at line 11
    [6.939][6.939:1051]()
    $c->response->header('Content-Disposition' => 'attachment; filename=' . $c->stash->{name} . '.closure.gz');
  • replacement in src/Hydra/lib/Hydra/View/NixClosure.pm at line 12
    [6.1052][6.1052:1096]()
    my $storePath = $c->stash->{storePath};
    [6.1052]
    [6.1096]
    my @storePaths = @{$c->stash->{storePaths}};
  • replacement in src/Hydra/lib/Hydra/View/NixClosure.pm at line 14
    [6.1097][6.1097:1173]()
    open(OUTPUT, "nix-store --export `nix-store -qR $storePath` | gzip |");
    [6.1097]
    [6.1173]
    open(OUTPUT, "nix-store --export `nix-store -qR @storePaths` | gzip |");
  • replacement in src/Hydra/lib/Hydra/View/NixManifest.pm at line 19
    [6.639][6.639:683]()
    my $storePath = $c->stash->{storePath};
    [6.639]
    [6.683]
    my @storePaths = @{$c->stash->{storePaths}};
  • replacement in src/Hydra/lib/Hydra/View/NixManifest.pm at line 23
    [6.744][6.744:880]()
    my @paths = split '\n', `nix-store --query --requisites $storePath`
    or die "cannot query dependencies of `$storePath': $?";
    [6.744]
    [6.880]
    my @paths = split '\n', `nix-store --query --requisites @storePaths`
    or die "cannot query dependencies of path(s) @storePaths: $?";
  • replacement in src/Hydra/root/product-list.tt at line 46
    [6.2124][6.433:489](),[6.3296][6.433:489]()
    <a href="[% c.uri_for('/closure' build.id) %]">
    [6.2124]
    [6.3370]
    [% filename = "${build.nixname}.closure.gz" %]
    [% uri = c.uri_for('/build' build.id 'nix' 'closure' filename ) %]
    <a href="[% uri %]">
  • replacement in src/Hydra/root/product-list.tt at line 60
    [6.3786][6.2363:2463]()
    <pre>$ gunzip &lt; [% HTML.escape(build.nixname) %].closure.gz | nix-store --import</pre>
    [6.3786]
    [6.3883]
    <pre>$ gunzip &lt; [% filename %] | nix-store --import</pre>
  • replacement in src/Hydra/root/product-list.tt at line 64
    [6.3937][6.490:585]()
    <pre>$ curl [% c.uri_for('/closure' build.id) %] | gunzip | nix-store --import</pre>
    [6.3937]
    [6.4050]
    <pre>$ curl [% uri %] | gunzip | nix-store --import</pre>