diff --git a/src/libmain/Makefile.am b/src/libmain/Makefile.am index 3c28441ca..aa5f673fd 100644 --- a/src/libmain/Makefile.am +++ b/src/libmain/Makefile.am @@ -7,5 +7,6 @@ AM_CXXFLAGS = \ -DNIX_DATA_DIR=\"$(datadir)\" \ -DNIX_STATE_DIR=\"$(localstatedir)/nix\" \ -DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \ + -DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \ -DNIX_VERSION=\"$(VERSION)\" \ -I.. ${aterm_include} -I../libutil -I../libstore diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 5c994d7b4..0a6ebcd5c 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -106,6 +106,7 @@ static void initAndRun(int argc, char * * argv) nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)); nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)); nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); + nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)); /* Check that the store directory and its parent are not symlinks. */ diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 323acf265..6f09e9cb7 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -213,14 +213,9 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds) lockFile(*fd, ltRead, true); /* Read the entire file. */ - struct stat st; - if (fstat(*fd, &st) == -1) - throw SysError(format("statting `%1%'") % path); - unsigned char buf[st.st_size]; /* !!! stack space */ - readFull(*fd, buf, st.st_size); + string contents = readFile(*fd); /* Extract the roots. */ - string contents((char *) buf, st.st_size); unsigned int pos = 0, end; while ((end = contents.find((char) 0, pos)) != string::npos) { @@ -310,7 +305,9 @@ static Paths topoSort(const PathSet & paths) void collectGarbage(GCAction action, PathSet & result) { result.clear(); - + + string gcKeepOutputs = querySetting("gc-keep-outputs", "false"); + /* Acquire the global GC root. This prevents a) New roots from being added. b) Processes from creating new temporary root files. */ @@ -333,6 +330,19 @@ void collectGarbage(GCAction action, PathSet & result) for (PathSet::const_iterator i = roots.begin(); i != roots.end(); ++i) computeFSClosure(canonPath(*i), livePaths); + if (gcKeepOutputs == "true") { + /* Hmz, identical to storePathRequisites in nix-store. */ + for (PathSet::iterator i = livePaths.begin(); + i != livePaths.end(); ++i) + if (isDerivation(*i)) { + Derivation drv = derivationFromPath(*i); + for (DerivationOutputs::iterator j = drv.outputs.begin(); + j != drv.outputs.end(); ++j) + if (isValidPath(j->second.path)) + computeFSClosure(j->second.path, livePaths); + } + } + if (action == gcReturnLive) { result = livePaths; return; diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 52f2a0a0b..22820f2fe 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -1,10 +1,14 @@ #include "globals.hh" +#include + + string nixStore = "/UNINIT"; string nixDataDir = "/UNINIT"; string nixLogDir = "/UNINIT"; string nixStateDir = "/UNINIT"; string nixDBPath = "/UNINIT"; +string nixConfDir = "/UNINIT"; bool keepFailed = false; @@ -17,3 +21,49 @@ Verbosity buildVerbosity = lvlInfo; unsigned int maxBuildJobs = 1; bool readOnlyMode = false; + + +static bool settingsRead = false; + +static map settings; + + +static void readSettings() +{ + Path settingsFile = (format("%1%/%2%") % nixConfDir % "nix.conf").str(); + if (!pathExists(settingsFile)) return; + string contents = readFile(settingsFile); + + unsigned int pos = 0; + + while (pos < contents.size()) { + string line; + while (pos < contents.size() && contents[pos] != '\n') + line += contents[pos++]; + pos++; + + unsigned int hash = line.find('#'); + if (hash != string::npos) + line = string(line, 0, hash); + + if (line.find_first_not_of(" ") == string::npos) continue; + + istringstream is(line); + string name, sep, value; + is >> name >> sep >> value; + if (sep != "=" || !is) + throw Error(format("illegal configuration line `%1%'") % line); + + settings[name] = value; + }; + + settingsRead = true; +} + + +string querySetting(const string & name, const string & def) +{ + if (!settingsRead) readSettings(); + map::iterator i = settings.find(name); + return i == settings.end() ? def : i->second; +} diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index beaa0acc9..0e851fd74 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -23,6 +23,11 @@ extern string nixStateDir; /* nixDBPath is the path name of our Berkeley DB environment. */ extern string nixDBPath; +/* nixConfDir is the directory where configuration files are + stored. */ +extern string nixConfDir; + + /* Misc. global flags. */ @@ -48,4 +53,7 @@ extern unsigned int maxBuildJobs; extern bool readOnlyMode; +string querySetting(const string & name, const string & def); + + #endif /* !__GLOBALS_H */ diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 108c054b7..2fb3e9ee6 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -164,6 +164,27 @@ Strings readDirectory(const Path & path) } +string readFile(int fd) +{ + struct stat st; + if (fstat(fd, &st) == -1) + throw SysError("statting file"); + unsigned char buf[st.st_size]; /* !!! stack space */ + readFull(fd, buf, st.st_size); + + return string((char *) buf, st.st_size); +} + + +string readFile(const Path & path) +{ + AutoCloseFD fd = open(path.c_str(), O_RDONLY); + if (fd == -1) + throw SysError(format("opening file `%1%'") % path); + return readFile(fd); +} + + static void _deletePath(const Path & path) { checkInterrupt(); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index d9d5a7cdf..c7f117129 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -90,6 +90,10 @@ bool isLink(const Path & path); removed. */ Strings readDirectory(const Path & path); +/* Read the contents of a file into a string. */ +string readFile(int fd); +string readFile(const Path & path); + /* Delete a path; i.e., in the case of a directory, it is deleted recursively. Don't use this at home, kids. */ void deletePath(const Path & path);