Add fetchTarball builtin
This function downloads and unpacks the given URL at evaluation time. This is primarily intended to make it easier to deal with Nix expressions that have external dependencies. For instance, to fetch Nixpkgs 14.12: with import (fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-14.12.tar.gz) {}; Or to fetch a specific revision: with import (fetchTarball https://github.com/NixOS/nixpkgs/archive/2766a4b44ee6eafae03a042801270c7f6b8ed32a.tar.gz) {}; This patch also adds a ‘fetchurl’ builtin that downloads but doesn't unpack its argument. Not sure if it's useful though.
This commit is contained in:
		
							parent
							
								
									7ea6ecf855
								
							
						
					
					
						commit
						000b5a000f
					
				
					 2 changed files with 120 additions and 1 deletions
				
			
		|  | @ -18,6 +18,8 @@ | |||
| #include <cstring> | ||||
| #include <dlfcn.h> | ||||
| 
 | ||||
| #include <curl/curl.h> | ||||
| 
 | ||||
| 
 | ||||
| namespace nix { | ||||
| 
 | ||||
|  | @ -1479,6 +1481,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"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue