+
diff --git a/src/script/hydra-eval-jobset b/src/script/hydra-eval-jobset
index c6f6c275..7ed7ebe8 100755
--- a/src/script/hydra-eval-jobset
+++ b/src/script/hydra-eval-jobset
@@ -438,13 +438,17 @@ sub checkBuild {
# new build to be scheduled if the meta.maintainers field is
# changed?
if (defined $prevEval) {
+ my $pathOrDrvConstraint = defined $firstOutputPath
+ ? { path => $firstOutputPath }
+ : { drvPath => $drvPath };
+
my ($prevBuild) = $prevEval->builds->search(
# The "project" and "jobset" constraints are
# semantically unnecessary (because they're implied by
# the eval), but they give a factor 1000 speedup on
# the Nixpkgs jobset with PostgreSQL.
{ jobset_id => $jobset->get_column('id'), job => $jobName,
- name => $firstOutputName, path => $firstOutputPath },
+ name => $firstOutputName, %$pathOrDrvConstraint },
{ rows => 1, columns => ['id', 'finished'], join => ['buildoutputs'] });
if (defined $prevBuild) {
#print STDERR " already scheduled/built as build ", $prevBuild->id, "\n";
diff --git a/src/sql/hydra.sql b/src/sql/hydra.sql
index eaae6da3..e9457972 100644
--- a/src/sql/hydra.sql
+++ b/src/sql/hydra.sql
@@ -247,7 +247,7 @@ create trigger BuildBumped after update on Builds for each row
create table BuildOutputs (
build integer not null,
name text not null,
- path text not null,
+ path text,
primary key (build, name),
foreign key (build) references Builds(id) on delete cascade
);
@@ -303,7 +303,7 @@ create table BuildStepOutputs (
build integer not null,
stepnr integer not null,
name text not null,
- path text not null,
+ path text,
primary key (build, stepnr, name),
foreign key (build) references Builds(id) on delete cascade,
foreign key (build, stepnr) references BuildSteps(build, stepnr) on delete cascade
diff --git a/src/sql/upgrade-84.sql b/src/sql/upgrade-84.sql
new file mode 100644
index 00000000..bf142b30
--- /dev/null
+++ b/src/sql/upgrade-84.sql
@@ -0,0 +1,4 @@
+-- CA derivations do not have statically known output paths. The values
+-- are only filled in after the build runs.
+ALTER TABLE BuildStepOutputs ALTER COLUMN path DROP NOT NULL;
+ALTER TABLE BuildOutputs ALTER COLUMN path DROP NOT NULL;
diff --git a/t/content-addressed/basic.t b/t/content-addressed/basic.t
new file mode 100644
index 00000000..6597e727
--- /dev/null
+++ b/t/content-addressed/basic.t
@@ -0,0 +1,61 @@
+use feature 'unicode_strings';
+use strict;
+use warnings;
+use Setup;
+
+my %ctx = test_init(
+ nix_config => qq|
+ experimental-features = ca-derivations
+ |,
+);
+
+require Hydra::Schema;
+require Hydra::Model::DB;
+
+use JSON::MaybeXS;
+
+use HTTP::Request::Common;
+use Test2::V0;
+require Catalyst::Test;
+Catalyst::Test->import('Hydra');
+
+my $db = Hydra::Model::DB->new;
+hydra_setup($db);
+
+my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
+
+my $jobset = createBaseJobset("content-addressed", "content-addressed.nix", $ctx{jobsdir});
+
+ok(evalSucceeds($jobset), "Evaluating jobs/content-addressed.nix should exit with return code 0");
+is(nrQueuedBuildsForJobset($jobset), 5, "Evaluating jobs/content-addressed.nix should result in 4 builds");
+
+for my $build (queuedBuildsForJobset($jobset)) {
+ ok(runBuild($build), "Build '".$build->job."' from jobs/content-addressed.nix should exit with code 0");
+ my $newbuild = $db->resultset('Builds')->find($build->id);
+ is($newbuild->finished, 1, "Build '".$build->job."' from jobs/content-addressed.nix should be finished.");
+ my $expected = $build->job eq "fails" ? 1 : $build->job =~ /with_failed/ ? 6 : 0;
+ is($newbuild->buildstatus, $expected, "Build '".$build->job."' from jobs/content-addressed.nix should have buildstatus $expected.");
+
+ my $response = request("/build/".$build->id);
+ ok($response->is_success, "The 'build' page for build '".$build->job."' should load properly");
+
+ if ($newbuild->buildstatus == 0) {
+ my $buildOutputs = $newbuild->buildoutputs;
+ for my $output ($newbuild->buildoutputs) {
+ # XXX: This hardcodes /nix/store/.
+ # It's fine because in practice the nix store for the tests will be of
+ # the form `/some/thing/nix/store/`, but it would be cleaner if there
+ # was a way to query Nix for its store dir?
+ like(
+ $output->path, qr|/nix/store/|,
+ "Output '".$output->name."' of build '".$build->job."' should be a valid store path"
+ );
+ }
+ }
+
+}
+
+isnt(<$ctx{deststoredir}/realisations/*>, "", "The destination store should have the realisations of the built derivations registered");
+
+done_testing;
+
diff --git a/t/content-addressed/without-experimental-feature.t b/t/content-addressed/without-experimental-feature.t
new file mode 100644
index 00000000..a37d138e
--- /dev/null
+++ b/t/content-addressed/without-experimental-feature.t
@@ -0,0 +1,28 @@
+use feature 'unicode_strings';
+use strict;
+use warnings;
+use Setup;
+
+my %ctx = test_init();
+
+require Hydra::Schema;
+require Hydra::Model::DB;
+
+use JSON::MaybeXS;
+
+use HTTP::Request::Common;
+use Test2::V0;
+require Catalyst::Test;
+Catalyst::Test->import('Hydra');
+
+my $db = Hydra::Model::DB->new;
+hydra_setup($db);
+
+my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
+
+my $jobset = createBaseJobset("content-addressed", "content-addressed.nix", $ctx{jobsdir});
+
+ok(evalSucceeds($jobset), "Evaluating jobs/content-addressed.nix without the experimental feature should exit with return code 0");
+is(nrQueuedBuildsForJobset($jobset), 0, "Evaluating jobs/content-addressed.nix without the experimental Nix feature should result in 0 build");
+
+done_testing;
diff --git a/t/jobs/config.nix.in b/t/jobs/config.nix.in
index 51b6c06f..41776341 100644
--- a/t/jobs/config.nix.in
+++ b/t/jobs/config.nix.in
@@ -6,4 +6,9 @@ rec {
system = builtins.currentSystem;
PATH = path;
} // args);
+ mkContentAddressedDerivation = args: mkDerivation ({
+ __contentAddressed = true;
+ outputHashMode = "recursive";
+ outputHashAlgo = "sha256";
+ } // args);
}
diff --git a/t/jobs/content-addressed.nix b/t/jobs/content-addressed.nix
new file mode 100644
index 00000000..65496df5
--- /dev/null
+++ b/t/jobs/content-addressed.nix
@@ -0,0 +1,35 @@
+let cfg = import ./config.nix; in
+rec {
+ empty_dir =
+ cfg.mkContentAddressedDerivation {
+ name = "empty-dir";
+ builder = ./empty-dir-builder.sh;
+ };
+
+ fails =
+ cfg.mkContentAddressedDerivation {
+ name = "fails";
+ builder = ./fail.sh;
+ };
+
+ succeed_with_failed =
+ cfg.mkContentAddressedDerivation {
+ name = "succeed-with-failed";
+ builder = ./succeed-with-failed.sh;
+ };
+
+ caDependingOnCA =
+ cfg.mkContentAddressedDerivation {
+ name = "ca-depending-on-ca";
+ builder = ./dir-with-file-builder.sh;
+ FOO = empty_dir;
+ };
+
+ nonCaDependingOnCA =
+ cfg.mkDerivation {
+ name = "non-ca-depending-on-ca";
+ builder = ./dir-with-file-builder.sh;
+ FOO = empty_dir;
+ };
+}
+
diff --git a/t/jobs/dir-with-file-builder.sh b/t/jobs/dir-with-file-builder.sh
new file mode 100755
index 00000000..8592a1e8
--- /dev/null
+++ b/t/jobs/dir-with-file-builder.sh
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+mkdir $out
+echo foo > $out/a-file
diff --git a/t/jobs/empty-dir-builder.sh b/t/jobs/empty-dir-builder.sh
index 949216e0..addc7ef6 100755
--- a/t/jobs/empty-dir-builder.sh
+++ b/t/jobs/empty-dir-builder.sh
@@ -1,6 +1,3 @@
#! /bin/sh
-# Workaround for https://github.com/NixOS/nix/pull/6051
-echo "some output"
-
mkdir $out
diff --git a/t/lib/HydraTestContext.pm b/t/lib/HydraTestContext.pm
index a22c3df1..e1a5b226 100644
--- a/t/lib/HydraTestContext.pm
+++ b/t/lib/HydraTestContext.pm
@@ -39,6 +39,8 @@ use Hydra::Helper::Exec;
sub new {
my ($class, %opts) = @_;
+ my $deststoredir;
+
# Cleanup will be managed by yath. By the default it will be cleaned
# up, but can be kept to aid in debugging test failures.
my $dir = File::Temp->newdir(CLEANUP => 0);
@@ -55,6 +57,7 @@ sub new {
my $hydra_config = $opts{'hydra_config'} || "";
$hydra_config = "queue_runner_metrics_address = 127.0.0.1:0\n" . $hydra_config;
if ($opts{'use_external_destination_store'} // 1) {
+ $deststoredir = "$dir/nix/dest-store";
$hydra_config = "store_uri = file://$dir/nix/dest-store\n" . $hydra_config;
}
@@ -81,7 +84,8 @@ sub new {
nix_state_dir => $nix_state_dir,
nix_log_dir => $nix_log_dir,
testdir => abs_path(dirname(__FILE__) . "/.."),
- jobsdir => abs_path(dirname(__FILE__) . "/../jobs")
+ jobsdir => abs_path(dirname(__FILE__) . "/../jobs"),
+ deststoredir => $deststoredir,
}, $class;
if ($opts{'before_init'}) {
diff --git a/t/queue-runner/notifications.t b/t/queue-runner/notifications.t
index 1966cde1..d0e72409 100644
--- a/t/queue-runner/notifications.t
+++ b/t/queue-runner/notifications.t
@@ -8,7 +8,7 @@ my $binarycachedir = File::Temp->newdir();
my $ctx = test_context(
nix_config => qq|
- experimental-features = nix-command
+ experimental-features = nix-command ca-derivations
substituters = file://${binarycachedir}?trusted=1
|,
hydra_config => q|