Skip to content

Commit

Permalink
nix-prefetch-url: Rewrite in C++
Browse files Browse the repository at this point in the history
  • Loading branch information
edolstra committed Oct 1, 2015
1 parent bdc4a0b commit bec3c31
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 133 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ makefiles = \
src/nix-collect-garbage/local.mk \
src/download-via-ssh/local.mk \
src/nix-log2xml/local.mk \
src/nix-prefetch-url/local.mk \
src/bsdiff-4.3/local.mk \
perl/local.mk \
scripts/local.mk \
Expand Down
1 change: 0 additions & 1 deletion scripts/local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ nix_bin_scripts := \
$(d)/nix-copy-closure \
$(d)/nix-generate-patches \
$(d)/nix-install-package \
$(d)/nix-prefetch-url \
$(d)/nix-pull \
$(d)/nix-push

Expand Down
132 changes: 0 additions & 132 deletions scripts/nix-prefetch-url.in

This file was deleted.

1 change: 1 addition & 0 deletions src/libutil/util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ public:
AutoDelete(const Path & p, bool recursive = true);
~AutoDelete();
void cancel();
operator Path() const { return path; }
};


Expand Down
7 changes: 7 additions & 0 deletions src/nix-prefetch-url/local.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
programs += nix-prefetch-url

nix-prefetch-url_DIR := $(d)

nix-prefetch-url_SOURCES := $(d)/nix-prefetch-url.cc

nix-prefetch-url_LIBS = libmain libexpr libstore libutil libformat
132 changes: 132 additions & 0 deletions src/nix-prefetch-url/nix-prefetch-url.cc
Original file line number Diff line number Diff line change
@@ -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;
});
}

0 comments on commit bec3c31

Please sign in to comment.