Support building a derivation if some outputs are already valid

This handles the chroot and build hook cases, which are easy.
Supporting the non-chroot-build case will require more work (hash
rewriting!).

Issue #21.
This commit is contained in:
Eelco Dolstra 2012-09-11 16:59:59 -04:00
parent 295027f533
commit a2785b7391
2 changed files with 28 additions and 23 deletions

View file

@ -6,6 +6,7 @@ use IO::Handle;
use Nix::Config; use Nix::Config;
use Nix::SSH qw/sshOpts openSSHConnection/; use Nix::SSH qw/sshOpts openSSHConnection/;
use Nix::CopyClosure; use Nix::CopyClosure;
use Nix::Store;
no warnings('once'); no warnings('once');
@ -286,7 +287,7 @@ if (system("exec ssh $hostName @sshOpts '(read; kill -INT -\$\$) <&0 & nix-store
foreach my $output (@outputs) { foreach my $output (@outputs) {
my $maybeSignRemote = ""; my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0; $maybeSignRemote = "--sign" if $UID != 0;
next if isValidPath($output);
system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" . system("exec ssh $hostName @sshOpts 'nix-store --export $maybeSignRemote $output'" .
"| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0 "| NIX_HELD_LOCKS=$output @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?"; or die "cannot copy $output from $hostName: $?";

View file

@ -756,6 +756,9 @@ private:
/* Referenceable paths (i.e., input and output paths). */ /* Referenceable paths (i.e., input and output paths). */
PathSet allPaths; PathSet allPaths;
/* Outputs that are already valid. */
PathSet validPaths;
/* User selected for running the builder. */ /* User selected for running the builder. */
UserLock buildUser; UserLock buildUser;
@ -1141,7 +1144,7 @@ void DerivationGoal::tryToBuild()
omitted, but that would be less efficient.) Note that since we omitted, but that would be less efficient.) Note that since we
now hold the locks on the output paths, no other process can now hold the locks on the output paths, no other process can
build this derivation, so no further checks are necessary. */ build this derivation, so no further checks are necessary. */
PathSet validPaths = checkPathValidity(true); validPaths = checkPathValidity(true);
if (validPaths.size() == drv.outputs.size()) { if (validPaths.size() == drv.outputs.size()) {
debug(format("skipping build of derivation `%1%', someone beat us to it") debug(format("skipping build of derivation `%1%', someone beat us to it")
% drvPath); % drvPath);
@ -1150,23 +1153,17 @@ void DerivationGoal::tryToBuild()
return; return;
} }
if (validPaths.size() > 0) printMsg(lvlError, format("BLOCKERS: %1%") % showPaths(validPaths));
/* !!! fix this; try to delete valid paths */
throw Error(
format("derivation `%1%' is blocked by its output paths")
% drvPath);
/* If any of the outputs already exist but are not valid, delete /* If any of the outputs already exist but are not valid, delete
them. */ them. */
foreach (DerivationOutputs::iterator, i, drv.outputs) { foreach (DerivationOutputs::iterator, i, drv.outputs) {
Path path = i->second.path; Path path = i->second.path;
if (worker.store.isValidPath(path)) if (worker.store.isValidPath(path)) continue;
throw Error(format("obstructed build: path `%1%' exists") % path); if (!pathExists(path)) continue;
if (pathExists(path)) {
debug(format("removing unregistered path `%1%'") % path); debug(format("removing unregistered path `%1%'") % path);
deletePathWrapped(path); deletePathWrapped(path);
} }
}
/* Check again whether any output previously failed to build, /* Check again whether any output previously failed to build,
because some other process may have tried and failed before we because some other process may have tried and failed before we
@ -1283,6 +1280,10 @@ void DerivationGoal::buildDone()
Path path = i->second.path; Path path = i->second.path;
if (useChroot && pathExists(chrootRootDir + path)) { if (useChroot && pathExists(chrootRootDir + path)) {
/* Move output paths from the chroot to the Nix store.
If the output was already valid, just skip
(discard) it. */
if (validPaths.find(path) != validPaths.end()) continue;
if (rename((chrootRootDir + path).c_str(), path.c_str()) == -1) if (rename((chrootRootDir + path).c_str(), path.c_str()) == -1)
throw SysError(format("moving build output `%1%' from the chroot to the Nix store") % path); throw SysError(format("moving build output `%1%' from the chroot to the Nix store") % path);
} }
@ -1747,6 +1748,9 @@ void DerivationGoal::startBuilder()
#else #else
throw Error("chroot builds are not supported on this platform"); throw Error("chroot builds are not supported on this platform");
#endif #endif
} else { // !useChroot
if (validPaths.size() > 0)
throw Error(format("derivation `%1%' is blocked by its output paths %2%") % drvPath % showPaths(validPaths));
} }