* Store user environment manifests as a Nix expression in
$out/manifest.nix rather than as an ATerm. (Hm, I thought I committed this two days ago...)
This commit is contained in:
		
							parent
							
								
									f3b8833a48
								
							
						
					
					
						commit
						fe2d869e04
					
				
					 11 changed files with 205 additions and 183 deletions
				
			
		|  | @ -1,5 +1,12 @@ | |||
| #include "util.hh" | ||||
| #include "get-drvs.hh" | ||||
| #include "derivations.hh" | ||||
| #include "store-api.hh" | ||||
| #include "globals.hh" | ||||
| #include "shared.hh" | ||||
| #include "eval.hh" | ||||
| #include "parser.hh" | ||||
| #include "profiles.hh" | ||||
| 
 | ||||
| 
 | ||||
| namespace nix { | ||||
|  | @ -11,18 +18,138 @@ static void readLegacyManifest(const Path & path, DrvInfos & elems); | |||
| DrvInfos queryInstalled(EvalState & state, const Path & userEnv) | ||||
| { | ||||
|     DrvInfos elems; | ||||
|      | ||||
|     Path path = userEnv + "/manifest"; | ||||
| 
 | ||||
|     if (!pathExists(path)) | ||||
|         return DrvInfos(); /* not an error, assume nothing installed */ | ||||
|     Path manifestFile = userEnv + "/manifest.nix"; | ||||
|     Path oldManifestFile = userEnv + "/manifest"; | ||||
| 
 | ||||
|     readLegacyManifest(path, elems); | ||||
|     if (pathExists(manifestFile)) { | ||||
|         Value v; | ||||
|         state.eval(parseExprFromFile(state, manifestFile), v); | ||||
|         getDerivations(state, v, "", Bindings(), elems); | ||||
|     } else if (pathExists(oldManifestFile)) | ||||
|         readLegacyManifest(oldManifestFile, elems); | ||||
| 
 | ||||
|     return elems; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool createUserEnv(EvalState & state, DrvInfos & elems, | ||||
|     const Path & profile, bool keepDerivations, | ||||
|     const string & lockToken) | ||||
| { | ||||
|     /* Build the components in the user environment, if they don't
 | ||||
|        exist already. */ | ||||
|     PathSet drvsToBuild; | ||||
|     foreach (DrvInfos::const_iterator, i, elems) | ||||
|         if (i->queryDrvPath(state) != "") | ||||
|             drvsToBuild.insert(i->queryDrvPath(state)); | ||||
| 
 | ||||
|     debug(format("building user environment dependencies")); | ||||
|     store->buildDerivations(drvsToBuild); | ||||
| 
 | ||||
|     /* Construct the whole top level derivation. */ | ||||
|     PathSet references; | ||||
|     Value manifest; | ||||
|     state.mkList(manifest, elems.size()); | ||||
|     unsigned int n = 0; | ||||
|     foreach (DrvInfos::iterator, i, elems) { | ||||
|         /* Create a pseudo-derivation containing the name, system,
 | ||||
|            output path, and optionally the derivation path, as well as | ||||
|            the meta attributes. */ | ||||
|         Path drvPath = keepDerivations ? i->queryDrvPath(state) : ""; | ||||
| 
 | ||||
|         Value & v(*state.allocValues(1)); | ||||
|         manifest.list.elems[n++] = &v; | ||||
|         state.mkAttrs(v); | ||||
| 
 | ||||
|         mkString((*v.attrs)[state.sType], "derivation"); | ||||
|         mkString((*v.attrs)[state.sName], i->name); | ||||
|         mkString((*v.attrs)[state.sSystem], i->system); | ||||
|         mkString((*v.attrs)[state.sOutPath], i->queryOutPath(state)); | ||||
|         if (drvPath != "") | ||||
|             mkString((*v.attrs)[state.sDrvPath], i->queryDrvPath(state)); | ||||
|          | ||||
|         state.mkAttrs((*v.attrs)[state.sMeta]); | ||||
|          | ||||
|         MetaInfo meta = i->queryMetaInfo(state); | ||||
| 
 | ||||
|         foreach (MetaInfo::const_iterator, j, meta) { | ||||
|             Value & v2((*(*v.attrs)[state.sMeta].attrs)[state.symbols.create(j->first)]); | ||||
|             switch (j->second.type) { | ||||
|                 case MetaValue::tpInt: mkInt(v2, j->second.intValue); break; | ||||
|                 case MetaValue::tpString: mkString(v2, j->second.stringValue); break; | ||||
|                 case MetaValue::tpStrings: { | ||||
|                     state.mkList(v2, j->second.stringValues.size()); | ||||
|                     unsigned int m = 0; | ||||
|                     foreach (Strings::const_iterator, k, j->second.stringValues) { | ||||
|                         v2.list.elems[m] = state.allocValues(1); | ||||
|                         mkString(*v2.list.elems[m++], *k); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|                 default: abort(); | ||||
|             } | ||||
|         } | ||||
|      | ||||
|         /* This is only necessary when installing store paths, e.g.,
 | ||||
|            `nix-env -i /nix/store/abcd...-foo'. */ | ||||
|         store->addTempRoot(i->queryOutPath(state)); | ||||
|         store->ensurePath(i->queryOutPath(state)); | ||||
|          | ||||
|         references.insert(i->queryOutPath(state)); | ||||
|         if (drvPath != "") references.insert(drvPath); | ||||
|     } | ||||
| 
 | ||||
|     /* Also write a copy of the list of user environment elements to
 | ||||
|        the store; we need it for future modifications of the | ||||
|        environment. */ | ||||
|     Path manifestFile = store->addTextToStore("env-manifest.nix", | ||||
|         (format("%1%") % manifest).str(), references); | ||||
| 
 | ||||
|     printMsg(lvlError, manifestFile); | ||||
| 
 | ||||
|     /* Get the environment builder expression. */ | ||||
|     Value envBuilder; | ||||
|     state.eval(parseExprFromFile(state, nixDataDir + "/nix/corepkgs/buildenv"), envBuilder); | ||||
| 
 | ||||
|     /* Construct a Nix expression that calls the user environment
 | ||||
|        builder with the manifest as argument. */ | ||||
|     Value args, topLevel; | ||||
|     state.mkAttrs(args); | ||||
|     mkString((*args.attrs)[state.sSystem], thisSystem); | ||||
|     mkString((*args.attrs)[state.symbols.create("manifest")], | ||||
|         manifestFile, singleton<PathSet>(manifestFile)); | ||||
|     (*args.attrs)[state.symbols.create("derivations")] = manifest; | ||||
|     mkApp(topLevel, envBuilder, args); | ||||
|          | ||||
|     /* Evaluate it. */ | ||||
|     debug("evaluating user environment builder"); | ||||
|     DrvInfo topLevelDrv; | ||||
|     if (!getDerivation(state, topLevel, topLevelDrv)) | ||||
|         abort(); | ||||
|      | ||||
|     /* Realise the resulting store expression. */ | ||||
|     debug("building user environment"); | ||||
|     store->buildDerivations(singleton<PathSet>(topLevelDrv.queryDrvPath(state))); | ||||
| 
 | ||||
|     /* Switch the current user environment to the output path. */ | ||||
|     PathLocks lock; | ||||
|     lockProfile(lock, profile); | ||||
| 
 | ||||
|     Path lockTokenCur = optimisticLockProfile(profile); | ||||
|     if (lockToken != lockTokenCur) { | ||||
|         printMsg(lvlError, format("profile `%1%' changed while we were busy; restarting") % profile); | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     debug(format("switching to new user environment")); | ||||
|     Path generation = createGeneration(profile, topLevelDrv.queryOutPath(state)); | ||||
|     switchLink(profile, generation); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Code for parsing manifests in the old textual ATerm format. */ | ||||
| 
 | ||||
| static string parseStr(std::istream & str) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue