about summary refs log tree commit diff
path: root/src/nix-env
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-env')
-rw-r--r--src/nix-env/main.cc330
-rw-r--r--src/nix-env/profiles.cc2
-rw-r--r--src/nix-env/profiles.hh2
3 files changed, 171 insertions, 163 deletions
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
index fa07135fc09e..a9125001226f 100644
--- a/src/nix-env/main.cc
+++ b/src/nix-env/main.cc
@@ -45,7 +45,7 @@ typedef void (* Operation) (Globals & globals,
     Strings opFlags, Strings opArgs);
 
 
-struct DrvInfo
+struct UserEnvElem
 {
     string name;
     string system;
@@ -53,8 +53,7 @@ struct DrvInfo
     Path outPath;
 };
 
-typedef map<Path, DrvInfo> DrvInfos;
-typedef vector<DrvInfo> DrvInfoList;
+typedef map<Path, UserEnvElem> UserEnvElems;
 
 
 void printHelp()
@@ -63,7 +62,7 @@ void printHelp()
 }
 
 
-bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
+static bool parseDerivation(EvalState & state, Expr e, UserEnvElem & elem)
 {
     ATermList es;
     e = evalExpr(state, e);
@@ -73,54 +72,54 @@ bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
 
     a = queryAttr(e, "name");
     if (!a) throw badTerm("derivation name missing", e);
-    drv.name = evalString(state, a);
+    elem.name = evalString(state, a);
 
     a = queryAttr(e, "system");
     if (!a)
-        drv.system = "unknown";
+        elem.system = "unknown";
     else
-        drv.system = evalString(state, a);
+        elem.system = evalString(state, a);
 
     a = queryAttr(e, "drvPath");
-    if (a) drv.drvPath = evalPath(state, a);
+    if (a) elem.drvPath = evalPath(state, a);
 
     a = queryAttr(e, "outPath");
     if (!a) throw badTerm("output path missing", e);
-    drv.outPath = evalPath(state, a);
+    elem.outPath = evalPath(state, a);
 
     return true;
 }
 
 
-bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
+static bool parseDerivations(EvalState & state, Expr e, UserEnvElems & elems)
 {
     ATermList es;
-    DrvInfo drv;
+    UserEnvElem elem;
 
     e = evalExpr(state, e);
 
-    if (parseDerivation(state, e, drv)) 
-        drvs[drv.outPath] = drv;
+    if (parseDerivation(state, e, elem)) 
+        elems[elem.outPath] = elem;
 
     else if (matchAttrs(e, es)) {
         ATermMap drvMap;
         queryAllAttrs(e, drvMap);
         for (ATermIterator i(drvMap.keys()); i; ++i) {
             debug(format("evaluating attribute `%1%'") % *i);
-            if (parseDerivation(state, drvMap.get(*i), drv))
-                drvs[drv.outPath] = drv;
+            if (parseDerivation(state, drvMap.get(*i), elem))
+                elems[elem.outPath] = elem;
             else
-                parseDerivations(state, drvMap.get(*i), drvs);
+                parseDerivations(state, drvMap.get(*i), elems);
         }
     }
 
     else if (matchList(e, es)) {
         for (ATermIterator i(es); i; ++i) {
             debug(format("evaluating list element"));
-            if (parseDerivation(state, *i, drv))
-                drvs[drv.outPath] = drv;
+            if (parseDerivation(state, *i, elem))
+                elems[elem.outPath] = elem;
             else
-                parseDerivations(state, *i, drvs);
+                parseDerivations(state, *i, elems);
         }
     }
 
@@ -129,30 +128,18 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
 
 
 static void loadDerivations(EvalState & state, Path nixExprPath,
-    string systemFilter, DrvInfos & drvs)
+    string systemFilter, UserEnvElems & elems)
 {
     Expr e = parseExprFromFile(state, absPath(nixExprPath));
-    if (!parseDerivations(state, e, drvs))
+    if (!parseDerivations(state, e, elems))
         throw Error("set of derivations expected");
 
     /* Filter out all derivations not applicable to the current
        system. */
-    for (DrvInfos::iterator i = drvs.begin(), j; i != drvs.end(); i = j) {
+    for (UserEnvElems::iterator i = elems.begin(), j; i != elems.end(); i = j) {
         j = i; j++;
         if (systemFilter != "*" && i->second.system != systemFilter)
-            drvs.erase(i);
-    }
-}
-
-
-static void queryInstSources(EvalState & state,
-    const InstallSourceInfo & instSource, DrvInfos & drvs)
-{
-    switch (instSource.type) {
-        case srcUnknown:
-            loadDerivations(state, instSource.nixExprPath,
-                instSource.systemFilter, drvs);
-            break;
+            elems.erase(i);
     }
 }
 
@@ -184,7 +171,7 @@ struct AddPos : TermFun
 };
 
 
-void queryInstalled(EvalState & state, DrvInfos & drvs,
+static void queryInstalled(EvalState & state, UserEnvElems & elems,
     const Path & userEnv)
 {
     Path path = userEnv + "/manifest";
@@ -198,19 +185,19 @@ void queryInstalled(EvalState & state, DrvInfos & drvs,
     AddPos addPos;
     e = bottomupRewrite(addPos, e);
 
-    if (!parseDerivations(state, e, drvs))
+    if (!parseDerivations(state, e, elems))
         throw badTerm(format("set of derivations expected in `%1%'") % path, e);
 }
 
 
-void createUserEnv(EvalState & state, const DrvInfos & drvs,
+static void createUserEnv(EvalState & state, const UserEnvElems & elems,
     const Path & profile, bool keepDerivations)
 {
     /* Build the components in the user environment, if they don't
        exist already. */
     PathSet drvsToBuild;
-    for (DrvInfos::const_iterator i = drvs.begin(); 
-         i != drvs.end(); ++i)
+    for (UserEnvElems::const_iterator i = elems.begin(); 
+         i != elems.end(); ++i)
         if (i->second.drvPath != "")
             drvsToBuild.insert(i->second.drvPath);
 
@@ -225,8 +212,8 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
     PathSet references;
     ATermList manifest = ATempty;
     ATermList inputs = ATempty;
-    for (DrvInfos::const_iterator i = drvs.begin(); 
-         i != drvs.end(); ++i)
+    for (UserEnvElems::const_iterator i = elems.begin(); 
+         i != elems.end(); ++i)
     {
         Path drvPath = keepDerivations ? i->second.drvPath : "";
         ATerm t = makeAttrs(ATmakeList5(
@@ -268,7 +255,7 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
 
     /* Instantiate it. */
     debug(format("evaluating builder expression `%1%'") % topLevel);
-    DrvInfo topLevelDrv;
+    UserEnvElem topLevelDrv;
     if (!parseDerivation(state, topLevel, topLevelDrv))
         abort();
     
@@ -278,67 +265,104 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
 
     /* Switch the current user environment to the output path. */
     debug(format("switching to new user environment"));
-    Path generation = createGeneration(profile,
-        topLevelDrv.outPath, topLevelDrv.drvPath);
+    Path generation = createGeneration(profile, topLevelDrv.outPath);
     switchLink(profile, generation);
 }
 
 
-static void installDerivations(Globals & globals,
-    DrvNames & selectors, const Path & profile)
+static void queryInstSources(EvalState & state,
+    const InstallSourceInfo & instSource, const Strings & args,
+    UserEnvElems & elems)
 {
-    debug(format("installing derivations"));
+    switch (instSource.type) {
 
-    /* Fetch all derivations from the input file. */
-    DrvInfos availDrvs;
-    queryInstSources(globals.state, globals.instSource, availDrvs);
-
-    /* Filter out the ones we're not interested in. */
-    DrvInfos selectedDrvs;
-    StringSet selectedNames;
-    for (DrvInfos::iterator i = availDrvs.begin();
-         i != availDrvs.end(); ++i)
-    {
-        DrvName drvName(i->second.name);
-        for (DrvNames::iterator j = selectors.begin();
-             j != selectors.end(); ++j)
-        {
-            if (j->matches(drvName)) {
-                printMsg(lvlInfo,
-                    format("installing `%1%'") % i->second.name);
-                j->hits++;
-                selectedDrvs.insert(*i);
-                selectedNames.insert(drvName.name);
+        /* Get the available user environment elements from the
+           derivations specified in a Nix expression, including only
+           those with names matching any of the names in `args'. */
+        case srcUnknown:
+        case srcNixExprDrvs: {
+
+            DrvNames selectors = drvNamesFromArgs(args);
+
+            /* Load the derivations from the (default or specified)
+               Nix expression. */
+            UserEnvElems allElems;
+            loadDerivations(state, instSource.nixExprPath,
+                instSource.systemFilter, allElems);
+
+            /* Filter out the ones we're not interested in. */
+            for (UserEnvElems::iterator i = allElems.begin();
+                 i != allElems.end(); ++i)
+            {
+                DrvName drvName(i->second.name);
+                for (DrvNames::iterator j = selectors.begin();
+                     j != selectors.end(); ++j)
+                {
+                    if (j->matches(drvName)) {
+                        j->hits++;
+                        elems.insert(*i);
+                    }
+                }
             }
+            
+            /* Check that all selectors have been used. */
+            for (DrvNames::iterator i = selectors.begin();
+                 i != selectors.end(); ++i)
+                if (i->hits == 0)
+                    throw Error(format("selector `%1%' matches no derivations")
+                        % i->fullName);
+    
+            break;
         }
+
+        case srcNixExprs:
+            break;
+
+        case srcStorePaths:
+            break;
+
+        case srcProfile:
+            break;
     }
+}
 
-    /* Check that all selectors have been used. */
-    for (DrvNames::iterator i = selectors.begin();
-         i != selectors.end(); ++i)
-        if (i->hits == 0)
-            throw Error(format("selector `%1%' matches no derivations")
-                % i->fullName);
-    
-    /* Add in the already installed derivations. */
-    DrvInfos installedDrvs;
-    queryInstalled(globals.state, installedDrvs, profile);
 
-    for (DrvInfos::iterator i = installedDrvs.begin();
-         i != installedDrvs.end(); ++i)
+static void installDerivations(Globals & globals,
+    const Strings & args, const Path & profile)
+{
+    debug(format("installing derivations"));
+
+    /* Get the set of user environment elements to be installed. */
+    UserEnvElems newElems;
+    queryInstSources(globals.state, globals.instSource, args, newElems);
+
+    StringSet newNames;
+    for (UserEnvElems::iterator i = newElems.begin(); i != newElems.end(); ++i) {
+        printMsg(lvlInfo,
+            format("installing `%1%'") % i->second.name);
+        newNames.insert(DrvName(i->second.name).name);
+    }
+
+    /* Add in the already installed derivations, unless they have the
+       same name as a to-be-installed element. */
+    UserEnvElems installedElems;
+    queryInstalled(globals.state, installedElems, profile);
+
+    for (UserEnvElems::iterator i = installedElems.begin();
+         i != installedElems.end(); ++i)
     {
         DrvName drvName(i->second.name);
         if (!globals.preserveInstalled &&
-            selectedNames.find(drvName.name) != selectedNames.end())
+            newNames.find(drvName.name) != newNames.end())
             printMsg(lvlInfo,
                 format("uninstalling `%1%'") % i->second.name);
         else
-            selectedDrvs.insert(*i);
+            newElems.insert(*i);
     }
 
     if (globals.dryRun) return;
 
-    createUserEnv(globals.state, selectedDrvs,
+    createUserEnv(globals.state, newElems,
         profile, globals.keepDerivations);
 }
 
@@ -349,9 +373,7 @@ static void opInstall(Globals & globals,
     if (opFlags.size() > 0)
         throw UsageError(format("unknown flags `%1%'") % opFlags.front());
 
-    DrvNames drvNames = drvNamesFromArgs(opArgs);
-    
-    installDerivations(globals, drvNames, globals.profile);
+    installDerivations(globals, opArgs, globals.profile);
 }
 
 
@@ -359,7 +381,7 @@ typedef enum { utLt, utLeq, utAlways } UpgradeType;
 
 
 static void upgradeDerivations(Globals & globals,
-    DrvNames & selectors, const Path & profile,
+    const Strings & args, const Path & profile,
     UpgradeType upgradeType)
 {
     debug(format("upgrading derivations"));
@@ -370,47 +392,28 @@ static void upgradeDerivations(Globals & globals,
        name and a higher version number. */
 
     /* Load the currently installed derivations. */
-    DrvInfos installedDrvs;
-    queryInstalled(globals.state, installedDrvs, profile);
+    UserEnvElems installedElems;
+    queryInstalled(globals.state, installedElems, profile);
 
     /* Fetch all derivations from the input file. */
-    DrvInfos availDrvs;
-    queryInstSources(globals.state, globals.instSource, availDrvs);
+    UserEnvElems availElems;
+    queryInstSources(globals.state, globals.instSource, args, availElems);
 
     /* Go through all installed derivations. */
-    DrvInfos newDrvs;
-    for (DrvInfos::iterator i = installedDrvs.begin();
-         i != installedDrvs.end(); ++i)
+    UserEnvElems newElems;
+    for (UserEnvElems::iterator i = installedElems.begin();
+         i != installedElems.end(); ++i)
     {
         DrvName drvName(i->second.name);
-        DrvName selector;
 
-        /* Do we want to upgrade this derivation? */
-        bool upgrade = false;
-        for (DrvNames::iterator j = selectors.begin();
-             j != selectors.end(); ++j)
-        {
-            if (j->name == "*" || j->name == drvName.name) {
-                j->hits++;
-                selector = *j;
-                upgrade = true;
-                break;
-            }
-        }
-
-        if (!upgrade) {
-            newDrvs.insert(*i);
-            continue;
-        }
-            
-        /* If yes, find the derivation in the input Nix expression
-           with the same name and satisfying the version constraints
-           specified by upgradeType.  If there are multiple matches,
-           take the one with highest version. */
-        DrvInfos::iterator bestDrv = availDrvs.end();
+        /* Find the derivation in the input Nix expression with the
+           same name and satisfying the version constraints specified
+           by upgradeType.  If there are multiple matches, take the
+           one with highest version. */
+        UserEnvElems::iterator bestElem = availElems.end();
         DrvName bestName;
-        for (DrvInfos::iterator j = availDrvs.begin();
-             j != availDrvs.end(); ++j)
+        for (UserEnvElems::iterator j = availElems.begin();
+             j != availElems.end(); ++j)
         {
             DrvName newName(j->second.name);
             if (newName.name == drvName.name) {
@@ -419,31 +422,30 @@ static void upgradeDerivations(Globals & globals,
                     upgradeType == utLeq && d <= 0 ||
                     upgradeType == utAlways)
                 {
-                    if (selector.matches(newName) &&
-                        (bestDrv == availDrvs.end() ||
+                    if ((bestElem == availElems.end() ||
                          compareVersions(
                              bestName.version, newName.version) < 0))
                     {
-                        bestDrv = j;
+                        bestElem = j;
                         bestName = newName;
                     }
                 }
             }
         }
 
-        if (bestDrv != availDrvs.end() &&
-            i->second.drvPath != bestDrv->second.drvPath)
+        if (bestElem != availElems.end() &&
+            i->second.outPath != bestElem->second.outPath)
         {
             printMsg(lvlInfo,
                 format("upgrading `%1%' to `%2%'")
-                % i->second.name % bestDrv->second.name);
-            newDrvs.insert(*bestDrv);
-        } else newDrvs.insert(*i);
+                % i->second.name % bestElem->second.name);
+            newElems.insert(*bestElem);
+        } else newElems.insert(*i);
     }
     
     if (globals.dryRun) return;
 
-    createUserEnv(globals.state, newDrvs,
+    createUserEnv(globals.state, newElems,
         profile, globals.keepDerivations);
 }
 
@@ -459,20 +461,18 @@ static void opUpgrade(Globals & globals,
         else if (*i == "--always") upgradeType = utAlways;
         else throw UsageError(format("unknown flag `%1%'") % *i);
 
-    DrvNames drvNames = drvNamesFromArgs(opArgs);
-    
-    upgradeDerivations(globals, drvNames, globals.profile, upgradeType);
+    upgradeDerivations(globals, opArgs, globals.profile, upgradeType);
 }
 
 
 static void uninstallDerivations(Globals & globals, DrvNames & selectors,
     Path & profile)
 {
-    DrvInfos installedDrvs;
-    queryInstalled(globals.state, installedDrvs, profile);
+    UserEnvElems installedElems;
+    queryInstalled(globals.state, installedElems, profile);
 
-    for (DrvInfos::iterator i = installedDrvs.begin();
-         i != installedDrvs.end(); ++i)
+    for (UserEnvElems::iterator i = installedElems.begin();
+         i != installedElems.end(); ++i)
     {
         DrvName drvName(i->second.name);
         for (DrvNames::iterator j = selectors.begin();
@@ -480,13 +480,13 @@ static void uninstallDerivations(Globals & globals, DrvNames & selectors,
             if (j->matches(drvName)) {
                 printMsg(lvlInfo,
                     format("uninstalling `%1%'") % i->second.name);
-                installedDrvs.erase(i);
+                installedElems.erase(i);
             }
     }
 
     if (globals.dryRun) return;
 
-    createUserEnv(globals.state, installedDrvs,
+    createUserEnv(globals.state, installedElems,
         profile, globals.keepDerivations);
 }
 
@@ -510,7 +510,7 @@ static bool cmpChars(char a, char b)
 }
 
 
-static bool cmpDrvByName(const DrvInfo & a, const DrvInfo & b)
+static bool cmpElemByName(const UserEnvElem & a, const UserEnvElem & b)
 {
     return lexicographical_compare(
         a.name.begin(), a.name.end(),
@@ -575,17 +575,17 @@ static void opQuery(Globals & globals,
         else throw UsageError(format("unknown flag `%1%'") % *i);
 
     /* Obtain derivation information from the specified source. */
-    DrvInfos drvs;
+    UserEnvElems elems;
 
     switch (source) {
 
         case sInstalled:
-            queryInstalled(globals.state, drvs, globals.profile);
+            queryInstalled(globals.state, elems, globals.profile);
             break;
 
         case sAvailable: {
             loadDerivations(globals.state, globals.instSource.nixExprPath,
-                globals.instSource.systemFilter, drvs);
+                globals.instSource.systemFilter, elems);
             break;
         }
 
@@ -595,14 +595,14 @@ static void opQuery(Globals & globals,
     if (opArgs.size() != 0) throw UsageError("no arguments expected");
 
     /* Sort them by name. */
-    DrvInfoList drvs2;
-    for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i)
-        drvs2.push_back(i->second);
-    sort(drvs2.begin(), drvs2.end(), cmpDrvByName);
+    vector<UserEnvElem> elems2;
+    for (UserEnvElems::iterator i = elems.begin(); i != elems.end(); ++i)
+        elems2.push_back(i->second);
+    sort(elems2.begin(), elems2.end(), cmpElemByName);
 
     /* We only need to know the installed paths when we are querying
        the status of the derivation. */
-    DrvInfos installed; /* installed paths */
+    UserEnvElems installed; /* installed paths */
     
     if (printStatus)
         queryInstalled(globals.state, installed, globals.profile);
@@ -610,8 +610,9 @@ static void opQuery(Globals & globals,
     /* Print the desired columns. */
     Table table;
     
-    for (DrvInfoList::iterator i = drvs2.begin(); i != drvs2.end(); ++i) {
-
+    for (vector<UserEnvElem>::iterator i = elems2.begin();
+         i != elems2.end(); ++i)
+    {
         Strings columns;
         
         if (printStatus) {
@@ -794,6 +795,16 @@ static void opDefaultExpr(Globals & globals,
 }
 
 
+static string needArg(Strings::iterator & i,
+    const Strings & args, const string & arg)
+{
+    ++i;
+    if (i == args.end()) throw UsageError(
+        format("`%1%' requires an argument") % arg);
+    return *i;
+}
+
+
 void run(Strings args)
 {
     Strings opFlags, opArgs;
@@ -818,6 +829,12 @@ void run(Strings args)
 
         if (arg == "--install" || arg == "-i")
             op = opInstall;
+        else if (arg == "--from-expression" || arg == "-E")
+            globals.instSource.type = srcNixExprs;
+        else if (arg == "--from-profile") {
+            globals.instSource.type = srcProfile;
+            globals.instSource.profile = needArg(i, args, arg);
+        }
         else if (arg == "--uninstall" || arg == "-e")
             op = opUninstall;
         else if (arg == "--upgrade" || arg == "-u")
@@ -827,16 +844,10 @@ void run(Strings args)
         else if (arg == "--import" || arg == "-I") /* !!! bad name */
             op = opDefaultExpr;
         else if (arg == "--profile" || arg == "-p") {
-            ++i;
-            if (i == args.end()) throw UsageError(
-                format("`%1%' requires an argument") % arg);
-            globals.profile = absPath(*i);
+            globals.profile = absPath(needArg(i, args, arg));
         }
         else if (arg == "--file" || arg == "-f") {
-            ++i;
-            if (i == args.end()) throw UsageError(
-                format("`%1%' requires an argument") % arg);
-            globals.instSource.nixExprPath = absPath(*i);
+            globals.instSource.nixExprPath = absPath(needArg(i, args, arg));
         }
         else if (arg == "--switch-profile" || arg == "-S")
             op = opSwitchProfile;
@@ -855,10 +866,7 @@ void run(Strings args)
         else if (arg == "--preserve-installed" || arg == "-P")
             globals.preserveInstalled = true;
         else if (arg == "--system-filter") {
-            ++i;
-            if (i == args.end()) throw UsageError(
-                format("`%1%' requires an argument") % arg);
-            globals.instSource.systemFilter = *i;
+            globals.instSource.systemFilter = needArg(i, args, arg);
         }
         else if (arg[0] == '-')
             opFlags.push_back(arg);
diff --git a/src/nix-env/profiles.cc b/src/nix-env/profiles.cc
index 52144eb2f69d..1039634d60ac 100644
--- a/src/nix-env/profiles.cc
+++ b/src/nix-env/profiles.cc
@@ -69,7 +69,7 @@ static void makeName(const Path & profile, unsigned int num,
 }
 
 
-Path createGeneration(Path profile, Path outPath, Path drvPath)
+Path createGeneration(Path profile, Path outPath)
 {
     /* The new generation number should be higher than old the
        previous ones. */
diff --git a/src/nix-env/profiles.hh b/src/nix-env/profiles.hh
index 58e45835eab4..dc27d1c83de8 100644
--- a/src/nix-env/profiles.hh
+++ b/src/nix-env/profiles.hh
@@ -28,7 +28,7 @@ typedef list<Generation> Generations;
    profile, sorted by generation number. */
 Generations findGenerations(Path profile, int & curGen);
     
-Path createGeneration(Path profile, Path outPath, Path drvPath);
+Path createGeneration(Path profile, Path outPath);
 
 void deleteGeneration(const Path & profile, unsigned int gen);