Make <nix/fetchurl.nix> a builtin builder

This ensures that 1) the derivation doesn't change when Nix changes;
2) the derivation closure doesn't contain Nix and its dependencies; 3)
we don't have to rely on ugly chroot hacks.
This commit is contained in:
Eelco Dolstra 2015-07-20 04:30:16 +02:00
parent eda2f36c2a
commit 0a2bee307b
9 changed files with 61 additions and 20 deletions

View file

@ -12,7 +12,6 @@ in rec {
tar = "@tar@"; tar = "@tar@";
tarFlags = "@tarFlags@"; tarFlags = "@tarFlags@";
tr = "@tr@"; tr = "@tr@";
curl = "@curl@";
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@"; nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
nixPrefix = "@prefix@"; nixPrefix = "@prefix@";

View file

@ -5,20 +5,9 @@ with import <nix/config.nix>;
assert (outputHash != "" && outputHashAlgo != "") assert (outputHash != "" && outputHashAlgo != "")
|| md5 != "" || sha1 != "" || sha256 != ""; || md5 != "" || sha1 != "" || sha256 != "";
let
builder = builtins.toFile "fetchurl.sh"
(''
echo "downloading $url into $out"
${curl} --fail --location --max-redirs 20 --insecure "$url" > "$out"
'' + (if executable then "${coreutils}/chmod +x $out" else ""));
in
derivation { derivation {
name = baseNameOf (toString url); name = baseNameOf (toString url);
builder = shell; builder = "builtin:fetchurl";
args = [ "-e" builder ];
# New-style output content requirements. # New-style output content requirements.
outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else
@ -39,6 +28,4 @@ derivation {
# by definition pure. # by definition pure.
"http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy" "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
]; ];
inherit chrootDeps;
} }

View file

@ -8,7 +8,7 @@ libexpr_SOURCES := $(wildcard $(d)/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
libexpr_LIBS = libutil libstore libformat libexpr_LIBS = libutil libstore libformat
libexpr_LDFLAGS = -ldl -lcurl libexpr_LDFLAGS = -ldl
# The dependency on libgc must be propagated (i.e. meaning that # The dependency on libgc must be propagated (i.e. meaning that
# programs/libraries that use libexpr must explicitly pass -lgc), # programs/libraries that use libexpr must explicitly pass -lgc),

View file

@ -8,6 +8,7 @@
#include "util.hh" #include "util.hh"
#include "archive.hh" #include "archive.hh"
#include "affinity.hh" #include "affinity.hh"
#include "builtins.hh"
#include <map> #include <map>
#include <sstream> #include <sstream>
@ -1269,6 +1270,12 @@ bool substitutesAllowed(const BasicDerivation & drv)
} }
static bool isBuiltin(const BasicDerivation & drv)
{
return string(drv.builder, 0, 8) == "builtin:";
}
void DerivationGoal::tryToBuild() void DerivationGoal::tryToBuild()
{ {
trace("trying to build"); trace("trying to build");
@ -2139,7 +2146,7 @@ void DerivationGoal::startBuilder()
#endif #endif
{ {
ProcessOptions options; ProcessOptions options;
options.allowVfork = !buildUser.enabled(); options.allowVfork = !buildUser.enabled() && !isBuiltin(*drv);
pid = startProcess([&]() { pid = startProcess([&]() {
runChild(); runChild();
}, options); }, options);
@ -2386,7 +2393,9 @@ void DerivationGoal::runChild()
const char *builder = "invalid"; const char *builder = "invalid";
string sandboxProfile; string sandboxProfile;
if (useChroot && SANDBOX_ENABLED) { if (isBuiltin(*drv))
;
else if (useChroot && SANDBOX_ENABLED) {
/* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */
PathSet ancestry; PathSet ancestry;
@ -2413,7 +2422,6 @@ void DerivationGoal::runChild()
for (auto & i : inputPaths) for (auto & i : inputPaths)
dirsInChroot[i] = i; dirsInChroot[i] = i;
/* TODO: we should factor out the policy cleanly, so we don't have to repeat the constants every time... */ /* TODO: we should factor out the policy cleanly, so we don't have to repeat the constants every time... */
sandboxProfile += "(version 1)\n"; sandboxProfile += "(version 1)\n";
@ -2517,6 +2525,20 @@ void DerivationGoal::runChild()
} }
/* Execute the program. This should not return. */ /* Execute the program. This should not return. */
if (isBuiltin(*drv)) {
try {
logType = ltFlat;
if (drv->builder == "builtin:fetchurl")
builtinFetchurl(*drv);
else
throw Error(format("unsupported builtin function %1%") % string(drv->builder, 8));
_exit(0);
} catch (std::exception & e) {
writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
_exit(1);
}
}
execve(builder, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); execve(builder, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
throw SysError(format("executing %1%") % drv->builder); throw SysError(format("executing %1%") % drv->builder);

24
src/libstore/builtins.cc Normal file
View file

@ -0,0 +1,24 @@
#include "builtins.hh"
#include "download.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv)
{
auto url = drv.env.find("url");
if (url == drv.env.end()) throw Error("attribute url missing");
printMsg(lvlInfo, format("downloading %1%...") % url->second);
auto data = downloadFile(url->second); // FIXME: show progress
auto out = drv.env.find("out");
if (out == drv.env.end()) throw Error("attribute url missing");
writeFile(out->second, data.data);
auto executable = drv.env.find("out");
if (executable != drv.env.end() && executable->second == "1") {
if (chmod(out->second.c_str(), 0755) == -1)
throw SysError(format("making %1% executable") % out->second);
}
}
}

9
src/libstore/builtins.hh Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#include "derivations.hh"
namespace nix {
void builtinFetchurl(const BasicDerivation & drv);
}

View file

@ -8,7 +8,7 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
libstore_LIBS = libutil libformat libstore_LIBS = libutil libformat
libstore_LDFLAGS = -lsqlite3 -lbz2 libstore_LDFLAGS = -lsqlite3 -lbz2 -lcurl
ifeq ($(OS), SunOS) ifeq ($(OS), SunOS)
libstore_LDFLAGS += -lsocket libstore_LDFLAGS += -lsocket