* Unify exportReferencesGraph and exportBuildReferencesGraph, and make

sure that it works as expected when you pass it a derivation.  That
  is, we have to make sure that all build-time dependencies are built,
  and that they are all in the input closure (otherwise remote builds
  might fail, for example).  This is ensured at instantiation time by
  adding all derivations and their sources to inputDrvs and inputSrcs.
This commit is contained in:
Eelco Dolstra 2009-03-18 17:36:42 +00:00
parent e530e0a350
commit 2897286487
4 changed files with 39 additions and 66 deletions

View file

@ -140,11 +140,7 @@ while (scalar @tmp > 0) {
my @tmp2 = @tmp[0..$n - 1]; my @tmp2 = @tmp[0..$n - 1];
@tmp = @tmp[$n..scalar @tmp - 1]; @tmp = @tmp[$n..scalar @tmp - 1];
# Note: we disable build hooks because of the impure path my $pid = open(READ, "$binDir/nix-store --realise @tmp2|")
# reference (see above). Even if that is fixed, using a hook
# probably wouldn't make that much sense; pumping lots of data
# around just to compress them won't gain that much.
my $pid = open(READ, "$binDir/nix-store --no-build-hook --realise @tmp2|")
or die "cannot run nix-store"; or die "cannot run nix-store";
while (<READ>) { while (<READ>) {
chomp; chomp;

View file

@ -399,16 +399,29 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
/* Everything in the context of the strings in the derivation /* Everything in the context of the strings in the derivation
attributes should be added as dependencies of the resulting attributes should be added as dependencies of the resulting
derivation. */ derivation. */
for (PathSet::iterator i = context.begin(); i != context.end(); ++i) { foreach (PathSet::iterator, i, context) {
Path path = *i; Path path = *i;
bool buildDrv = true;
/* Paths marked with `=' denote that the path of a derivation
is explicitly passed to the builder. Since that allows the
builder to gain access to every path in the dependency
graph of the derivation (including all outputs), all paths
in the graph must be added to this derivation's list of
inputs to ensure that they are available when the builder
runs. */
if (path.at(0) == '=') { if (path.at(0) == '=') {
buildDrv = false;
path = string(path, 1); path = string(path, 1);
PathSet refs; computeFSClosure(path, refs);
foreach (PathSet::iterator, j, refs) {
drv.inputSrcs.insert(*j);
if (isDerivation(*j))
drv.inputDrvs[*j] = singleton<StringSet>("out");
}
} }
debug(format("derivation uses `%1%'") % path); debug(format("derivation uses `%1%'") % path);
assert(isStorePath(path)); assert(isStorePath(path));
if (buildDrv && isDerivation(path)) if (isDerivation(path))
drv.inputDrvs[path] = singleton<StringSet>("out"); drv.inputDrvs[path] = singleton<StringSet>("out");
else else
drv.inputSrcs.insert(path); drv.inputSrcs.insert(path);
@ -484,7 +497,7 @@ static Expr prim_derivationStrict(EvalState & state, const ATermVector & args)
outAttrs.set(toATerm("outPath"), outAttrs.set(toATerm("outPath"),
makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos())); makeAttrRHS(makeStr(outPath, singleton<PathSet>(drvPath)), makeNoPos()));
outAttrs.set(toATerm("drvPath"), outAttrs.set(toATerm("drvPath"),
makeAttrRHS(makeStr(drvPath, singleton<PathSet>(drvPath)), makeNoPos())); makeAttrRHS(makeStr(drvPath, singleton<PathSet>("=" + drvPath)), makeNoPos()));
return makeAttrs(outAttrs); return makeAttrs(outAttrs);
} }
@ -541,13 +554,6 @@ static Expr prim_storePath(EvalState & state, const ATermVector & args)
Path path2 = toStorePath(path); Path path2 = toStorePath(path);
if (!store->isValidPath(path2)) if (!store->isValidPath(path2))
throw EvalError(format("store path `%1%' is not valid") % path2); throw EvalError(format("store path `%1%' is not valid") % path2);
/* If this is a derivation, mark it so it doesn't get built;
i.e. we want the dependency as a "source" dependency. This is
to make nix-push work properly (we want it to create a NAR
archive of the derivation, not build the derivation as a
side-effect). The `=' is a special marker that gets stripped
off by prim_derivationStrict. */
if (isDerivation(path2)) path2 = "=" + path2;
context.insert(path2); context.insert(path2);
return makeStr(path, context); return makeStr(path, context);
} }

View file

@ -935,8 +935,6 @@ void DerivationGoal::inputsRealised()
/* Second, the input sources. */ /* Second, the input sources. */
foreach (PathSet::iterator, i, drv.inputSrcs) foreach (PathSet::iterator, i, drv.inputSrcs)
computeFSClosure(*i, inputPaths); computeFSClosure(*i, inputPaths);
/* !!! if `*i' is a derivation, then add the closure of every
output in the dependency graph to `inputPaths'. */
debug(format("added input paths %1%") % showPaths(inputPaths)); debug(format("added input paths %1%") % showPaths(inputPaths));
@ -1534,55 +1532,27 @@ void DerivationGoal::startBuilder()
throw BuildError(format("`exportReferencesGraph' contains an invalid path `%1%'") throw BuildError(format("`exportReferencesGraph' contains an invalid path `%1%'")
% storePath); % storePath);
/* Write closure info to `fileName'. */ /* If there are derivations in the graph, then include their
PathSet refs; outputs as well. This is useful if you want to do things
computeFSClosure(storePath, refs); like passing all build-time dependencies of some path to a
/* !!! in secure Nix, the writing should be done on the derivation that builds a NixOS DVD image. */
build uid for security (maybe). */ PathSet paths, paths2;
writeStringToFile(tmpDir + "/" + fileName, computeFSClosure(storePath, paths);
makeValidityRegistration(refs, false, false)); paths2 = paths;
}
// The same for derivations foreach (PathSet::iterator, j, paths2) {
// !!! urgh, cut&paste duplication if (isDerivation(*j)) {
s = drv.env["exportBuildReferencesGraph"]; Derivation drv = derivationFromPath(*j);
ss = tokenizeString(s); foreach (DerivationOutputs::iterator, k, drv.outputs)
if (ss.size() % 2 != 0) computeFSClosure(k->second.path, paths);
throw BuildError(format("odd number of tokens in `exportBuildReferencesGraph': `%1%'") % s); }
for (Strings::iterator i = ss.begin(); i != ss.end(); ) { }
string fileName = *i++;
checkStoreName(fileName); /* !!! abuse of this function */
/* Check that the store path is valid. */
Path storePath = *i++;
if (!isInStore(storePath))
throw BuildError(format("`exportBuildReferencesGraph' contains a non-store path `%1%'")
% storePath);
storePath = toStorePath(storePath);
if (!worker.store.isValidPath(storePath))
throw BuildError(format("`exportBuildReferencesGraph' contains an invalid path `%1%'")
% storePath);
/* Write closure info to `fileName'. */ /* Write closure info to `fileName'. */
PathSet refs1,refs;
computeFSClosure(storePath, refs1);
for (PathSet::iterator j = refs1.begin(); j != refs1.end() ; j++) {
refs.insert (*j);
if (isDerivation (*j)) {
Derivation deriv = derivationFromPath (*j);
for (DerivationOutputs::iterator k=deriv.outputs.begin();
k != deriv.outputs.end(); k++) {
refs.insert(k->second.path);
}
}
}
/* !!! in secure Nix, the writing should be done on the
build uid for security (maybe). */
writeStringToFile(tmpDir + "/" + fileName, writeStringToFile(tmpDir + "/" + fileName,
makeValidityRegistration(refs, false, false)); makeValidityRegistration(paths, false, false));
} }
/* If `build-users-group' is not empty, then we have to build as /* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */ one of the members of that group. */
@ -2167,7 +2137,7 @@ SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker)
SubstitutionGoal::~SubstitutionGoal() SubstitutionGoal::~SubstitutionGoal()
{ {
/* !!! Once we let substitution goals run under a build user, we /* !!! Once we let substitution goals run under a build user, we
need to do use the setuid helper just as in ~DerivationGoal(). need to use the setuid helper just as in ~DerivationGoal().
Idem for cancel. */ Idem for cancel. */
if (pid != -1) worker.childTerminated(pid); if (pid != -1) worker.childTerminated(pid);
} }

View file

@ -4,12 +4,13 @@ rec {
printRefs = printRefs =
'' ''
echo $exportReferencesGraph
while read path; do while read path; do
read drv read drv
read nrRefs read nrRefs
echo "$path has $nrRefs references" echo "$path has $nrRefs references"
echo "$path" >> $out echo "$path" >> $out
for ((n = 0; n < $nrRefs; n++)); do read ref; echo "ref $ref"; done for ((n = 0; n < $nrRefs; n++)); do read ref; echo "ref $ref"; test -e "$ref"; done
done < refs done < refs
''; '';
@ -22,7 +23,7 @@ rec {
buildGraph = mkDerivation { buildGraph = mkDerivation {
name = "dependencies"; name = "dependencies";
builder = builtins.toFile "build-graph-builder" "${printRefs}"; builder = builtins.toFile "build-graph-builder" "${printRefs}";
exportBuildReferencesGraph = ["refs" (import ./dependencies.nix).drvPath]; exportReferencesGraph = ["refs" (import ./dependencies.nix).drvPath];
}; };
} }