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 <fcntl.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <eval.hh> | #include "eval.hh" | ||||||
| #include <download.hh> | #include "download.hh" | ||||||
| #include <store-api.hh> | #include "store-api.hh" | ||||||
|  | #include "primops/fetchgit.hh" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
|  | @ -657,6 +658,10 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl | ||||||
| 
 | 
 | ||||||
|     if (isUri(elem.second)) { |     if (isUri(elem.second)) { | ||||||
|         try { |         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) }; |                 res = { true, makeDownloader()->downloadCached(store, elem.second, true) }; | ||||||
|         } catch (DownloadError & e) { |         } catch (DownloadError & e) { | ||||||
|             printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ cannot be downloaded, ignoring") % elem.second); |             printMsg(lvlError, format("warning: Nix search path entry ‘%1%’ cannot be downloaded, ignoring") % elem.second); | ||||||
|  |  | ||||||
|  | @ -5,6 +5,43 @@ | ||||||
| 
 | 
 | ||||||
| namespace nix { | 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) | static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
| { | { | ||||||
|     // FIXME: cut&paste from fetch().
 |     // FIXME: cut&paste from fetch().
 | ||||||
|  | @ -35,39 +72,7 @@ static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Va | ||||||
|     } else |     } else | ||||||
|         url = state.forceStringNoCtx(*args[0], pos); |         url = state.forceStringNoCtx(*args[0], pos); | ||||||
| 
 | 
 | ||||||
|     if (!isUri(url)) |     Path storePath = exportGit(state.store, url, rev); | ||||||
|         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); |  | ||||||
| 
 | 
 | ||||||
|     mkString(v, storePath, PathSet({storePath})); |     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) | bool hasSuffix(const string & s, const string & suffix) | ||||||
| { | { | ||||||
|     return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == 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'. */ | /* Return true iff `s' ends in `suffix'. */ | ||||||
| bool hasSuffix(const string & s, const string & suffix); | bool hasSuffix(const string & s, const string & suffix); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue