aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-05-21 17:19:36 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-05-21 17:19:36 +0200
commit9f9080e2c019f188ba679a7a89284d7eaf629710 (patch)
treedac5d9672e2b4c139c2e97d7766911b62f8b069b /src
parenteac5841970737b799c55ec78f6ace6d80762ff04 (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.cc1
-rw-r--r--src/libstore/globals.hh3
-rw-r--r--src/libutil/util.cc2
-rw-r--r--src/libutil/util.hh2
-rw-r--r--src/nix-store/local.mk2
-rw-r--r--src/nix-store/nix-store.cc29
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);
}
}