Fix exportReferencesGraph in the structured attrs case

This commit is contained in:
Eelco Dolstra 2017-10-25 14:08:29 +02:00
parent 2d5b1b24bf
commit 3395e3bbc4
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
2 changed files with 87 additions and 69 deletions

View file

@ -914,9 +914,6 @@ private:
/* Make a file owned by the builder. */
void chownToBuilder(const Path & path);
/* Handle the exportReferencesGraph attribute. */
void doExportReferencesGraph();
/* Run the builder's process. */
void runChild();
@ -1745,6 +1742,37 @@ int childEntry(void * arg)
}
PathSet exportReferences(Store & store, Path storePath)
{
/* Check that the store path is valid. */
if (!store.isInStore(storePath))
throw BuildError(format("'exportReferencesGraph' contains a non-store path '%1%'")
% storePath);
storePath = store.toStorePath(storePath);
if (!store.isValidPath(storePath))
throw BuildError(format("'exportReferencesGraph' contains an invalid path '%1%'")
% storePath);
/* If there are derivations in the graph, then include their
outputs as well. This is useful if you want to do things
like passing all build-time dependencies of some path to a
derivation that builds a NixOS DVD image. */
PathSet paths, paths2;
store.computeFSClosure(storePath, paths);
paths2 = paths;
for (auto & j : paths2) {
if (isDerivation(j)) {
Derivation drv = store.derivationFromPath(j);
for (auto & k : drv.outputs)
store.computeFSClosure(k.second.path, paths);
}
}
return paths;
}
void DerivationGoal::startBuilder()
{
/* Right platform? */
@ -1820,7 +1848,29 @@ void DerivationGoal::startBuilder()
writeStructuredAttrs();
/* Handle exportReferencesGraph(), if set. */
doExportReferencesGraph();
if (!drv->env.count("__json")) {
/* The `exportReferencesGraph' feature allows the references graph
to be passed to a builder. This attribute should be a list of
pairs [name1 path1 name2 path2 ...]. The references graph of
each `pathN' will be stored in a text file `nameN' in the
temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver
fields are left empty. */
string s = get(drv->env, "exportReferencesGraph");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError(format("odd number of tokens in 'exportReferencesGraph': '%1%'") % s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
string fileName = *i++;
checkStoreName(fileName); /* !!! abuse of this function */
Path storePath = *i++;
/* Write closure info to <fileName>. */
writeFile(tmpDir + "/" + fileName,
worker.store.makeValidityRegistration(
exportReferences(worker.store, storePath), false, false));
}
}
if (useChroot) {
@ -2309,6 +2359,20 @@ void DerivationGoal::writeStructuredAttrs()
outputs[i.first] = rewriteStrings(i.second.path, inputRewrites);
json["outputs"] = outputs;
/* Handle exportReferencesGraph. */
auto e = json.find("exportReferencesGraph");
if (e != json.end() && e->is_object()) {
for (auto i = e->begin(); i != e->end(); ++i) {
std::ostringstream str;
{
JSONPlaceholder jsonRoot(str, true);
worker.store.pathInfoToJSON(jsonRoot,
exportReferences(worker.store, i->get<std::string>()), false, true);
}
json[i.key()] = nlohmann::json::parse(str.str()); // urgh
}
}
writeFile(tmpDir + "/.attrs.json", json.dump());
/* As a convenience to bash scripts, write a shell file that
@ -2393,71 +2457,6 @@ void DerivationGoal::chownToBuilder(const Path & path)
}
void DerivationGoal::doExportReferencesGraph()
{
/* The `exportReferencesGraph' feature allows the references graph
to be passed to a builder. This attribute should be a list of
pairs [name1 path1 name2 path2 ...]. The references graph of
each `pathN' will be stored in a text file `nameN' in the
temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver
fields are left empty. */
string s = get(drv->env, "exportReferencesGraph");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError(format("odd number of tokens in 'exportReferencesGraph': '%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 (!worker.store.isInStore(storePath))
throw BuildError(format("'exportReferencesGraph' contains a non-store path '%1%'")
% storePath);
storePath = worker.store.toStorePath(storePath);
if (!worker.store.isValidPath(storePath))
throw BuildError(format("'exportReferencesGraph' contains an invalid path '%1%'")
% storePath);
/* If there are derivations in the graph, then include their
outputs as well. This is useful if you want to do things
like passing all build-time dependencies of some path to a
derivation that builds a NixOS DVD image. */
PathSet paths, paths2;
worker.store.computeFSClosure(storePath, paths);
paths2 = paths;
for (auto & j : paths2) {
if (isDerivation(j)) {
Derivation drv = worker.store.derivationFromPath(j);
for (auto & k : drv.outputs)
worker.store.computeFSClosure(k.second.path, paths);
}
}
if (!drv->env.count("__json")) {
/* Write closure info to <fileName>. */
writeFile(tmpDir + "/" + fileName,
worker.store.makeValidityRegistration(paths, false, false));
} else {
/* Write a more comprehensive JSON serialisation to
<fileName>. */
std::ostringstream str;
{
JSONPlaceholder jsonRoot(str, true);
worker.store.pathInfoToJSON(jsonRoot, paths, false, true);
}
writeFile(tmpDir + "/" + fileName, str.str());
}
}
}
void setupSeccomp()
{
#if __linux__

View file

@ -1,5 +1,16 @@
with import ./config.nix;
let
dep = mkDerivation {
name = "dep";
buildCommand = ''
mkdir $out; echo bla > $out/bla
'';
};
in
mkDerivation {
name = "structured";
@ -21,6 +32,12 @@ mkDerivation {
mkdir ''${outputs[out]}
echo bar > $dest
json=$(cat .attrs.json)
[[ $json =~ '"narHash":"sha256:1r7yc43zqnzl5b0als5vnyp649gk17i37s7mj00xr8kc47rjcybk"' ]]
[[ $json =~ '"narSize":288' ]]
[[ $json =~ '"closureSize":288' ]]
[[ $json =~ '"references":[]' ]]
'';
buildInputs = [ "a" "b" "c" 123 "'" "\"" null ];
@ -44,4 +61,6 @@ mkDerivation {
"foo bar" = "BAD";
"1foobar" = "BAD";
"foo$" = "BAD";
exportReferencesGraph.refs = dep;
}