about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-10-01T16·07+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-10-01T16·07+0200
commit06f29fafe8496ae751e84a8ded0cc1041740cfe0 (patch)
tree47885d8e77feb6c76772239d4ee87192953b310b
parenta3c4eb096456673b48f4fc35b76097d67e022141 (diff)
nix-prefetch-url: Support prefetching from a Nix expression
For example,

  $ nix-prefetch-url -A hello.src

will prefetch the file specified by the fetchurl call in the attribute
‘hello.src’ from the Nix expression in the current directory. This
differs from ‘nix-build -A hello.src’ in that it doesn't verify the
hash.

You can also specify a path to the Nix expression:

  $ nix-prefetch-url ~/Dev/nixpkgs -A hello.src

List elements (typically used in ‘patches’ attributes) also work:

  $ nix-prefetch-url -A portmidi.patches.0
-rw-r--r--doc/manual/command-ref/nix-prefetch-url.xml1
-rw-r--r--src/nix-prefetch-url/nix-prefetch-url.cc40
2 files changed, 37 insertions, 4 deletions
diff --git a/doc/manual/command-ref/nix-prefetch-url.xml b/doc/manual/command-ref/nix-prefetch-url.xml
index 0f24bef39abf..9cbaa42a1b1f 100644
--- a/doc/manual/command-ref/nix-prefetch-url.xml
+++ b/doc/manual/command-ref/nix-prefetch-url.xml
@@ -20,6 +20,7 @@
   <cmdsynopsis>
     <command>nix-prefetch-url</command>
     <arg><option>--type</option> <replaceable>hashAlgo</replaceable></arg>
+    <arg><option>--print-path</option></arg>
     <arg choice='plain'><replaceable>url</replaceable></arg>
     <arg><replaceable>hash</replaceable></arg>
   </cmdsynopsis>
diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc
index cb6078fca1c7..112d303e0c16 100644
--- a/src/nix-prefetch-url/nix-prefetch-url.cc
+++ b/src/nix-prefetch-url/nix-prefetch-url.cc
@@ -5,6 +5,7 @@
 #include "eval.hh"
 #include "eval-inline.hh"
 #include "common-opts.hh"
+#include "attr-path.hh"
 
 #include <iostream>
 
@@ -49,6 +50,9 @@ int main(int argc, char * * argv)
         std::vector<string> args;
         Strings searchPath;
         bool printPath = getEnv("PRINT_PATH") != "";
+        bool fromExpr = false;
+        string attrPath;
+        std::map<string, string> autoArgs_;
 
         parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
             if (*arg == "--help")
@@ -63,6 +67,12 @@ int main(int argc, char * * argv)
             }
             else if (*arg == "--print-path")
                 printPath = true;
+            else if (*arg == "--attr" || *arg == "-A") {
+                fromExpr = true;
+                attrPath = getArg(*arg, arg, end);
+            }
+            else if (parseAutoArgs(arg, end, autoArgs_))
+                ;
             else if (parseSearchPathArg(arg, end, searchPath))
                 ;
             else if (*arg != "" && arg->at(0) == '-')
@@ -72,15 +82,37 @@ int main(int argc, char * * argv)
             return true;
         });
 
-        if (args.size() < 1 || args.size() > 2)
-            throw UsageError("nix-prefetch-url expects one argument");
+        if (args.size() > 2)
+            throw UsageError("too many arguments");
 
         store = openStore();
-
         EvalState state(searchPath);
 
+        Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
+
+        /* If -A is given, get the URI from the specified Nix
+           expression. */
+        string uri;
+        if (!fromExpr) {
+            if (args.empty())
+                throw UsageError("you must specify a URI");
+            uri = args[0];
+        } else {
+            Path path = resolveExprPath(lookupFileArg(state, args.empty() ? "." : args[0]));
+            Value vRoot;
+            state.evalFile(path, vRoot);
+            Value & v(*findAlongAttrPath(state, attrPath, autoArgs, vRoot));
+            state.forceAttrs(v);
+            auto urls = v.attrs->find(state.symbols.create("urls"));
+            if (urls == v.attrs->end())
+                throw Error("attribute set does not contain a ‘urls’ attribute");
+            state.forceList(*urls->value);
+            if (urls->value->listSize() < 1)
+                throw Error("‘urls’ list is empty");
+            uri = state.forceString(*urls->value->listElems()[0]);
+        }
+
         /* Figure out a name in the Nix store. */
-        auto uri = args[0];
         auto name = baseNameOf(uri);
         if (name.empty())
             throw Error(format("cannot figure out file name for ‘%1%’") % uri);