aboutsummaryrefslogtreecommitdiff
path: root/src/nix-prefetch-url/nix-prefetch-url.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-prefetch-url/nix-prefetch-url.cc')
-rw-r--r--src/nix-prefetch-url/nix-prefetch-url.cc132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc
new file mode 100644
index 000000000..bd52df1c7
--- /dev/null
+++ b/src/nix-prefetch-url/nix-prefetch-url.cc
@@ -0,0 +1,132 @@
+#include "hash.hh"
+#include "shared.hh"
+#include "download.hh"
+#include "store-api.hh"
+#include "eval.hh"
+#include "eval-inline.hh"
+#include "common-opts.hh"
+
+#include <iostream>
+
+using namespace nix;
+
+
+/* If ‘uri’ starts with ‘mirror://’, then resolve it using the list of
+ mirrors defined in Nixpkgs. */
+string resolveMirrorUri(EvalState & state, string uri)
+{
+ if (string(uri, 0, 9) != "mirror://") return uri;
+
+ string s(uri, 9);
+ auto p = s.find('/');
+ if (p == string::npos) throw Error("invalid mirror URI");
+ string mirrorName(s, 0, p);
+
+ Value vMirrors;
+ state.eval(state.parseExprFromString("import <nixpkgs/pkgs/build-support/fetchurl/mirrors.nix>", "."), vMirrors);
+ state.forceAttrs(vMirrors);
+
+ auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName));
+ if (mirrorList == vMirrors.attrs->end())
+ throw Error(format("unknown mirror name ‘%1%’") % mirrorName);
+ state.forceList(*mirrorList->value);
+
+ if (mirrorList->value->listSize() < 1)
+ throw Error(format("mirror URI ‘%1%’ did not expand to anything") % uri);
+
+ string mirror = state.forceString(*mirrorList->value->listElems()[0]);
+ return mirror + (hasSuffix(mirror, "/") ? "" : "/") + string(s, p + 1);
+}
+
+
+int main(int argc, char * * argv)
+{
+ return handleExceptions(argv[0], [&]() {
+ initNix();
+ initGC();
+
+ HashType ht = htSHA256;
+ std::vector<string> args;
+ Strings searchPath;
+
+ parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
+ if (*arg == "--help")
+ showManPage("nix-prefetch-url");
+ else if (*arg == "--version")
+ printVersion("nix-prefetch-url");
+ else if (*arg == "--type") {
+ string s = getArg(*arg, arg, end);
+ ht = parseHashType(s);
+ if (ht == htUnknown)
+ throw UsageError(format("unknown hash type ‘%1%’") % s);
+ }
+ else if (parseSearchPathArg(arg, end, searchPath))
+ ;
+ else if (*arg != "" && arg->at(0) == '-')
+ return false;
+ else
+ args.push_back(*arg);
+ return true;
+ });
+
+ if (args.size() < 1 || args.size() > 2)
+ throw UsageError("nix-prefetch-url expects one argument");
+
+ store = openStore();
+
+ EvalState state(searchPath);
+
+ /* 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);
+
+ /* If an expected hash is given, the file may already exist in
+ the store. */
+ Hash hash, expectedHash(ht);
+ Path storePath;
+ if (args.size() == 2) {
+ expectedHash = parseHash16or32(ht, args[1]);
+ storePath = makeFixedOutputPath(false, ht, expectedHash, name);
+ if (store->isValidPath(storePath))
+ hash = expectedHash;
+ else
+ storePath.clear();
+ }
+
+ if (storePath.empty()) {
+
+ auto actualUri = resolveMirrorUri(state, uri);
+
+ if (uri != actualUri)
+ printMsg(lvlInfo, format("‘%1%’ expands to ‘%2%’") % uri % actualUri);
+
+ /* Download the file. */
+ auto result = downloadFile(actualUri);
+
+ /* Copy the file to the Nix store. FIXME: if RemoteStore
+ implemented addToStoreFromDump() and downloadFile()
+ supported a sink, we could stream the download directly
+ into the Nix store. */
+ AutoDelete tmpDir(createTempDir(), true);
+ Path tmpFile = (Path) tmpDir + "/tmp";
+ writeFile(tmpFile, result.data);
+
+ /* FIXME: inefficient; addToStore() will also hash
+ this. */
+ hash = hashString(ht, result.data);
+
+ if (expectedHash != Hash(ht) && expectedHash != hash)
+ throw Error(format("hash mismatch for ‘%1%’") % uri);
+
+ storePath = store->addToStore(name, tmpFile, false, ht);
+ }
+
+ printMsg(lvlInfo, format("path is ‘%1%’") % storePath);
+
+ std::cout << printHash16or32(hash) << std::endl;
+ if (getEnv("PRINT_PATH") != "")
+ std::cout << storePath << std::endl;
+ });
+}