From 7343e6c8ae6d18f38f42a0714212ca5deb957c39 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 30 May 2010 20:29:56 +0000 Subject: [PATCH 1/8] * Remove an accidentally committed debug statement. --- src/nix-env/user-env.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 72e13fceb..0a619f698 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -106,8 +106,6 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, Path manifestFile = store->addTextToStore("env-manifest.nix", (format("%1%") % manifest).str(), references); - printMsg(lvlError, manifestFile); - /* Get the environment builder expression. */ Value envBuilder; state.eval(parseExprFromFile(state, nixDataDir + "/nix/corepkgs/buildenv"), envBuilder); From da52f8bea0620cd55e10a8ec90306fa169f2d14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Mon, 31 May 2010 16:36:20 +0000 Subject: [PATCH 2/8] Comment out dead code in `nix-store'. * src/nix-store/dotgraph.cc (pathLabel): Move within #if 0 section. --- src/nix-store/dotgraph.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc index 83df9e9cd..72146eb68 100644 --- a/src/nix-store/dotgraph.cc +++ b/src/nix-store/dotgraph.cc @@ -52,13 +52,13 @@ static string symbolicName(const string & path) } +#if 0 string pathLabel(const Path & nePath, const string & elemPath) { return (string) nePath + "-" + elemPath; } -#if 0 void printClosure(const Path & nePath, const StoreExpr & fs) { PathSet workList(fs.closure.roots); From 8bcdd36f10c5adfd312493c822c95c6fa5fbd110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Mon, 31 May 2010 16:36:24 +0000 Subject: [PATCH 3/8] Add XML output to `nix-store'. * src/nix-store/Makefile.am (nix_store_SOURCES): Add `xmlgraph.cc' and `xmlgraph.hh'. * src/nix-store/help.txt (Operations): Document `--xml'. * src/nix-store/nix-store.cc (opQuery): Handle `--xml'. * src/nix-store/xmlgraph.cc, src/nix-store/xmlgraph.hh: New files. --- src/nix-store/Makefile.am | 5 ++- src/nix-store/help.txt | 1 + src/nix-store/nix-store.cc | 14 ++++++-- src/nix-store/xmlgraph.cc | 71 ++++++++++++++++++++++++++++++++++++++ src/nix-store/xmlgraph.hh | 12 +++++++ 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 src/nix-store/xmlgraph.cc create mode 100644 src/nix-store/xmlgraph.hh diff --git a/src/nix-store/Makefile.am b/src/nix-store/Makefile.am index 9a439dd92..b6dd37a61 100644 --- a/src/nix-store/Makefile.am +++ b/src/nix-store/Makefile.am @@ -1,6 +1,9 @@ bin_PROGRAMS = nix-store -nix_store_SOURCES = nix-store.cc dotgraph.cc dotgraph.hh help.txt +nix_store_SOURCES = \ + nix-store.cc dotgraph.cc dotgraph.hh help.txt \ + xmlgraph.cc xmlgraph.hh + nix_store_LDADD = ../libmain/libmain.la ../libstore/libstore.la ../libutil/libutil.la \ ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ diff --git a/src/nix-store/help.txt b/src/nix-store/help.txt index 7576e3ef5..071934b20 100644 --- a/src/nix-store/help.txt +++ b/src/nix-store/help.txt @@ -39,6 +39,7 @@ Query flags: --referrers-closure: print all paths (in)directly refering to the path --tree: print a tree showing the dependency graph of the path --graph: print a dot graph rooted at given path + --xml: emit an XML representation of the graph rooted at the given path --hash: print the SHA-256 hash of the contents of the path --roots: print the garbage collector roots that point to the path diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 22effc65d..e22ef7efc 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -6,6 +6,7 @@ #include "archive.hh" #include "shared.hh" #include "dotgraph.hh" +#include "xmlgraph.hh" #include "local-store.hh" #include "util.hh" #include "help.txt.hh" @@ -226,7 +227,7 @@ static void opQuery(Strings opFlags, Strings opArgs) { enum { qOutputs, qRequisites, qReferences, qReferrers , qReferrersClosure, qDeriver, qBinding, qHash - , qTree, qGraph, qResolve, qRoots } query = qOutputs; + , qTree, qGraph, qXml, qResolve, qRoots } query = qOutputs; bool useOutput = false; bool includeOutputs = false; bool forceRealise = false; @@ -249,6 +250,7 @@ static void opQuery(Strings opFlags, Strings opArgs) else if (*i == "--hash") query = qHash; else if (*i == "--tree") query = qTree; else if (*i == "--graph") query = qGraph; + else if (*i == "--xml") query = qXml; else if (*i == "--resolve") query = qResolve; else if (*i == "--roots") query = qRoots; else if (*i == "--use-output" || *i == "-u") useOutput = true; @@ -327,7 +329,15 @@ static void opQuery(Strings opFlags, Strings opArgs) PathSet roots; foreach (Strings::iterator, i, opArgs) roots.insert(maybeUseOutput(followLinksToStorePath(*i), useOutput, forceRealise)); - printDotGraph(roots); + printDotGraph(roots); + break; + } + + case qXml: { + PathSet roots; + foreach (Strings::iterator, i, opArgs) + roots.insert(maybeUseOutput(followLinksToStorePath(*i), useOutput, forceRealise)); + printXmlGraph(roots); break; } diff --git a/src/nix-store/xmlgraph.cc b/src/nix-store/xmlgraph.cc new file mode 100644 index 000000000..1b3ad3d28 --- /dev/null +++ b/src/nix-store/xmlgraph.cc @@ -0,0 +1,71 @@ +#include "xmlgraph.hh" +#include "util.hh" +#include "store-api.hh" + +#include + + +using std::cout; + +namespace nix { + + +static inline const string & xmlQuote(const string & s) +{ + // Luckily, store paths shouldn't contain any character that needs to be + // quoted. + return s; +} + + +static string makeEdge(const string & src, const string & dst) +{ + format f = format(" \n") + % xmlQuote(src) % xmlQuote(dst); + return f.str(); +} + + +static string makeNode(const string & id) +{ + format f = format(" \n") % xmlQuote(id); + return f.str(); +} + + +void printXmlGraph(const PathSet & roots) +{ + PathSet workList(roots); + PathSet doneSet; + + cout << "\n" + << "\n"; + + while (!workList.empty()) { + Path path = *(workList.begin()); + workList.erase(path); + + if (doneSet.find(path) != doneSet.end()) continue; + doneSet.insert(path); + + cout << makeNode(path); + + PathSet references; + store->queryReferences(path, references); + + for (PathSet::iterator i = references.begin(); + i != references.end(); ++i) + { + if (*i != path) { + workList.insert(*i); + cout << makeEdge(*i, path); + } + } + + } + + cout << "\n"; +} + + +} diff --git a/src/nix-store/xmlgraph.hh b/src/nix-store/xmlgraph.hh new file mode 100644 index 000000000..2f9908c43 --- /dev/null +++ b/src/nix-store/xmlgraph.hh @@ -0,0 +1,12 @@ +#ifndef __XMLGRAPH_H +#define __XMLGRAPH_H + +#include "types.hh" + +namespace nix { + +void printXmlGraph(const PathSet & roots); + +} + +#endif /* !__XMLGRAPH_H */ From 89865da76d87292e5bc61f324b1ac892d40236e7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 Jun 2010 11:19:32 +0000 Subject: [PATCH 4/8] * Turn build errors during evaluation into EvalErrors. --- src/libexpr/nixexpr.hh | 1 + src/libexpr/primops.cc | 6 +++++- src/libstore/build.cc | 2 +- src/libstore/store-api.hh | 2 -- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 1c72441b2..b1043a326 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -15,6 +15,7 @@ MakeError(AssertionError, EvalError) MakeError(ThrownError, AssertionError) MakeError(Abort, EvalError) MakeError(TypeError, EvalError) +MakeError(ImportError, EvalError) // error building an imported derivation /* Position objects. */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 9d36fb6a0..42c858611 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -37,7 +37,11 @@ static void prim_import(EvalState & state, Value * * args, Value & v) throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") % path % *i); if (isDerivation(*i)) - store->buildDerivations(singleton(*i)); + try { + store->buildDerivations(singleton(*i)); + } catch (Error & e) { + throw ImportError(e.msg()); + } } state.evalFile(path, v); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 412640670..f901c1f7d 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -267,7 +267,7 @@ public: MakeError(SubstError, Error) -MakeError(BuildError, Error) /* denoted a permanent build failure */ +MakeError(BuildError, Error) /* denotes a permanent build failure */ ////////////////////////////////////////////////////////////////////// diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 8506d47e3..0590f448c 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -16,8 +16,6 @@ namespace nix { typedef std::map Roots; - - struct GCOptions { /* Garbage collector operation: From 1ab67cf437704f51f514e2ab7856e3c87f3c88b1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 2 Jun 2010 09:43:04 +0000 Subject: [PATCH 5/8] --- src/libexpr/eval.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 1ee6c5a7f..f95df5e4d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -59,6 +59,7 @@ std::ostream & operator << (std::ostream & str, const Value & v) str << "]"; break; case tThunk: + case tApp: case tCopy: str << ""; break; From 07ca66cf242eef3c7a6396e9353e48037034498b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Jun 2010 13:56:11 +0000 Subject: [PATCH 6/8] * Applied a patch from David Brown to prevent `nix-store --optimise' from failing on rename() on BtrFS. --- src/libstore/optimise-store.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index d15049201..3ed54e24d 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -119,9 +119,23 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath, } /* Atomically replace the old file with the new hard link. */ - if (rename(tempLink.c_str(), path.c_str()) == -1) + if (rename(tempLink.c_str(), path.c_str()) == -1) { + if (errno == EMLINK) { + /* Some filesystems generate too many links on the + rename, rather than on the original link. + (Probably it temporarily increases the st_nlink + field before decreasing it again.) */ + printMsg(lvlInfo, format("`%1%' has maximum number of links") % prevPath.first); + hashToPath[hash] = std::pair(path, st.st_ino); + + /* Unlink the temp link. */ + if (unlink(tempLink.c_str()) == -1) + printMsg(lvlError, format("unable to unlink `%1%'") % tempLink); + return; + } throw SysError(format("cannot rename `%1%' to `%2%'") % tempLink % path); + } } else printMsg(lvlTalkative, format("would link `%1%' to `%2%'") % path % prevPath.first); From f16fe2af8d59fef156c29077a240a832d3e60ef2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 10 Jun 2010 10:29:50 +0000 Subject: [PATCH 7/8] * builtins.toXML: propagate the string context. This is a regression from the old ATerm-based evaluator. --- src/libexpr/eval.cc | 14 +++++++++----- src/libexpr/eval.hh | 2 ++ src/libexpr/value-to-xml.cc | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f95df5e4d..eb1d8d432 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -902,12 +902,18 @@ string EvalState::forceString(Value & v) } -string EvalState::forceString(Value & v, PathSet & context) +void copyContext(const Value & v, PathSet & context) { - string s = forceString(v); if (v.string.context) for (const char * * p = v.string.context; *p; ++p) context.insert(*p); +} + + +string EvalState::forceString(Value & v, PathSet & context) +{ + string s = forceString(v); + copyContext(v, context); return s; } @@ -938,9 +944,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, string s; if (v.type == tString) { - if (v.string.context) - for (const char * * p = v.string.context; *p; ++p) - context.insert(*p); + copyContext(v, context); return v.string.s; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 65c689a50..0cdf0b283 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -161,6 +161,8 @@ void mkString(Value & v, const char * s); void mkString(Value & v, const string & s, const PathSet & context = PathSet()); void mkPath(Value & v, const char * s); +void copyContext(const Value & v, PathSet & context); + typedef std::map DrvHashes; diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index e751fd300..8955a8a33 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -69,6 +69,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, case tString: /* !!! show the context? */ + copyContext(v, context); doc.writeEmptyElement("string", singletonAttrs("value", v.string.s)); break; From b57189174f6e11c3e9e0f7c65c08a72f689fe194 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 14 Jun 2010 08:34:48 +0000 Subject: [PATCH 8/8] * In importPath() and exportPath(), lock the temporary directory to prevent it from being deleted by the garbage collector. --- src/libstore/local-store.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 2c0aa3579..f430492fd 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -873,6 +873,8 @@ void LocalStore::exportPath(const Path & path, bool sign, writeInt(1, hashAndWriteSink); Path tmpDir = createTempDir(); + PathLocks tmpDirLock(singleton(tmpDir)); + tmpDirLock.setDeletion(true); AutoDelete delTmp(tmpDir); Path hashFile = tmpDir + "/hash"; writeFile(hashFile, printHash(hash)); @@ -922,6 +924,8 @@ Path LocalStore::importPath(bool requireSignature, Source & source) store path follows the archive data proper), and besides, we don't know yet whether the signature is valid. */ Path tmpDir = createTempDir(nixStore); + PathLocks tmpDirLock(singleton(tmpDir)); + tmpDirLock.setDeletion(true); AutoDelete delTmp(tmpDir); /* !!! could be GC'ed! */ Path unpacked = tmpDir + "/unpacked";