about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-05-05T15·09+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-05-05T15·09+0200
commit9451ef3731904090d7c8476137960a3fb9d4679d (patch)
treee1963c47fbba25a17f5a72670d774d28db229f1a /src
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')
-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
-rw-r--r--src/nix-env/nix-env.cc4
-rw-r--r--src/nix-instantiate/nix-instantiate.cc10
6 files changed, 123 insertions, 99 deletions
diff --git a/src/libexpr/download.cc b/src/libexpr/download.cc
index cb06b94e6d87..e3c6c505c543 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 65396e5de329..36fa183d68f9 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 664d6692f51e..e3f2f09b20bd 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 8823efe82e62..fe2f1b1e0ae1 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);
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 10b95dad168c..5cf41e844e83 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -1423,6 +1423,8 @@ int main(int argc, char * * argv)
 
         if (!op) throw UsageError("no operation specified");
 
+        store = openStore();
+
         globals.state = std::shared_ptr<EvalState>(new EvalState(searchPath));
         globals.state->repair = repair;
 
@@ -1441,8 +1443,6 @@ int main(int argc, char * * argv)
                 : canonPath(settings.nixStateDir + "/profiles/default");
         }
 
-        store = openStore();
-
         op(globals, opFlags, opArgs);
 
         globals.state->printStats();
diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc
index 5abaa617d245..973a34ec1495 100644
--- a/src/nix-instantiate/nix-instantiate.cc
+++ b/src/nix-instantiate/nix-instantiate.cc
@@ -155,14 +155,16 @@ int main(int argc, char * * argv)
             return true;
         });
 
+        if (evalOnly && !wantsReadWrite)
+            settings.readOnlyMode = true;
+
+        store = openStore();
+
         EvalState state(searchPath);
         state.repair = repair;
 
         Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
 
-        if (evalOnly && !wantsReadWrite)
-            settings.readOnlyMode = true;
-
         if (attrPaths.empty()) attrPaths.push_back("");
 
         if (findFile) {
@@ -174,8 +176,6 @@ int main(int argc, char * * argv)
             return;
         }
 
-        store = openStore();
-
         if (readStdin) {
             Expr * e = parseStdin(state);
             processExpr(state, attrPaths, parseOnly, strict, autoArgs,