aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-05-05 17:09:42 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-05-05 17:09:42 +0200
commit9451ef3731904090d7c8476137960a3fb9d4679d (patch)
treee1963c47fbba25a17f5a72670d774d28db229f1a /src/libexpr
parent35d30d67ebcca90c3120eeaa7f38baee8805c670 (diff)
Allow URLs in the Nix search path
E.g. to install "hello" from the latest Nixpkgs: $ nix-build '<nixpkgs>' -A hello -I nixpkgs=https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz Or to install a specific version of NixOS: $ nixos-rebuild switch -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/63def04891a0abc328b1b0b3a78ec02c58f48583.tar.gz
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/download.cc89
-rw-r--r--src/libexpr/download.hh2
-rw-r--r--src/libexpr/parser.y29
-rw-r--r--src/libexpr/primops.cc88
4 files changed, 116 insertions, 92 deletions
diff --git a/src/libexpr/download.cc b/src/libexpr/download.cc
index cb06b94e6..e3c6c505c 100644
--- a/src/libexpr/download.cc
+++ b/src/libexpr/download.cc
@@ -1,6 +1,8 @@
#include "download.hh"
#include "util.hh"
#include "globals.hh"
+#include "hash.hh"
+#include "store-api.hh"
#include <curl/curl.h>
@@ -134,4 +136,91 @@ DownloadResult downloadFile(string url, string expectedETag)
return res;
}
+
+Path downloadFileCached(const string & url, bool unpack)
+{
+ Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
+ createDirs(cacheDir);
+
+ string urlHash = printHash32(hashString(htSHA256, url));
+
+ Path dataFile = cacheDir + "/" + urlHash + ".info";
+ Path fileLink = cacheDir + "/" + urlHash + "-file";
+
+ Path storePath;
+
+ string expectedETag;
+
+ int ttl = settings.get("tarball-ttl", 60 * 60);
+ bool skip = false;
+
+ if (pathExists(fileLink) && pathExists(dataFile)) {
+ storePath = readLink(fileLink);
+ store->addTempRoot(storePath);
+ if (store->isValidPath(storePath)) {
+ auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
+ if (ss.size() >= 3 && ss[0] == url) {
+ time_t lastChecked;
+ if (string2Int(ss[2], lastChecked) && lastChecked + ttl >= time(0))
+ skip = true;
+ else if (!ss[1].empty()) {
+ printMsg(lvlDebug, format("verifying previous ETag ‘%1%’") % ss[1]);
+ expectedETag = ss[1];
+ }
+ }
+ } else
+ storePath = "";
+ }
+
+ string name;
+ auto p = url.rfind('/');
+ if (p != string::npos) name = string(url, p + 1);
+
+ if (!skip) {
+
+ if (storePath.empty())
+ printMsg(lvlInfo, format("downloading ‘%1%’...") % url);
+ else
+ printMsg(lvlInfo, format("checking ‘%1%’...") % url);
+
+ try {
+ auto res = downloadFile(url, expectedETag);
+
+ if (!res.cached)
+ storePath = store->addTextToStore(name, res.data, PathSet(), false);
+
+ assert(!storePath.empty());
+ replaceSymlink(storePath, fileLink);
+
+ writeFile(dataFile, url + "\n" + res.etag + "\n" + int2String(time(0)) + "\n");
+ } catch (DownloadError & e) {
+ if (storePath.empty()) throw;
+ printMsg(lvlError, format("warning: %1%; using cached result") % e.msg());
+ }
+ }
+
+ if (unpack) {
+ Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
+ Path unpackedStorePath;
+ if (pathExists(unpackedLink)) {
+ unpackedStorePath = readLink(unpackedLink);
+ store->addTempRoot(unpackedStorePath);
+ if (!store->isValidPath(unpackedStorePath))
+ unpackedStorePath = "";
+ }
+ if (unpackedStorePath.empty()) {
+ printMsg(lvlInfo, format("unpacking ‘%1%’...") % url);
+ Path tmpDir = createTempDir();
+ AutoDelete autoDelete(tmpDir, true);
+ runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"}, "");
+ unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false);
+ }
+ replaceSymlink(unpackedStorePath, unpackedLink);
+ return unpackedStorePath;
+ }
+
+ return storePath;
+}
+
+
}
diff --git a/src/libexpr/download.hh b/src/libexpr/download.hh
index 65396e5de..36fa183d6 100644
--- a/src/libexpr/download.hh
+++ b/src/libexpr/download.hh
@@ -13,6 +13,8 @@ struct DownloadResult
DownloadResult downloadFile(string url, string expectedETag = "");
+Path downloadFileCached(const string & url, bool unpack);
+
MakeError(DownloadError, Error)
}
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 664d6692f..e3f2f09b2 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -527,6 +527,8 @@ formal
#include <unistd.h>
#include <eval.hh>
+#include <download.hh>
+#include <store-api.hh>
namespace nix {
@@ -599,6 +601,15 @@ Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
}
+bool isUri(const string & s)
+{
+ size_t pos = s.find("://");
+ if (pos == string::npos) return false;
+ string scheme(s, 0, pos);
+ return scheme == "http" || scheme == "https";
+}
+
+
void EvalState::addToSearchPath(const string & s, bool warn)
{
size_t pos = s.find('=');
@@ -611,6 +622,9 @@ void EvalState::addToSearchPath(const string & s, bool warn)
path = string(s, pos + 1);
}
+ if (isUri(path))
+ path = downloadFileCached(path, true);
+
path = absPath(path);
if (pathExists(path)) {
debug(format("adding path ‘%1%’ to the search path") % path);
@@ -629,16 +643,17 @@ Path EvalState::findFile(const string & path)
Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos & pos)
{
- foreach (SearchPath::iterator, i, searchPath) {
+ for (auto & i : searchPath) {
+ assert(!isUri(i.second));
Path res;
- if (i->first.empty())
- res = i->second + "/" + path;
+ if (i.first.empty())
+ res = i.second + "/" + path;
else {
- if (path.compare(0, i->first.size(), i->first) != 0 ||
- (path.size() > i->first.size() && path[i->first.size()] != '/'))
+ if (path.compare(0, i.first.size(), i.first) != 0 ||
+ (path.size() > i.first.size() && path[i.first.size()] != '/'))
continue;
- res = i->second +
- (path.size() == i->first.size() ? "" : "/" + string(path, i->first.size()));
+ res = i.second +
+ (path.size() == i.first.size() ? "" : "/" + string(path, i.first.size()));
}
if (pathExists(res)) return canonPath(res);
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 8823efe82..fe2f1b1e0 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -103,7 +103,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
}
w.attrs->sort();
Value fun;
- state.evalFile(state.findFile("nix/imported-drv-to-derivation.nix"), fun);
+ state.evalFile(settings.nixDataDir + "/nix/corepkgs/imported-drv-to-derivation.nix", fun);
state.forceFunction(fun, pos);
mkApp(v, fun, w);
state.forceAttrs(v, pos);
@@ -1512,88 +1512,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
} else
url = state.forceStringNoCtx(*args[0], pos);
- Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
- createDirs(cacheDir);
-
- string urlHash = printHash32(hashString(htSHA256, url));
-
- Path dataFile = cacheDir + "/" + urlHash + ".info";
- Path fileLink = cacheDir + "/" + urlHash + "-file";
-
- Path storePath;
-
- string expectedETag;
-
- int ttl = settings.get("tarball-ttl", 60 * 60);
- bool skip = false;
-
- if (pathExists(fileLink) && pathExists(dataFile)) {
- storePath = readLink(fileLink);
- store->addTempRoot(storePath);
- if (store->isValidPath(storePath)) {
- auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
- if (ss.size() >= 3 && ss[0] == url) {
- time_t lastChecked;
- if (string2Int(ss[2], lastChecked) && lastChecked + ttl >= time(0))
- skip = true;
- else if (!ss[1].empty()) {
- printMsg(lvlDebug, format("verifying previous ETag ‘%1%’") % ss[1]);
- expectedETag = ss[1];
- }
- }
- } else
- storePath = "";
- }
-
- string name;
- auto p = url.rfind('/');
- if (p != string::npos) name = string(url, p + 1);
-
- if (!skip) {
-
- if (storePath.empty())
- printMsg(lvlInfo, format("downloading ‘%1%’...") % url);
- else
- printMsg(lvlInfo, format("checking ‘%1%’...") % url);
-
- try {
- auto res = downloadFile(url, expectedETag);
-
- if (!res.cached)
- storePath = store->addTextToStore(name, res.data, PathSet(), state.repair);
-
- assert(!storePath.empty());
- replaceSymlink(storePath, fileLink);
-
- writeFile(dataFile, url + "\n" + res.etag + "\n" + int2String(time(0)) + "\n");
- } catch (DownloadError & e) {
- if (storePath.empty()) throw;
- printMsg(lvlError, format("warning: %1%; using cached result") % e.msg());
- }
- }
-
- if (unpack) {
- Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
- Path unpackedStorePath;
- if (pathExists(unpackedLink)) {
- unpackedStorePath = readLink(unpackedLink);
- store->addTempRoot(unpackedStorePath);
- if (!store->isValidPath(unpackedStorePath))
- unpackedStorePath = "";
- }
- if (unpackedStorePath.empty()) {
- printMsg(lvlDebug, format("unpacking ‘%1%’...") % storePath);
- Path tmpDir = createTempDir();
- AutoDelete autoDelete(tmpDir, true);
- runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"}, "");
- unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, state.repair);
- }
- replaceSymlink(unpackedStorePath, unpackedLink);
- mkString(v, unpackedStorePath, singleton<PathSet>(unpackedStorePath));
- }
-
- else
- mkString(v, storePath, singleton<PathSet>(storePath));
+ mkString(v, downloadFileCached(url, unpack), PathSet({url}));
}
@@ -1753,8 +1672,7 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
- string path = findFile("nix/derivation.nix");
- assert(!path.empty());
+ string path = settings.nixDataDir + "/nix/corepkgs/derivation.nix";
sDerivationNix = symbols.create(path);
evalFile(path, v);
addConstant("derivation", v);