diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-05-21 17:19:36 +0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-05-21 17:19:36 +0200 |
commit | 9f9080e2c019f188ba679a7a89284d7eaf629710 (patch) | |
tree | dac5d9672e2b4c139c2e97d7766911b62f8b069b /src | |
parent | eac5841970737b799c55ec78f6ace6d80762ff04 (diff) |
nix-store -l: Fetch build logs from the Internet
If a build log is not available locally, then ‘nix-store -l’ will now
try to download it from the servers listed in the ‘log-servers’ option
in nix.conf. For instance, if you have:
log-servers = http://hydra.nixos.org/log
then it will try to get logs from http://hydra.nixos.org/log/<base
name of the store path>. So you can do things like:
$ nix-store -l $(which xterm)
and get a log even if xterm wasn't built locally.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/globals.cc | 1 | ||||
-rw-r--r-- | src/libstore/globals.hh | 3 | ||||
-rw-r--r-- | src/libutil/util.cc | 2 | ||||
-rw-r--r-- | src/libutil/util.hh | 2 | ||||
-rw-r--r-- | src/nix-store/local.mk | 2 | ||||
-rw-r--r-- | src/nix-store/nix-store.cc | 29 |
6 files changed, 35 insertions, 4 deletions
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 739199d48..180344e33 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -147,6 +147,7 @@ void Settings::update() get(envKeepDerivations, "env-keep-derivations"); get(sshSubstituterHosts, "ssh-substituter-hosts"); get(useSshSubstituter, "use-ssh-substituter"); + get(logServers, "log-servers"); string subs = getEnv("NIX_SUBSTITUTERS", "default"); if (subs == "default") { diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 711c36529..65a6c388b 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -197,6 +197,9 @@ struct Settings { /* Whether to show a stack trace if Nix evaluation fails. */ bool showTrace; + /* A list of URL prefixes that can return Nix build logs. */ + Strings logServers; + private: SettingsMap settings, overrides; diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 846674a29..8fc78b146 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -901,7 +901,7 @@ string runProgram(Path program, bool searchPath, const Strings & args) /* Wait for the child to finish. */ int status = pid.wait(true); if (!statusOk(status)) - throw Error(format("program `%1%' %2%") + throw ExecError(format("program `%1%' %2%") % program % statusToString(status)); return result; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index ce2d77c19..1e9ffcf51 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -257,6 +257,8 @@ void killUser(uid_t uid); string runProgram(Path program, bool searchPath = false, const Strings & args = Strings()); +MakeError(ExecError, Error) + /* Close all file descriptors except stdin, stdout, stderr, and those listed in the given set. Good practice in child processes. */ void closeMostFDs(const set<int> & exceptions); diff --git a/src/nix-store/local.mk b/src/nix-store/local.mk index 7f93e4c19..dc049f348 100644 --- a/src/nix-store/local.mk +++ b/src/nix-store/local.mk @@ -7,3 +7,5 @@ nix-store_SOURCES := $(wildcard $(d)/*.cc) nix-store_LIBS = libmain libstore libutil libformat nix-store_LDFLAGS = -lbz2 + +nix-store_CXXFLAGS = -DCURL=\"$(curl)\" diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 5da401c77..4fee7258c 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -467,10 +467,11 @@ static void opReadLog(Strings opFlags, Strings opArgs) foreach (Strings::iterator, i, opArgs) { Path path = useDeriver(followLinksToStorePath(*i)); - for (int j = 0; j <= 2; j++) { - if (j == 2) throw Error(format("build log of derivation `%1%' is not available") % path); + string baseName = baseNameOf(path); + bool found = false; + + for (int j = 0; j < 2; j++) { - string baseName = baseNameOf(path); Path logPath = j == 0 ? (format("%1%/%2%/%3%/%4%") % settings.nixLogDir % drvsLogDir % string(baseName, 0, 2) % string(baseName, 2)).str() @@ -481,6 +482,7 @@ static void opReadLog(Strings opFlags, Strings opArgs) /* !!! Make this run in O(1) memory. */ string log = readFile(logPath); writeFull(STDOUT_FILENO, (const unsigned char *) log.data(), log.size()); + found = true; break; } @@ -500,9 +502,30 @@ static void opReadLog(Strings opFlags, Strings opArgs) writeFull(STDOUT_FILENO, buf, n); } while (err != BZ_STREAM_END); BZ2_bzReadClose(&err, bz); + found = true; break; } } + + if (!found) { + for (auto & i : settings.logServers) { + string prefix = i; + if (!prefix.empty() && prefix.back() != '/') prefix += '/'; + string url = prefix + baseName; + try { + string log = runProgram(CURL, true, {"--fail", "--location", "--silent", "--", url}); + std::cout << "(using build log from " << url << ")" << std::endl; + std::cout << log; + found = true; + break; + } catch (ExecError & e) { + /* Ignore errors from curl. FIXME: actually, might be + nice to print a warning on HTTP status != 404. */ + } + } + } + + if (!found) throw Error(format("build log of derivation `%1%' is not available") % path); } } |