* Allow scheduled builds to be cancelled. They're not removed from

the database, just marked as cancelled, because otherwise the
  scheduler would just add them again.
This commit is contained in:
Eelco Dolstra 2009-03-06 12:49:01 +00:00
parent 11360c7aa8
commit dca6b943d0
3 changed files with 88 additions and 40 deletions

View file

@ -30,7 +30,7 @@ sub view_build : Chained('build') PathPart('') Args(0) {
$c->stash->{curTime} = time; $c->stash->{curTime} = time;
$c->stash->{available} = isValidPath $build->outpath; $c->stash->{available} = isValidPath $build->outpath;
$c->stash->{drvAvailable} = isValidPath $build->drvpath; $c->stash->{drvAvailable} = isValidPath $build->drvpath;
$c->stash->{flashMsg} = $c->flash->{afterRestart}; $c->stash->{flashMsg} = $c->flash->{buildMsg};
if (!$build->finished && $build->schedulingInfo->busy) { if (!$build->finished && $build->schedulingInfo->busy) {
my $logfile = $build->schedulingInfo->logfile; my $logfile = $build->schedulingInfo->logfile;
@ -156,17 +156,19 @@ sub nix : Chained('build') PathPart('nix') CaptureArgs(0) {
} }
sub restart : Chained('build') PathPart('restart') Args(0) { sub restart : Chained('build') PathPart Args(0) {
my ($self, $c) = @_; my ($self, $c) = @_;
my $build = $c->stash->{build}; my $build = $c->stash->{build};
requireProjectOwner($c, $build->project); requireProjectOwner($c, $build->project);
error($c, "This build cannot be restarted.")
unless $build->finished && $build->resultInfo->buildstatus == 3;
$c->model('DB')->schema->txn_do(sub { $c->model('DB')->schema->txn_do(sub {
error($c, "This build cannot be restarted.")
unless $build->finished &&
($build->resultInfo->buildstatus == 3 ||
$build->resultInfo->buildstatus == 4);
$build->finished(0); $build->finished(0);
$build->timestamp(time()); $build->timestamp(time());
$build->update; $build->update;
@ -181,7 +183,41 @@ sub restart : Chained('build') PathPart('restart') Args(0) {
}); });
}); });
$c->flash->{afterRestart} = "Build has been restarted."; $c->flash->{buildMsg} = "Build has been restarted.";
$c->res->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures));
}
sub cancel : Chained('build') PathPart Args(0) {
my ($self, $c) = @_;
my $build = $c->stash->{build};
requireProjectOwner($c, $build->project);
$c->model('DB')->schema->txn_do(sub {
error($c, "This build cannot be cancelled.")
if $build->finished || $build->schedulingInfo->busy;
# !!! Actually, it would be nice to be able to cancel busy
# builds as well, but we would have to send a signal or
# something to the build process.
$build->finished(1);
$build->timestamp(time());
$build->update;
$c->model('DB::BuildResultInfo')->create(
{ id => $build->id
, iscachedbuild => 0
, buildstatus => 4 # = cancelled
});
$build->schedulingInfo->delete;
});
$c->flash->{buildMsg} = "Build has been cancelled.";
$c->res->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures)); $c->res->redirect($c->uri_for($self->action_for("view_build"), $c->req->captures));
} }

View file

@ -40,12 +40,17 @@
[% ELSIF build.resultInfo.buildstatus == 2 %] [% ELSIF build.resultInfo.buildstatus == 2 %]
<img src="/static/images/failure.gif" alt="Failed" /> <img src="/static/images/failure.gif" alt="Failed" />
<span class="error">A dependency of the build failed</span> <span class="error">A dependency of the build failed</span>
[% ELSIF build.resultInfo.buildstatus == 4 %]
<img src="/static/images/failure.gif" alt="Failed" />
<span class="error">Cancelled by user</span>
[% ELSE %] [% ELSE %]
<img src="/static/images/failure.gif" alt="Failed" /> <img src="/static/images/failure.gif" alt="Failed" />
<span class="error">Build failed</span> <span class="error">Build failed</span>
(see <a href="#nix-error">below</a>) (see <a href="#nix-error">below</a>)
[% END %]
[% IF build.resultInfo.buildstatus == 3 || build.resultInfo.buildstatus == 4 %]
<form action="[% c.uri_for('/build' build.id 'restart') %]" method="post" class="inline"> <form action="[% c.uri_for('/build' build.id 'restart') %]" method="post" class="inline">
<button id="delete-project" type="submit">Restart</button> <button id="restart" type="submit">Restart</button>
</form> </form>
[% END %] [% END %]
[% ELSIF build.schedulingInfo.busy %] [% ELSIF build.schedulingInfo.busy %]
@ -53,6 +58,11 @@
since [% PROCESS renderDateTime timestamp = build.schedulingInfo.starttime %] since [% PROCESS renderDateTime timestamp = build.schedulingInfo.starttime %]
[% ELSE %] [% ELSE %]
<strong>Scheduled to be built</strong> <strong>Scheduled to be built</strong>
[% IF c.user_exists %]
<form action="[% c.uri_for('/build' build.id 'cancel') %]" method="post" class="inline">
<button id="cancel" type="submit">Cancel</button>
</form>
[% END %]
[% END %] [% END %]
</td> </td>
</tr> </tr>
@ -116,44 +126,45 @@
<th>Time added:</th> <th>Time added:</th>
<td>[% PROCESS renderDateTime timestamp = build.timestamp %]</td> <td>[% PROCESS renderDateTime timestamp = build.timestamp %]</td>
</tr> </tr>
[% IF build.finished %] [% IF build.finished && build.resultInfo.buildstatus != 4 %]
<tr>
<th>Build started:</th>
<td>[% IF build.resultInfo.starttime %][% PROCESS renderDateTime timestamp = build.resultInfo.starttime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Build finished:</th>
<td>[% IF build.resultInfo.stoptime %][% PROCESS renderDateTime timestamp = build.resultInfo.stoptime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Duration (seconds):</th>
<td>
[% IF build.resultInfo.iscachedbuild %]
<em>(cached build)</em>
[% ELSE %]
[% build.resultInfo.stoptime - build.resultInfo.starttime %]
[% END %]
</td>
</tr>
[% IF build.resultInfo.logfile %]
<tr> <tr>
<th>Logfile:</th> <th>Build started:</th>
<td>[% IF build.resultInfo.starttime %][% PROCESS renderDateTime timestamp = build.resultInfo.starttime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Build finished:</th>
<td>[% IF build.resultInfo.stoptime %][% PROCESS renderDateTime timestamp = build.resultInfo.stoptime %][% ELSE %]<em>(cached build)</em>[% END %]</td>
</tr>
<tr>
<th>Duration (seconds):</th>
<td> <td>
<a href="[% c.uri_for('/build' build.id 'log') %]"><strong>Available</strong></a> [% IF build.resultInfo.iscachedbuild %]
<em>(cached build)</em>
[% ELSE %]
[% build.resultInfo.stoptime - build.resultInfo.starttime %]
[% END %]
</td> </td>
</tr> </tr>
[% IF build.resultInfo.logfile %]
<tr>
<th>Logfile:</th>
<td>
<a href="[% c.uri_for('/build' build.id 'log') %]"><strong>Available</strong></a>
</td>
</tr>
[% END %]
[% END %] [% END %]
[% ELSE %] [% IF !build.finished %]
<tr> <tr>
<th>Priority:</th> <th>Priority:</th>
<td>[% build.schedulingInfo.priority %]</td> <td>[% build.schedulingInfo.priority %]</td>
</tr> </tr>
[% IF build.schedulingInfo.busy %] [% IF build.schedulingInfo.busy %]
<tr> <tr>
<th>Logfile:</th> <th>Logfile:</th>
<td><tt>[% build.schedulingInfo.logfile %]</tt></td> <td><tt>[% build.schedulingInfo.logfile %]</tt></td>
</tr> </tr>
[% END %] [% END %]
[% END %] [% END %]
</table> </table>

View file

@ -61,6 +61,7 @@ create table BuildResultInfo (
-- 1 = build of this derivation failed -- 1 = build of this derivation failed
-- 2 = build of some dependency failed -- 2 = build of some dependency failed
-- 3 = other failure (see errorMsg) -- 3 = other failure (see errorMsg)
-- 4 = build cancelled (removed from queue; never built)
buildStatus integer, buildStatus integer,
errorMsg text, -- error message in case of a Nix failure errorMsg text, -- error message in case of a Nix failure