Support Git repos in the Nix path
E.g. $ nix-build -I nixpkgs=git://github.com/NixOS/nixpkgs '<nixpkgs>' -A hello This is not extremely useful yet because you can't specify a branch/revision.
This commit is contained in:
		
							parent
							
								
									38539b943a
								
							
						
					
					
						commit
						d8bf0d4859
					
				
					 5 changed files with 71 additions and 37 deletions
				
			
		|  | @ -520,9 +520,10 @@ formal | |||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include <eval.hh> | ||||
| #include <download.hh> | ||||
| #include <store-api.hh> | ||||
| #include "eval.hh" | ||||
| #include "download.hh" | ||||
| #include "store-api.hh" | ||||
| #include "primops/fetchgit.hh" | ||||
| 
 | ||||
| 
 | ||||
| namespace nix { | ||||
|  | @ -657,6 +658,10 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl | |||
| 
 | ||||
|     if (isUri(elem.second)) { | ||||
|         try { | ||||
|             if (hasPrefix(elem.second, "git://") || hasSuffix(elem.second, ".git")) | ||||
|                 // FIXME: support specifying revision/branch | ||||
|                 res = { true, exportGit(store, elem.second, "master") }; | ||||
|             else | ||||
|                 res = { true, makeDownloader()->downloadCached(store, elem.second, true) }; | ||||
|         } catch (DownloadError & e) { | ||||
|             printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ cannot be downloaded, ignoring") % elem.second); | ||||
|  |  | |||
|  | @ -5,6 +5,43 @@ | |||
| 
 | ||||
| namespace nix { | ||||
| 
 | ||||
| Path exportGit(ref<Store> store, const std::string & uri, const std::string & rev) | ||||
| { | ||||
|     if (!isUri(uri)) | ||||
|         throw EvalError(format("‘%s’ is not a valid URI") % uri); | ||||
| 
 | ||||
|     Path cacheDir = getCacheDir() + "/nix/git"; | ||||
| 
 | ||||
|     if (!pathExists(cacheDir)) { | ||||
|         createDirs(cacheDir); | ||||
|         runProgram("git", true, { "init", "--bare", cacheDir }); | ||||
|     } | ||||
| 
 | ||||
|     Activity act(*logger, lvlInfo, format("fetching Git repository ‘%s’") % uri); | ||||
| 
 | ||||
|     std::string localRef = "pid-" + std::to_string(getpid()); | ||||
|     Path localRefFile = cacheDir + "/refs/heads/" + localRef; | ||||
| 
 | ||||
|     runProgram("git", true, { "-C", cacheDir, "fetch", uri, rev + ":" + localRef }); | ||||
| 
 | ||||
|     std::string commitHash = chomp(readFile(localRefFile)); | ||||
| 
 | ||||
|     unlink(localRefFile.c_str()); | ||||
| 
 | ||||
|     debug(format("got revision ‘%s’") % commitHash); | ||||
| 
 | ||||
|     // FIXME: should pipe this, or find some better way to extract a
 | ||||
|     // revision.
 | ||||
|     auto tar = runProgram("git", true, { "-C", cacheDir, "archive", commitHash }); | ||||
| 
 | ||||
|     Path tmpDir = createTempDir(); | ||||
|     AutoDelete delTmpDir(tmpDir, true); | ||||
| 
 | ||||
|     runProgram("tar", true, { "x", "-C", tmpDir }, tar); | ||||
| 
 | ||||
|     return store->addToStore("git-export", tmpDir); | ||||
| } | ||||
| 
 | ||||
| static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||
| { | ||||
|     // FIXME: cut&paste from fetch().
 | ||||
|  | @ -35,39 +72,7 @@ static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Va | |||
|     } else | ||||
|         url = state.forceStringNoCtx(*args[0], pos); | ||||
| 
 | ||||
|     if (!isUri(url)) | ||||
|         throw EvalError(format("‘%s’ is not a valid URI, at %s") % url % pos); | ||||
| 
 | ||||
|     Path cacheDir = getCacheDir() + "/nix/git"; | ||||
| 
 | ||||
|     if (!pathExists(cacheDir)) { | ||||
|         createDirs(cacheDir); | ||||
|         runProgram("git", true, { "init", "--bare", cacheDir }); | ||||
|     } | ||||
| 
 | ||||
|     Activity act(*logger, lvlInfo, format("fetching Git repository ‘%s’") % url); | ||||
| 
 | ||||
|     std::string localRef = "pid-" + std::to_string(getpid()); | ||||
|     Path localRefFile = cacheDir + "/refs/heads/" + localRef; | ||||
| 
 | ||||
|     runProgram("git", true, { "-C", cacheDir, "fetch", url, rev + ":" + localRef }); | ||||
| 
 | ||||
|     std::string commitHash = chomp(readFile(localRefFile)); | ||||
| 
 | ||||
|     unlink(localRefFile.c_str()); | ||||
| 
 | ||||
|     debug(format("got revision ‘%s’") % commitHash); | ||||
| 
 | ||||
|     // FIXME: should pipe this, or find some better way to extract a
 | ||||
|     // revision.
 | ||||
|     auto tar = runProgram("git", true, { "-C", cacheDir, "archive", commitHash }); | ||||
| 
 | ||||
|     Path tmpDir = createTempDir(); | ||||
|     AutoDelete delTmpDir(tmpDir, true); | ||||
| 
 | ||||
|     runProgram("tar", true, { "x", "-C", tmpDir }, tar); | ||||
| 
 | ||||
|     Path storePath = state.store->addToStore("git-export", tmpDir); | ||||
|     Path storePath = exportGit(state.store, url, rev); | ||||
| 
 | ||||
|     mkString(v, storePath, PathSet({storePath})); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										14
									
								
								src/libexpr/primops/fetchgit.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/libexpr/primops/fetchgit.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include "ref.hh" | ||||
| 
 | ||||
| namespace nix { | ||||
| 
 | ||||
| class Store; | ||||
| 
 | ||||
| Path exportGit(ref<Store> store, | ||||
|     const std::string & uri, const std::string & rev); | ||||
| 
 | ||||
| } | ||||
|  | @ -1082,6 +1082,12 @@ bool statusOk(int status) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool hasPrefix(const string & s, const string & suffix) | ||||
| { | ||||
|     return s.compare(0, suffix.size(), suffix) == 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool hasSuffix(const string & s, const string & suffix) | ||||
| { | ||||
|     return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix; | ||||
|  |  | |||
|  | @ -333,6 +333,10 @@ template<class N> bool string2Float(const string & s, N & n) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Return true iff `s' starts with `prefix'. */ | ||||
| bool hasPrefix(const string & s, const string & prefix); | ||||
| 
 | ||||
| 
 | ||||
| /* Return true iff `s' ends in `suffix'. */ | ||||
| bool hasSuffix(const string & s, const string & suffix); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue