builtins.fetchgit: Support importing a working tree
For example, you can write src = fetchgit ./.; and if ./. refers to an unclean working tree, that tree will be copied to the Nix store. This removes the need for "cleanSource".
This commit is contained in:
		
							parent
							
								
									197922ea4e
								
							
						
					
					
						commit
						72cd52c3cd
					
				
					 7 changed files with 54 additions and 17 deletions
				
			
		|  | @ -667,7 +667,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl | |||
|         try { | ||||
|             if (hasPrefix(elem.second, "git://") || hasSuffix(elem.second, ".git")) | ||||
|                 // FIXME: support specifying revision/branch | ||||
|                 res = { true, exportGit(store, elem.second, "master").storePath }; | ||||
|                 res = { true, exportGit(store, elem.second).storePath }; | ||||
|             else | ||||
|                 res = { true, getDownloader()->downloadCached(store, elem.second, true) }; | ||||
|         } catch (DownloadError & e) { | ||||
|  |  | |||
|  | @ -16,9 +16,48 @@ using namespace std::string_literals; | |||
| namespace nix { | ||||
| 
 | ||||
| GitInfo exportGit(ref<Store> store, const std::string & uri, | ||||
|     const std::string & ref, const std::string & rev, | ||||
|     std::experimental::optional<std::string> ref, const std::string & rev, | ||||
|     const std::string & name) | ||||
| { | ||||
|     if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) { | ||||
| 
 | ||||
|         bool clean = true; | ||||
| 
 | ||||
|         try { | ||||
|             runProgram("git", true, { "-C", uri, "diff-index", "--quiet", "HEAD", "--" }); | ||||
|         } catch (ExecError e) { | ||||
|             if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 1) throw; | ||||
|             clean = false; | ||||
|         } | ||||
| 
 | ||||
|         if (!clean) { | ||||
| 
 | ||||
|             /* This is an unclean working tree. So copy all tracked
 | ||||
|                files. */ | ||||
| 
 | ||||
|             GitInfo gitInfo; | ||||
|             gitInfo.rev = "0000000000000000000000000000000000000000"; | ||||
|             gitInfo.shortRev = std::string(gitInfo.rev, 0, 7); | ||||
| 
 | ||||
|             auto files = tokenizeString<std::set<std::string>>( | ||||
|                 runProgram("git", true, { "-C", uri, "ls-files", "-z" }), "\0"s); | ||||
| 
 | ||||
|             PathFilter filter = [&](const Path & p) -> bool { | ||||
|                 assert(hasPrefix(p, uri)); | ||||
|                 auto st = lstat(p); | ||||
|                 if (S_ISDIR(st.st_mode)) return true; | ||||
|                 std::string file(p, uri.size() + 1); | ||||
|                 return files.count(file); | ||||
|             }; | ||||
| 
 | ||||
|             gitInfo.storePath = store->addToStore("source", uri, true, htSHA256, filter); | ||||
| 
 | ||||
|             return gitInfo; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!ref) ref = "master"; | ||||
| 
 | ||||
|     if (rev != "") { | ||||
|         std::regex revRegex("^[0-9a-fA-F]{40}$"); | ||||
|         if (!std::regex_match(rev, revRegex)) | ||||
|  | @ -32,7 +71,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri, | |||
|         runProgram("git", true, { "init", "--bare", cacheDir }); | ||||
|     } | ||||
| 
 | ||||
|     std::string localRef = hashString(htSHA256, fmt("%s-%s", uri, ref)).to_string(Base32, false); | ||||
|     std::string localRef = hashString(htSHA256, fmt("%s-%s", uri, *ref)).to_string(Base32, false); | ||||
| 
 | ||||
|     Path localRefFile = cacheDir + "/refs/heads/" + localRef; | ||||
| 
 | ||||
|  | @ -47,7 +86,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri, | |||
| 
 | ||||
|         // FIXME: git stderr messes up our progress indicator, so
 | ||||
|         // we're using --quiet for now. Should process its stderr.
 | ||||
|         runProgram("git", true, { "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, ref + ":" + localRef }); | ||||
|         runProgram("git", true, { "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, *ref + ":" + localRef }); | ||||
| 
 | ||||
|         struct timeval times[2]; | ||||
|         times[0].tv_sec = now; | ||||
|  | @ -114,7 +153,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri, | |||
| static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||
| { | ||||
|     std::string url; | ||||
|     std::string ref = "master"; | ||||
|     std::experimental::optional<std::string> ref; | ||||
|     std::string rev; | ||||
|     std::string name = "source"; | ||||
|     PathSet context; | ||||
|  | @ -145,7 +184,7 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va | |||
|     } else | ||||
|         url = state.coerceToString(pos, *args[0], context, false, false); | ||||
| 
 | ||||
|     if (hasPrefix(url, "/")) url = "file://" + url; | ||||
|     if (!isUri(url)) url = absPath(url); | ||||
| 
 | ||||
|     // FIXME: git externals probably can be used to bypass the URI
 | ||||
|     // whitelist. Ah well.
 | ||||
|  |  | |||
|  | @ -17,7 +17,8 @@ struct GitInfo | |||
| }; | ||||
| 
 | ||||
| GitInfo exportGit(ref<Store> store, const std::string & uri, | ||||
|     const std::string & ref, const std::string & rev = "", | ||||
|     std::experimental::optional<std::string> ref = {}, | ||||
|     const std::string & rev = "", | ||||
|     const std::string & name = ""); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ const std::string narVersionMagic1 = "nix-archive-1"; | |||
| 
 | ||||
| static string caseHackSuffix = "~nix~case~hack~"; | ||||
| 
 | ||||
| PathFilter defaultPathFilter; | ||||
| PathFilter defaultPathFilter = [](const Path &) { return true; }; | ||||
| 
 | ||||
| 
 | ||||
| static void dumpContents(const Path & path, size_t size, | ||||
|  |  | |||
|  | @ -44,13 +44,6 @@ namespace nix { | |||
| 
 | ||||
|      `+' denotes string concatenation. */ | ||||
| 
 | ||||
| struct PathFilter | ||||
| { | ||||
|     virtual ~PathFilter() { } | ||||
|     virtual bool operator () (const Path & path) { return true; } | ||||
| }; | ||||
| 
 | ||||
| extern PathFilter defaultPathFilter; | ||||
| 
 | ||||
| void dumpPath(const Path & path, Sink & sink, | ||||
|     PathFilter & filter = defaultPathFilter); | ||||
|  |  | |||
|  | @ -93,8 +93,6 @@ Hash hashFile(HashType ht, const Path & path); | |||
| 
 | ||||
| /* Compute the hash of the given path.  The hash is defined as
 | ||||
|    (essentially) hashString(ht, dumpPath(path)). */ | ||||
| struct PathFilter; | ||||
| extern PathFilter defaultPathFilter; | ||||
| typedef std::pair<Hash, unsigned long long> HashResult; | ||||
| HashResult hashPath(HashType ht, const Path & path, | ||||
|     PathFilter & filter = defaultPathFilter); | ||||
|  |  | |||
|  | @ -481,4 +481,10 @@ struct MaintainCount | |||
| std::pair<unsigned short, unsigned short> getWindowSize(); | ||||
| 
 | ||||
| 
 | ||||
| /* Used in various places. */ | ||||
| typedef std::function<bool(const Path & path)> PathFilter; | ||||
| 
 | ||||
| extern PathFilter defaultPathFilter; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue