commit
						abe6be578b
					
				
					 8 changed files with 162 additions and 27 deletions
				
			
		|  | @ -308,7 +308,8 @@ stdenv.mkDerivation { … } | ||||||
|   </varlistentry> |   </varlistentry> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   <varlistentry><term><function>builtins.filterSource</function> |   <varlistentry xml:id='builtin-filterSource'> | ||||||
|  |     <term><function>builtins.filterSource</function> | ||||||
|     <replaceable>e1</replaceable> <replaceable>e2</replaceable></term> |     <replaceable>e1</replaceable> <replaceable>e2</replaceable></term> | ||||||
| 
 | 
 | ||||||
|     <listitem> |     <listitem> | ||||||
|  | @ -768,6 +769,75 @@ Evaluates to <literal>[ "foo" ]</literal>. | ||||||
| 
 | 
 | ||||||
|   </varlistentry> |   </varlistentry> | ||||||
| 
 | 
 | ||||||
|  |   <varlistentry> | ||||||
|  |     <term> | ||||||
|  |       <function>builtins.path</function> | ||||||
|  |       <replaceable>args</replaceable> | ||||||
|  |     </term> | ||||||
|  | 
 | ||||||
|  |     <listitem> | ||||||
|  |       <para> | ||||||
|  |         An enrichment of the built-in path type, based on the attributes | ||||||
|  |         present in <replaceable>args</replaceable>. All are optional | ||||||
|  |         except <varname>path</varname>: | ||||||
|  |       </para> | ||||||
|  | 
 | ||||||
|  |       <variablelist> | ||||||
|  |         <varlistentry> | ||||||
|  |           <term>path</term> | ||||||
|  |           <listitem> | ||||||
|  |             <para>The underlying path.</para> | ||||||
|  |           </listitem> | ||||||
|  |         </varlistentry> | ||||||
|  |         <varlistentry> | ||||||
|  |           <term>name</term> | ||||||
|  |           <listitem> | ||||||
|  |             <para> | ||||||
|  |               The name of the path when added to the store. This can | ||||||
|  |               used to reference paths that have nix-illegal characters | ||||||
|  |               in their names, like <literal>@</literal>. | ||||||
|  |             </para> | ||||||
|  |           </listitem> | ||||||
|  |         </varlistentry> | ||||||
|  |         <varlistentry> | ||||||
|  |           <term>filter</term> | ||||||
|  |           <listitem> | ||||||
|  |             <para> | ||||||
|  |               A function of the type expected by | ||||||
|  |               <link linkend="builtin-filterSource">builtins.filterSource</link>, | ||||||
|  |               with the same semantics. | ||||||
|  |             </para> | ||||||
|  |           </listitem> | ||||||
|  |         </varlistentry> | ||||||
|  |         <varlistentry> | ||||||
|  |           <term>recursive</term> | ||||||
|  |           <listitem> | ||||||
|  |             <para> | ||||||
|  |               When <literal>false</literal>, when | ||||||
|  |               <varname>path</varname> is added to the store it is with a | ||||||
|  |               flat hash, rather than a hash of the NAR serialization of | ||||||
|  |               the file. Thus, <varname>path</varname> must refer to a | ||||||
|  |               regular file, not a directory. This allows similar | ||||||
|  |               behavior to <literal>fetchurl</literal>. Defaults to | ||||||
|  |               <literal>true</literal>. | ||||||
|  |             </para> | ||||||
|  |           </listitem> | ||||||
|  |         </varlistentry> | ||||||
|  |         <varlistentry> | ||||||
|  |           <term>sha256</term> | ||||||
|  |           <listitem> | ||||||
|  |             <para> | ||||||
|  |               When provided, this is the expected hash of the file at | ||||||
|  |               the path. Evaluation will fail if the hash is incorrect, | ||||||
|  |               and providing a hash allows | ||||||
|  |               <literal>builtins.path</literal> to be used even when the | ||||||
|  |               <literal>pure-eval</literal> nix config option is on. | ||||||
|  |             </para> | ||||||
|  |           </listitem> | ||||||
|  |         </varlistentry> | ||||||
|  |       </variablelist> | ||||||
|  |     </listitem> | ||||||
|  |   </varlistentry> | ||||||
| 
 | 
 | ||||||
|   <varlistentry><term><function>builtins.pathExists</function> |   <varlistentry><term><function>builtins.pathExists</function> | ||||||
|   <replaceable>path</replaceable></term> |   <replaceable>path</replaceable></term> | ||||||
|  |  | ||||||
|  | @ -1578,7 +1578,7 @@ string EvalState::copyPathToStore(PathSet & context, const Path & path) | ||||||
|         dstPath = srcToStore[path]; |         dstPath = srcToStore[path]; | ||||||
|     else { |     else { | ||||||
|         dstPath = settings.readOnlyMode |         dstPath = settings.readOnlyMode | ||||||
|             ? store->computeStorePathForPath(checkSourcePath(path)).first |             ? store->computeStorePathForPath(baseNameOf(path), checkSourcePath(path)).first | ||||||
|             : store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair); |             : store->addToStore(baseNameOf(path), checkSourcePath(path), true, htSHA256, defaultPathFilter, repair); | ||||||
|         srcToStore[path] = dstPath; |         srcToStore[path] = dstPath; | ||||||
|         printMsg(lvlChatty, format("copied source '%1%' -> '%2%'") |         printMsg(lvlChatty, format("copied source '%1%' -> '%2%'") | ||||||
|  |  | ||||||
|  | @ -1023,20 +1023,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) | static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_, | ||||||
|  |     Value * filterFun, bool recursive, const Hash & expectedHash, Value & v) | ||||||
| { | { | ||||||
|     PathSet context; |     const auto path = settings.pureEval && expectedHash ? | ||||||
|     Path path = state.coerceToPath(pos, *args[1], context); |         path_ : | ||||||
|     if (!context.empty()) |         state.checkSourcePath(path_); | ||||||
|         throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos); |     PathFilter filter = filterFun ? ([&](const Path & path) { | ||||||
| 
 |  | ||||||
|     state.forceValue(*args[0]); |  | ||||||
|     if (args[0]->type != tLambda) |  | ||||||
|         throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos); |  | ||||||
| 
 |  | ||||||
|     path = state.checkSourcePath(path); |  | ||||||
| 
 |  | ||||||
|     PathFilter filter = [&](const Path & path) { |  | ||||||
|         auto st = lstat(path); |         auto st = lstat(path); | ||||||
| 
 | 
 | ||||||
|         /* Call the filter function.  The first argument is the path,
 |         /* Call the filter function.  The first argument is the path,
 | ||||||
|  | @ -1045,7 +1038,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args | ||||||
|         mkString(arg1, path); |         mkString(arg1, path); | ||||||
| 
 | 
 | ||||||
|         Value fun2; |         Value fun2; | ||||||
|         state.callFunction(*args[0], arg1, fun2, noPos); |         state.callFunction(*filterFun, arg1, fun2, noPos); | ||||||
| 
 | 
 | ||||||
|         Value arg2; |         Value arg2; | ||||||
|         mkString(arg2, |         mkString(arg2, | ||||||
|  | @ -1058,16 +1051,79 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args | ||||||
|         state.callFunction(fun2, arg2, res, noPos); |         state.callFunction(fun2, arg2, res, noPos); | ||||||
| 
 | 
 | ||||||
|         return state.forceBool(res, pos); |         return state.forceBool(res, pos); | ||||||
|     }; |     }) : defaultPathFilter; | ||||||
| 
 | 
 | ||||||
|     Path dstPath = settings.readOnlyMode |     Path expectedStorePath; | ||||||
|         ? state.store->computeStorePathForPath(path, true, htSHA256, filter).first |     if (expectedHash) { | ||||||
|         : state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); |         expectedStorePath = | ||||||
|  |             state.store->makeFixedOutputPath(recursive, expectedHash, name); | ||||||
|  |     } | ||||||
|  |     Path dstPath; | ||||||
|  |     if (!expectedHash || !state.store->isValidPath(expectedStorePath)) { | ||||||
|  |         dstPath = settings.readOnlyMode | ||||||
|  |             ? state.store->computeStorePathForPath(name, path, recursive, htSHA256, filter).first | ||||||
|  |             : state.store->addToStore(name, path, recursive, htSHA256, filter, state.repair); | ||||||
|  |         if (expectedHash && expectedStorePath != dstPath) { | ||||||
|  |             throw Error(format("store path mismatch in (possibly filtered) path added from '%1%'") % path); | ||||||
|  |         } | ||||||
|  |     } else | ||||||
|  |         dstPath = expectedStorePath; | ||||||
| 
 | 
 | ||||||
|     mkString(v, dstPath, {dstPath}); |     mkString(v, dstPath, {dstPath}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
|  | { | ||||||
|  |     PathSet context; | ||||||
|  |     Path path = state.coerceToPath(pos, *args[1], context); | ||||||
|  |     if (!context.empty()) | ||||||
|  |         throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % pos); | ||||||
|  | 
 | ||||||
|  |     state.forceValue(*args[0]); | ||||||
|  |     if (args[0]->type != tLambda) | ||||||
|  |         throw TypeError(format("first argument in call to 'filterSource' is not a function but %1%, at %2%") % showType(*args[0]) % pos); | ||||||
|  | 
 | ||||||
|  |     addPath(state, pos, baseNameOf(path), path, args[0], true, Hash(), v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
|  | { | ||||||
|  |     state.forceAttrs(*args[0], pos); | ||||||
|  |     Path path; | ||||||
|  |     string name; | ||||||
|  |     Value * filterFun = nullptr; | ||||||
|  |     auto recursive = true; | ||||||
|  |     Hash expectedHash; | ||||||
|  | 
 | ||||||
|  |     for (auto & attr : *args[0]->attrs) { | ||||||
|  |         const string & n(attr.name); | ||||||
|  |         if (n == "path") { | ||||||
|  |             PathSet context; | ||||||
|  |             path = state.coerceToPath(*attr.pos, *attr.value, context); | ||||||
|  |             if (!context.empty()) | ||||||
|  |                 throw EvalError(format("string '%1%' cannot refer to other paths, at %2%") % path % *attr.pos); | ||||||
|  |         } else if (attr.name == state.sName) | ||||||
|  |             name = state.forceStringNoCtx(*attr.value, *attr.pos); | ||||||
|  |         else if (n == "filter") { | ||||||
|  |             state.forceValue(*attr.value); | ||||||
|  |             filterFun = attr.value; | ||||||
|  |         } else if (n == "recursive") | ||||||
|  |             recursive = state.forceBool(*attr.value, *attr.pos); | ||||||
|  |         else if (n == "sha256") | ||||||
|  |             expectedHash = Hash(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); | ||||||
|  |         else | ||||||
|  |             throw EvalError(format("unsupported argument '%1%' to 'addPath', at %2%") % attr.name % *attr.pos); | ||||||
|  |     } | ||||||
|  |     if (path.empty()) | ||||||
|  |         throw EvalError(format("'path' required, at %1%") % pos); | ||||||
|  |     if (name.empty()) | ||||||
|  |         name = baseNameOf(path); | ||||||
|  | 
 | ||||||
|  |     addPath(state, pos, name, path, filterFun, recursive, expectedHash, v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /*************************************************************
 | /*************************************************************
 | ||||||
|  * Sets |  * Sets | ||||||
|  *************************************************************/ |  *************************************************************/ | ||||||
|  | @ -2085,6 +2141,7 @@ void EvalState::createBaseEnv() | ||||||
|     addPrimOp("__fromJSON", 1, prim_fromJSON); |     addPrimOp("__fromJSON", 1, prim_fromJSON); | ||||||
|     addPrimOp("__toFile", 2, prim_toFile); |     addPrimOp("__toFile", 2, prim_toFile); | ||||||
|     addPrimOp("__filterSource", 2, prim_filterSource); |     addPrimOp("__filterSource", 2, prim_filterSource); | ||||||
|  |     addPrimOp("__path", 1, prim_path); | ||||||
| 
 | 
 | ||||||
|     // Sets
 |     // Sets
 | ||||||
|     addPrimOp("__attrNames", 1, prim_attrNames); |     addPrimOp("__attrNames", 1, prim_attrNames); | ||||||
|  |  | ||||||
|  | @ -222,11 +222,10 @@ Path Store::makeTextPath(const string & name, const Hash & hash, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath, | std::pair<Path, Hash> Store::computeStorePathForPath(const string & name, | ||||||
|     bool recursive, HashType hashAlgo, PathFilter & filter) const |     const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const | ||||||
| { | { | ||||||
|     Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath); |     Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath); | ||||||
|     string name = baseNameOf(srcPath); |  | ||||||
|     Path dstPath = makeFixedOutputPath(recursive, h, name); |     Path dstPath = makeFixedOutputPath(recursive, h, name); | ||||||
|     return std::pair<Path, Hash>(dstPath, h); |     return std::pair<Path, Hash>(dstPath, h); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -307,9 +307,9 @@ public: | ||||||
|     /* This is the preparatory part of addToStore(); it computes the
 |     /* This is the preparatory part of addToStore(); it computes the
 | ||||||
|        store path to which srcPath is to be copied.  Returns the store |        store path to which srcPath is to be copied.  Returns the store | ||||||
|        path and the cryptographic hash of the contents of srcPath. */ |        path and the cryptographic hash of the contents of srcPath. */ | ||||||
|     std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath, |     std::pair<Path, Hash> computeStorePathForPath(const string & name, | ||||||
|         bool recursive = true, HashType hashAlgo = htSHA256, |         const Path & srcPath, bool recursive = true, | ||||||
|         PathFilter & filter = defaultPathFilter) const; |         HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const; | ||||||
| 
 | 
 | ||||||
|     /* Preparatory part of addTextToStore().
 |     /* Preparatory part of addTextToStore().
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								tests/lang/data
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/lang/data
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | foo | ||||||
							
								
								
									
										1
									
								
								tests/lang/eval-okay-path.exp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/lang/eval-okay-path.exp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | "/run/user/1000/nix-test/store/wjagrv37lfvfx92g2gf3yqflwypj0q1y-output" | ||||||
							
								
								
									
										7
									
								
								tests/lang/eval-okay-path.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/lang/eval-okay-path.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | builtins.path | ||||||
|  |   { path = ./.; | ||||||
|  |     filter = path: _: baseNameOf path == "data"; | ||||||
|  |     recursive = true; | ||||||
|  |     sha256 = "1yhm3gwvg5a41yylymgblsclk95fs6jy72w0wv925mmidlhcq4sw"; | ||||||
|  |     name = "output"; | ||||||
|  |   } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue