aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/local.mk2
-rw-r--r--src/libexpr/primops.cc119
2 files changed, 120 insertions, 1 deletions
diff --git a/src/libexpr/local.mk b/src/libexpr/local.mk
index 4c1f4de19..35e84980a 100644
--- a/src/libexpr/local.mk
+++ b/src/libexpr/local.mk
@@ -8,7 +8,7 @@ libexpr_SOURCES := $(wildcard $(d)/*.cc) $(d)/lexer-tab.cc $(d)/parser-tab.cc
libexpr_LIBS = libutil libstore libformat
-libexpr_LDFLAGS = -ldl
+libexpr_LDFLAGS = -ldl -lcurl
# The dependency on libgc must be propagated (i.e. meaning that
# programs/libraries that use libexpr must explicitly pass -lgc),
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index ac7652d37..e81849646 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -18,6 +18,8 @@
#include <cstring>
#include <dlfcn.h>
+#include <curl/curl.h>
+
namespace nix {
@@ -1480,6 +1482,119 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a
/*************************************************************
+ * Networking
+ *************************************************************/
+
+
+struct Curl
+{
+ CURL * curl;
+ string data;
+
+ static size_t writeCallback(void * contents, size_t size, size_t nmemb, void * userp)
+ {
+ Curl & c(* (Curl *) userp);
+ size_t realSize = size * nmemb;
+ c.data.append((char *) contents, realSize);
+ return realSize;
+ }
+
+ Curl()
+ {
+ curl = curl_easy_init();
+ if (!curl) throw Error("unable to initialize curl");
+
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt(curl, CURLOPT_CAINFO, getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt").c_str());
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, ("Nix/" + nixVersion).c_str());
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &curl);
+ }
+
+ ~Curl()
+ {
+ if (curl) curl_easy_cleanup(curl);
+ }
+
+ string fetch(const string & url)
+ {
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+
+ data.clear();
+
+ CURLcode res = curl_easy_perform(curl);
+ if (res != CURLE_OK)
+ throw Error(format("unable to download ‘%1%’: %2%")
+ % url % curl_easy_strerror(res));
+
+ return data;
+ }
+};
+
+
+void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
+ const string & who, bool unpack)
+{
+ if (state.restricted) throw Error(format("‘%1%’ is not allowed in restricted mode") % who);
+
+ string url;
+
+ state.forceValue(*args[0]);
+
+ if (args[0]->type == tAttrs) {
+
+ state.forceAttrs(*args[0], pos);
+
+ for (auto & attr : *args[0]->attrs) {
+ string name(attr.name);
+ if (name == "url")
+ url = state.forceStringNoCtx(*attr.value, *attr.pos);
+ else
+ throw EvalError(format("unsupported argument ‘%1%’ to ‘%2%’, at %3%") % attr.name % who % attr.pos);
+ }
+
+ if (url.empty())
+ throw EvalError(format("‘url’ argument required, at %1%") % pos);
+
+ } else
+ url = state.forceStringNoCtx(*args[0], pos);
+
+ // TODO: cache downloads.
+
+ Curl curl;
+ string data = curl.fetch(url);
+
+ string name;
+ string::size_type p = url.rfind('/');
+ if (p != string::npos) name = string(url, p + 1);
+
+ Path storePath = store->addTextToStore(name, data, PathSet(), state.repair);
+
+ if (unpack) {
+ Path tmpDir = createTempDir();
+ AutoDelete autoDelete(tmpDir, true);
+ runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"}, "");
+ storePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, state.repair);
+ }
+
+ mkString(v, storePath, singleton<PathSet>(storePath));
+}
+
+
+static void prim_fetchurl(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+ fetch(state, pos, args, v, "fetchurl", false);
+}
+
+
+static void prim_fetchTarball(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+ fetch(state, pos, args, v, "fetchTarball", true);
+}
+
+
+/*************************************************************
* Primop registration
*************************************************************/
@@ -1617,6 +1732,10 @@ void EvalState::createBaseEnv()
// Derivations
addPrimOp("derivationStrict", 1, prim_derivationStrict);
+ // Networking
+ addPrimOp("__fetchurl", 1, prim_fetchurl);
+ addPrimOp("fetchTarball", 1, prim_fetchTarball);
+
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
string path = findFile("nix/derivation.nix");