From abbbad5679348f206bf98a2d81e7226b744ac07d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 29 Apr 2019 22:12:13 +0200 Subject: [PATCH] Add 'nix list-tarballs' command E.g. $ nix list-tarballs nixpkgs.hello http://tarballs.nixos.org/stdenv-linux/x86_64/4907fc9e8d0d82b28b3c56e3a478a2882f1d700f/bootstrap-tools.tar.xz ... mirror://gnu/hello/hello-2.10.tar.gz $ nix list-tarballs --json -f '' (BTW the latter returns about 6000 files more than find-tarballs.nix.) --- src/libexpr/eval.hh | 5 ++ src/libexpr/primops.cc | 2 + src/nix/list-tarballs.cc | 137 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 src/nix/list-tarballs.cc diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index c537dad53..864c1bec4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -17,6 +17,7 @@ namespace nix { class Store; class EvalState; +struct Derivation; enum RepairFlag : bool; @@ -341,6 +342,10 @@ private: friend struct ExprOpConcatLists; friend struct ExprSelect; friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v); + +public: + + std::function derivationHook; }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 73c8e670f..3c21f3b4b 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -757,6 +757,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Write the resulting term into the Nix store directory. */ Path drvPath = writeDerivation(state.store, drv, drvName, state.repair); + if (state.derivationHook) state.derivationHook(drvPath, drv); + printMsg(lvlChatty, format("instantiated '%1%' -> '%2%'") % drvName % drvPath); diff --git a/src/nix/list-tarballs.cc b/src/nix/list-tarballs.cc new file mode 100644 index 000000000..1765207ac --- /dev/null +++ b/src/nix/list-tarballs.cc @@ -0,0 +1,137 @@ +#include "command.hh" +#include "eval.hh" +#include "eval-inline.hh" +#include "derivations.hh" +#include "common-args.hh" +#include "json.hh" + +using namespace nix; + +struct CmdListTarballs : MixJSON, InstallablesCommand +{ + std::string name() override + { + return "list-tarballs"; + } + + std::string description() override + { + return "list the 'fetchurl' calls made by the dependency graph of a package"; + } + + Examples examples() override + { + return { + Example{ + "To get the tarballs required to build GNU Hello and its dependencies:", + "nix list-tarballs nixpkgs.hello" + }, + }; + } + + struct File + { + std::string type; + bool recursive; + Hash hash; + std::string url; + Path storePath; + }; + + void doIt(ref store, std::function callback) + { + settings.readOnlyMode = true; + + auto state = getEvalState(); + auto autoArgs = getAutoArgs(*state); + + PathSet done; + + state->derivationHook = + [&](const Path & drvPath, const Derivation & drv) { + if (drv.outputs.size() != 1) return; + + auto & output = *drv.outputs.begin(); + + if (output.second.hashAlgo.empty() || output.second.hash.empty()) return; + + if (!done.insert(output.second.path).second) return; + + auto [recursive, hash] = output.second.parseHashInfo(); + + if (recursive) return; // FIXME + + std::optional url; + + auto i = drv.env.find("url"); + if (i != drv.env.end()) + url = i->second; + else { + i = drv.env.find("urls"); + if (i == drv.env.end()) return; + auto urls = tokenizeString>(i->second, " "); + if (urls.empty()) return; + url = urls[0]; + } + + File file; + file.type = drv.builder == "builtin:fetchurl" ? "fetchurl" : "unknown"; + file.recursive = recursive; + file.hash = hash; + file.url = *url; + file.storePath = output.second.path; + + callback(file); + }; + + std::function findDerivations; + + findDerivations = + [&](Value * v) { + state->forceValue(*v); + if (v->type == tAttrs) { + if (state->isDerivation(*v)) { + auto aDrvPath = v->attrs->get(state->sDrvPath); + if (!aDrvPath) return; + try { + state->forceValue(*(*aDrvPath)->value, *(*aDrvPath)->pos); + } catch (EvalError & e) { + } + } else { + for (auto & attr : *v->attrs) + findDerivations(attr.value); + } + } + }; + + for (auto & installable : installables) { + auto v = state->allocValue(); + state->autoCallFunction(autoArgs, installable->toValue(*state), v); + findDerivations(v); + } + } + + void run(ref store) override + { + if (json) { + JSONList json(std::cout); + doIt(store, + [&](const File & file) { + auto obj = json.object(); + obj.attr("type", file.type); + if (file.recursive) + obj.attr("recursive", true); + obj.attr("hash", file.hash.to_string(SRI)); + obj.attr("url", file.url); + obj.attr("storePath", file.storePath); + }); + } else { + doIt(store, + [&](const File & file) { + std::cout << file.url << "\n"; + }); + } + } +}; + +static RegisterCommand r1(make_ref());