LTP GCOV extension - code coverage report
Current view: directory - src/nix-env - main.cc
Test: app.info
Date: 2006-10-11 Instrumented lines: 565
Code covered: 69.2 % Executed lines: 391

       1                 : #include "profiles.hh"
       2                 : #include "names.hh"
       3                 : #include "globals.hh"
       4                 : #include "build.hh"
       5                 : #include "misc.hh"
       6                 : #include "gc.hh"
       7                 : #include "shared.hh"
       8                 : #include "parser.hh"
       9                 : #include "eval.hh"
      10                 : #include "help.txt.hh"
      11                 : #include "nixexpr-ast.hh"
      12                 : #include "get-drvs.hh"
      13                 : #include "attr-path.hh"
      14                 : #include "pathlocks.hh"
      15                 : #include "xml-writer.hh"
      16                 : #include "store.hh"
      17                 : #include "db.hh"
      18                 : #include "util.hh"
      19                 : 
      20                 : #include <cerrno>
      21                 : #include <ctime>
      22                 : #include <algorithm>
      23                 : #include <iostream>
      24                 : #include <sstream>
      25                 : 
      26                 : #include <unistd.h>
      27                 : 
      28                 : 
      29                 : using namespace nix;
      30                 : using std::cout;
      31                 : 
      32                 : 
      33                 : typedef enum {
      34                 :     srcNixExprDrvs,
      35                 :     srcNixExprs,
      36                 :     srcStorePaths,
      37                 :     srcProfile,
      38                 :     srcAttrPath,
      39                 :     srcUnknown
      40                 : } InstallSourceType;
      41                 : 
      42                 : 
      43                 : struct InstallSourceInfo
      44                 : {
      45                 :     InstallSourceType type;
      46                 :     Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
      47                 :     Path profile; /* for srcProfile */
      48                 :     string systemFilter; /* for srcNixExprDrvs */
      49                 :     ATermMap autoArgs;
      50             100 :     InstallSourceInfo() : autoArgs(128) { };
      51                 : };
      52                 : 
      53                 : 
      54                 : struct Globals
      55                 : {
      56                 :     InstallSourceInfo instSource;
      57                 :     Path profile;
      58                 :     EvalState state;
      59                 :     bool dryRun;
      60                 :     bool preserveInstalled;
      61                 :     bool keepDerivations;
      62                 :     string forceName;
      63                 : };
      64                 : 
      65                 : 
      66                 : typedef void (* Operation) (Globals & globals,
      67                 :     Strings opFlags, Strings opArgs);
      68                 : 
      69                 : 
      70                 : void printHelp()
      71               1 : {
      72               1 :     cout << string((char *) helpText, sizeof helpText);
      73                 : }
      74                 : 
      75                 : 
      76                 : static void loadDerivations(EvalState & state, Path nixExprPath,
      77                 :     string systemFilter, const ATermMap & autoArgs, DrvInfos & elems)
      78              10 : {
      79              10 :     getDerivations(state,
      80                 :         parseExprFromFile(state, absPath(nixExprPath)), "", autoArgs, elems);
      81                 : 
      82                 :     /* Filter out all derivations not applicable to the current
      83                 :        system. */
      84              56 :     for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) {
      85              46 :         j = i; j++;
      86              46 :         if (systemFilter != "*" && i->system != systemFilter)
      87               0 :             elems.erase(i);
      88                 :     }
      89                 : }
      90                 : 
      91                 : 
      92                 : static Path getHomeDir()
      93              51 : {
      94              51 :     Path homeDir(getEnv("HOME", ""));
      95            2457 :     if (homeDir == "") throw Error("HOME environment variable not set");
      96               0 :     return homeDir;
      97                 : }
      98                 : 
      99                 : 
     100                 : static Path getDefNixExprPath()
     101              50 : {
     102              50 :     return getHomeDir() + "/.nix-defexpr";
     103                 : }
     104                 : 
     105                 : 
     106                 : struct AddPos : TermFun
     107                 : {
     108                 :     ATerm operator () (ATerm e)
     109            1071 :     {
     110            1071 :         ATerm x, y, z;
     111            1071 :         if (matchBind(e, x, y, z)) return e;
     112             886 :         if (matchBind2(e, x, y))
     113               0 :             return makeBind(x, y, makeNoPos());
     114             886 :         return e;
     115                 :     }
     116             204 : };
     117                 : 
     118                 : 
     119                 : static DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
     120              41 : {
     121              41 :     Path path = userEnv + "/manifest";
     122                 : 
     123              41 :     if (!pathExists(path))
     124             439 :         return DrvInfos(); /* not an error, assume nothing installed */
     125                 : 
     126              36 :     Expr e = ATreadFromNamedFile(path.c_str());
     127              36 :     if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path);
     128                 : 
     129                 :     /* Compatibility: Bind(x, y) -> Bind(x, y, NoPos). */
     130             252 :     AddPos addPos;
     131              36 :     e = bottomupRewrite(addPos, e);
     132                 : 
     133              36 :     DrvInfos elems;
     134              36 :     getDerivations(state, e, "", ATermMap(1), elems);
     135              36 :     return elems;
     136                 : }
     137                 : 
     138                 : 
     139                 : static void createUserEnv(EvalState & state, const DrvInfos & elems,
     140                 :     const Path & profile, bool keepDerivations)
     141              16 : {
     142                 :     /* Build the components in the user environment, if they don't
     143                 :        exist already. */
     144            2002 :     PathSet drvsToBuild;
     145              31 :     for (DrvInfos::const_iterator i = elems.begin(); 
     146                 :          i != elems.end(); ++i)
     147                 :         /* Call to `isDerivation' is for compatibility with Nix <= 0.7
     148                 :            user environments. */
     149              15 :         if (i->queryDrvPath(state) != "" &&
     150                 :             isDerivation(i->queryDrvPath(state)))
     151              10 :             drvsToBuild.insert(i->queryDrvPath(state));
     152                 : 
     153              16 :     debug(format("building user environment dependencies"));
     154              16 :     buildDerivations(drvsToBuild);
     155                 : 
     156                 :     /* Get the environment builder expression. */
     157                 :     Expr envBuilder = parseExprFromFile(state,
     158              16 :         nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */
     159                 : 
     160                 :     /* Construct the whole top level derivation. */
     161              16 :     PathSet references;
     162              16 :     ATermList manifest = ATempty;
     163              16 :     ATermList inputs = ATempty;
     164              31 :     for (DrvInfos::const_iterator i = elems.begin(); 
     165                 :          i != elems.end(); ++i)
     166                 :     {
     167              15 :         Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
     168              15 :         ATerm t = makeAttrs(ATmakeList5(
     169                 :             makeBind(toATerm("type"),
     170                 :                 makeStr(toATerm("derivation")), makeNoPos()),
     171                 :             makeBind(toATerm("name"),
     172                 :                 makeStr(toATerm(i->name)), makeNoPos()),
     173                 :             makeBind(toATerm("system"),
     174                 :                 makeStr(toATerm(i->system)), makeNoPos()),
     175                 :             makeBind(toATerm("drvPath"),
     176                 :                 makePath(toATerm(drvPath)), makeNoPos()),
     177                 :             makeBind(toATerm("outPath"),
     178                 :                 makePath(toATerm(i->queryOutPath(state))), makeNoPos())
     179                 :             ));
     180              15 :         manifest = ATinsert(manifest, t);
     181              15 :         inputs = ATinsert(inputs, makeStr(toATerm(i->queryOutPath(state))));
     182                 : 
     183                 :         /* This is only necessary when installing store paths, e.g.,
     184                 :            `nix-env -i /nix/store/abcd...-foo'. */
     185              15 :         addTempRoot(i->queryOutPath(state));
     186              15 :         ensurePath(i->queryOutPath(state));
     187                 :         
     188              15 :         references.insert(i->queryOutPath(state));
     189              15 :         if (drvPath != "") references.insert(drvPath);
     190                 :     }
     191                 : 
     192                 :     /* Also write a copy of the list of inputs to the store; we need
     193                 :        it for future modifications of the environment. */
     194                 :     Path manifestFile = addTextToStore("env-manifest",
     195              16 :         atPrint(makeList(ATreverse(manifest))), references);
     196                 : 
     197              16 :     Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
     198                 :         makeBind(toATerm("system"),
     199                 :             makeStr(toATerm(thisSystem)), makeNoPos()),
     200                 :         makeBind(toATerm("derivations"),
     201                 :             makeList(ATreverse(inputs)), makeNoPos()),
     202                 :         makeBind(toATerm("manifest"),
     203                 :             makePath(toATerm(manifestFile)), makeNoPos())
     204                 :         )));
     205                 : 
     206                 :     /* Instantiate it. */
     207              16 :     debug(format("evaluating builder expression `%1%'") % topLevel);
     208            3106 :     DrvInfo topLevelDrv;
     209              16 :     if (!getDerivation(state, topLevel, topLevelDrv))
     210               0 :         abort();
     211                 :     
     212                 :     /* Realise the resulting store expression. */
     213              16 :     debug(format("building user environment"));
     214              16 :     buildDerivations(singleton<PathSet>(topLevelDrv.queryDrvPath(state)));
     215                 : 
     216                 :     /* Switch the current user environment to the output path. */
     217              15 :     debug(format("switching to new user environment"));
     218              15 :     Path generation = createGeneration(profile, topLevelDrv.queryOutPath(state));
     219              15 :     switchLink(profile, generation);
     220                 : }
     221                 : 
     222                 : 
     223                 : static DrvInfos filterBySelector(EvalState & state,
     224                 :     const DrvInfos & allElems,
     225                 :     const Strings & args, bool newestOnly)
     226              35 : {
     227             115 :     DrvNames selectors = drvNamesFromArgs(args);
     228                 : 
     229              35 :     DrvInfos elems;
     230             105 :     set<unsigned int> done;
     231                 : 
     232              71 :     for (DrvNames::iterator i = selectors.begin();
     233                 :          i != selectors.end(); ++i)
     234                 :     {
     235                 :         typedef list<std::pair<DrvInfo, unsigned int> > Matches;
     236             108 :         Matches matches;
     237              36 :         unsigned int n = 0;
     238             115 :         for (DrvInfos::const_iterator j = allElems.begin();
     239                 :              j != allElems.end(); ++j, ++n)
     240                 :         {
     241             489 :             DrvName drvName(j->name);
     242              79 :             if (i->matches(drvName)) {
     243              55 :                 i->hits++;
     244            2359 :                 matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n));
     245                 :             }
     246                 :         }
     247                 : 
     248                 :         /* If `newestOnly', if a selector matches multiple derivations
     249                 :            with the same name, pick the one with the highest version.
     250                 :            If there are multiple derivations with the same name *and*
     251                 :            version, then pick the first one. */
     252              36 :         if (newestOnly) {
     253                 : 
     254                 :             /* Map from package names to derivations. */
     255                 :             typedef map<string, std::pair<DrvInfo, unsigned int> > Newest;
     256              24 :             Newest newest;
     257               8 :             StringSet multiple;
     258                 : 
     259              22 :             for (Matches::iterator j = matches.begin(); j != matches.end(); ++j) {
     260              14 :                 DrvName drvName(j->first.name);
     261              14 :                 Newest::iterator k = newest.find(drvName.name);
     262              14 :                 if (k != newest.end()) {
     263               5 :                     int d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
     264             143 :                     if (d > 0) newest[drvName.name] = *j;
     265               0 :                     else if (d == 0) multiple.insert(j->first.name);
     266                 :                 } else
     267               9 :                     newest[drvName.name] = *j;
     268                 :             }
     269                 : 
     270               8 :             matches.clear();
     271              17 :             for (Newest::iterator j = newest.begin(); j != newest.end(); ++j) {
     272               9 :                 if (multiple.find(j->second.first.name) != multiple.end())
     273               0 :                     printMsg(lvlInfo,
     274                 :                         format("warning: there are multiple derivations named `%1%'; using the first one")
     275                 :                         % j->second.first.name);
     276               9 :                 matches.push_back(j->second);
     277                 :             }
     278                 :         }
     279                 : 
     280                 :         /* Insert only those elements in the final list that we
     281                 :            haven't inserted before. */
     282              86 :         for (Matches::iterator j = matches.begin(); j != matches.end(); ++j)
     283              50 :             if (done.find(j->second) == done.end()) {
     284              50 :                 done.insert(j->second);
     285              50 :                 elems.push_back(j->first);
     286                 :             }
     287                 :     }
     288                 :             
     289                 :     /* Check that all selectors have been used. */
     290              69 :     for (DrvNames::iterator i = selectors.begin();
     291                 :          i != selectors.end(); ++i)
     292              36 :         if (i->hits == 0)
     293               2 :             throw Error(format("selector `%1%' matches no derivations")
     294                 :                 % i->fullName);
     295                 : 
     296              33 :     return elems;
     297                 : }
     298                 : 
     299                 : 
     300                 : static void queryInstSources(EvalState & state,
     301                 :     const InstallSourceInfo & instSource, const Strings & args,
     302                 :     DrvInfos & elems, bool newestOnly)
     303              11 : {
     304              11 :     InstallSourceType type = instSource.type;
     305              11 :     if (type == srcUnknown && args.size() > 0 && args.front()[0] == '/')
     306               3 :         type = srcStorePaths;
     307                 :     
     308              11 :     switch (type) {
     309                 : 
     310                 :         /* Get the available user environment elements from the
     311                 :            derivations specified in a Nix expression, including only
     312                 :            those with names matching any of the names in `args'. */
     313                 :         case srcUnknown:
     314                 :         case srcNixExprDrvs: {
     315                 : 
     316                 :             /* Load the derivations from the (default or specified)
     317                 :                Nix expression. */
     318               8 :             DrvInfos allElems;
     319               8 :             loadDerivations(state, instSource.nixExprPath,
     320                 :                 instSource.systemFilter, instSource.autoArgs, allElems);
     321                 : 
     322               8 :             elems = filterBySelector(state, allElems, args, newestOnly);
     323                 :     
     324               8 :             break;
     325                 :         }
     326                 : 
     327                 :         /* Get the available user environment elements from the Nix
     328                 :            expressions specified on the command line; these should be
     329                 :            functions that take the default Nix expression file as
     330                 :            argument, e.g., if the file is `./foo.nix', then the
     331                 :            argument `x: x.bar' is equivalent to `(x: x.bar)
     332                 :            (import ./foo.nix)' = `(import ./foo.nix).bar'. */
     333                 :         case srcNixExprs: {
     334                 :                 
     335                 : 
     336                 :             Expr e1 = parseExprFromFile(state,
     337               0 :                 absPath(instSource.nixExprPath));
     338                 : 
     339               0 :             for (Strings::const_iterator i = args.begin();
     340                 :                  i != args.end(); ++i)
     341                 :             {
     342               0 :                 Expr e2 = parseExprFromString(state, *i, absPath("."));
     343               0 :                 Expr call = makeCall(e2, e1);
     344               0 :                 getDerivations(state, call, "", instSource.autoArgs, elems);
     345                 :             }
     346                 :             
     347               3 :             break;
     348                 :         }
     349                 :             
     350                 :         /* The available user environment elements are specified as a
     351                 :            list of store paths (which may or may not be
     352                 :            derivations). */
     353                 :         case srcStorePaths: {
     354                 : 
     355               6 :             for (Strings::const_iterator i = args.begin();
     356                 :                  i != args.end(); ++i)
     357                 :             {
     358               3 :                 assertStorePath(*i);
     359                 : 
     360               3 :                 DrvInfo elem;
     361               3 :                 elem.attrs = boost::shared_ptr<ATermMap>(new ATermMap(0)); /* ugh... */
     362               3 :                 string name = baseNameOf(*i);
     363               3 :                 string::size_type dash = name.find('-');
     364               3 :                 if (dash != string::npos)
     365               3 :                     name = string(name, dash + 1);
     366                 : 
     367               3 :                 if (isDerivation(*i)) {
     368               0 :                     elem.setDrvPath(*i);
     369            5836 :                     elem.setOutPath(findOutput(derivationFromPath(*i), "out"));
     370               0 :                     if (name.size() >= drvExtension.size() &&
     371                 :                         string(name, name.size() - drvExtension.size()) == drvExtension)
     372               0 :                         name = string(name, 0, name.size() - drvExtension.size());
     373                 :                 }
     374               3 :                 else elem.setOutPath(*i);
     375                 : 
     376               3 :                 elem.name = name;
     377                 : 
     378               3 :                 elems.push_back(elem);
     379                 :             }
     380                 :             
     381               0 :             break;
     382                 :         }
     383                 :             
     384                 :         /* Get the available user environment elements from another
     385                 :            user environment.  These are then filtered as in the
     386                 :            `srcNixExprDrvs' case. */
     387                 :         case srcProfile: {
     388               0 :             elems = filterBySelector(state,
     389                 :                 queryInstalled(state, instSource.profile),
     390                 :                 args, newestOnly);
     391               0 :             break;
     392                 :         }
     393                 : 
     394                 :         case srcAttrPath: {
     395               0 :             for (Strings::const_iterator i = args.begin();
     396                 :                  i != args.end(); ++i)
     397               0 :                 getDerivations(state,
     398                 :                     findAlongAttrPath(state, *i, instSource.autoArgs,
     399                 :                         parseExprFromFile(state, instSource.nixExprPath)),
     400                 :                     "", instSource.autoArgs, elems);
     401              11 :             break;
     402                 :         }
     403                 :     }
     404                 : }
     405                 : 
     406                 : 
     407                 : static void printMissing(EvalState & state, const DrvInfos & elems)
     408               0 : {
     409               0 :     PathSet targets, willBuild, willSubstitute;
     410               0 :     for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) {
     411               0 :         Path drvPath = i->queryDrvPath(state);
     412               0 :         if (drvPath != "")
     413               0 :             targets.insert(drvPath);
     414                 :         else
     415               0 :             targets.insert(i->queryOutPath(state));
     416                 :     }
     417                 : 
     418               0 :     queryMissing(targets, willBuild, willSubstitute);
     419                 : 
     420               0 :     if (!willBuild.empty()) {
     421               0 :         printMsg(lvlInfo, format("the following derivations will be built:"));
     422               0 :         for (PathSet::iterator i = willBuild.begin(); i != willBuild.end(); ++i)
     423               0 :             printMsg(lvlInfo, format("  %1%") % *i);
     424                 :     }
     425                 : 
     426               0 :     if (!willSubstitute.empty()) {
     427               0 :         printMsg(lvlInfo, format("the following paths will be substituted:"));
     428               0 :         for (PathSet::iterator i = willSubstitute.begin(); i != willSubstitute.end(); ++i)
     429               0 :             printMsg(lvlInfo, format("  %1%") % *i);
     430                 :     }
     431                 : }
     432                 : 
     433                 : 
     434                 : static void lockProfile(PathLocks & lock, const Path & profile)
     435              21 : {
     436              21 :     lock.lockPaths(singleton<PathSet>(profile),
     437                 :         (format("waiting for lock on profile `%1%'") % profile).str());
     438              21 :     lock.setDeletion(true);
     439                 : }
     440                 : 
     441                 : 
     442                 : static void installDerivations(Globals & globals,
     443                 :     const Strings & args, const Path & profile)
     444              10 : {
     445              10 :     debug(format("installing derivations"));
     446                 : 
     447                 :     /* Get the set of user environment elements to be installed. */
     448              10 :     DrvInfos newElems;
     449              10 :     queryInstSources(globals.state, globals.instSource, args, newElems, true);
     450                 : 
     451              10 :     StringSet newNames;
     452              22 :     for (DrvInfos::iterator i = newElems.begin(); i != newElems.end(); ++i) {
     453                 :         /* `forceName' is a hack to get package names right in some
     454                 :            one-click installs, namely those where the name used in the
     455                 :            path is not the one we want (e.g., `java-front' versus
     456                 :            `java-front-0.9pre15899'). */
     457              12 :         if (globals.forceName != "")
     458               2 :             i->name = globals.forceName;
     459              12 :         newNames.insert(DrvName(i->name).name);
     460                 :     }
     461                 : 
     462                 :     /* Add in the already installed derivations, unless they have the
     463                 :        same name as a to-be-installed element. */
     464              10 :     PathLocks lock;
     465              10 :     lockProfile(lock, profile);
     466              10 :     DrvInfos installedElems = queryInstalled(globals.state, profile);
     467                 : 
     468              10 :     DrvInfos allElems(newElems);
     469              13 :     for (DrvInfos::iterator i = installedElems.begin();
     470                 :          i != installedElems.end(); ++i)
     471                 :     {
     472               3 :         DrvName drvName(i->name);
     473               3 :         if (!globals.preserveInstalled &&
     474                 :             newNames.find(drvName.name) != newNames.end())
     475               2 :             printMsg(lvlInfo,
     476                 :                 format("replacing old `%1%'") % i->name);
     477                 :         else
     478               1 :             allElems.push_back(*i);
     479                 :     }
     480                 : 
     481              22 :     for (DrvInfos::iterator i = newElems.begin(); i != newElems.end(); ++i)
     482              12 :         printMsg(lvlInfo,
     483                 :             format("installing `%1%'") % i->name);
     484                 :         
     485              10 :     if (globals.dryRun) {
     486               0 :         printMissing(globals.state, newElems);
     487               0 :         return;
     488                 :     }
     489                 : 
     490              10 :     createUserEnv(globals.state, allElems,
     491                 :         profile, globals.keepDerivations);
     492                 : }
     493                 : 
     494                 : 
     495                 : static void opInstall(Globals & globals,
     496                 :     Strings opFlags, Strings opArgs)
     497              10 : {
     498              10 :     if (opFlags.size() > 0)
     499               4 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
     500                 : 
     501              10 :     installDerivations(globals, opArgs, globals.profile);
     502                 : }
     503                 : 
     504                 : 
     505                 : typedef enum { utLt, utLeq, utEq, utAlways } UpgradeType;
     506                 : 
     507                 : 
     508                 : static void upgradeDerivations(Globals & globals,
     509                 :     const Strings & args, const Path & profile,
     510                 :     UpgradeType upgradeType)
     511               1 : {
     512               1 :     debug(format("upgrading derivations"));
     513                 : 
     514                 :     /* Upgrade works as follows: we take all currently installed
     515                 :        derivations, and for any derivation matching any selector, look
     516                 :        for a derivation in the input Nix expression that has the same
     517                 :        name and a higher version number. */
     518                 : 
     519                 :     /* Load the currently installed derivations. */
     520               1 :     PathLocks lock;
     521               1 :     lockProfile(lock, profile);
     522               1 :     DrvInfos installedElems = queryInstalled(globals.state, profile);
     523                 : 
     524                 :     /* Fetch all derivations from the input file. */
     525               1 :     DrvInfos availElems;
     526               1 :     queryInstSources(globals.state, globals.instSource, args, availElems, false);
     527                 : 
     528                 :     /* Go through all installed derivations. */
     529               1 :     DrvInfos newElems;
     530               2 :     for (DrvInfos::iterator i = installedElems.begin();
     531                 :          i != installedElems.end(); ++i)
     532                 :     {
     533               1 :         DrvName drvName(i->name);
     534                 : 
     535                 :         /* Find the derivation in the input Nix expression with the
     536                 :            same name and satisfying the version constraints specified
     537                 :            by upgradeType.  If there are multiple matches, take the
     538                 :            one with highest version. */
     539               1 :         DrvInfos::iterator bestElem = availElems.end();
     540               1 :         DrvName bestName;
     541               4 :         for (DrvInfos::iterator j = availElems.begin();
     542                 :              j != availElems.end(); ++j)
     543                 :         {
     544               3 :             DrvName newName(j->name);
     545               3 :             if (newName.name == drvName.name) {
     546               3 :                 int d = compareVersions(drvName.version, newName.version);
     547               3 :                 if (upgradeType == utLt && d < 0 ||
     548                 :                     upgradeType == utLeq && d <= 0 ||
     549                 :                     upgradeType == utEq && d == 0 ||
     550                 :                     upgradeType == utAlways)
     551                 :                 {
     552               1 :                     if ((bestElem == availElems.end() ||
     553                 :                          compareVersions(
     554                 :                              bestName.version, newName.version) < 0))
     555                 :                     {
     556               1 :                         bestElem = j;
     557               3 :                         bestName = newName;
     558                 :                     }
     559                 :                 }
     560                 :             }
     561                 :         }
     562                 : 
     563               1 :         if (bestElem != availElems.end() &&
     564                 :             i->queryOutPath(globals.state) !=
     565                 :                 bestElem->queryOutPath(globals.state))
     566                 :         {
     567               1 :             printMsg(lvlInfo,
     568                 :                 format("upgrading `%1%' to `%2%'")
     569                 :                 % i->name % bestElem->name);
     570               1 :             newElems.push_back(*bestElem);
     571               0 :         } else newElems.push_back(*i);
     572                 :     }
     573                 :     
     574               1 :     if (globals.dryRun) {
     575               0 :         printMissing(globals.state, newElems);
     576               0 :         return;
     577                 :     }
     578                 : 
     579               1 :     createUserEnv(globals.state, newElems,
     580                 :         profile, globals.keepDerivations);
     581                 : }
     582                 : 
     583                 : 
     584                 : static void opUpgrade(Globals & globals,
     585                 :     Strings opFlags, Strings opArgs)
     586               1 : {
     587               1 :     UpgradeType upgradeType = utLt;
     588               1 :     for (Strings::iterator i = opFlags.begin();
     589                 :          i != opFlags.end(); ++i)
     590               0 :         if (*i == "--lt") upgradeType = utLt;
     591               0 :         else if (*i == "--leq") upgradeType = utLeq;
     592               0 :         else if (*i == "--eq") upgradeType = utEq;
     593               0 :         else if (*i == "--always") upgradeType = utAlways;
     594               0 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     595                 : 
     596               1 :     upgradeDerivations(globals, opArgs, globals.profile, upgradeType);
     597                 : }
     598                 : 
     599                 : 
     600                 : static void uninstallDerivations(Globals & globals, DrvNames & selectors,
     601                 :     Path & profile)
     602               5 : {
     603               5 :     PathLocks lock;
     604               5 :     lockProfile(lock, profile);
     605               5 :     DrvInfos installedElems = queryInstalled(globals.state, profile);
     606               5 :     DrvInfos newElems;
     607                 : 
     608              10 :     for (DrvInfos::iterator i = installedElems.begin();
     609                 :          i != installedElems.end(); ++i)
     610                 :     {
     611               5 :         DrvName drvName(i->name);
     612               5 :         bool found = false;
     613               6 :         for (DrvNames::iterator j = selectors.begin();
     614                 :              j != selectors.end(); ++j)
     615               5 :             if (j->matches(drvName)) {
     616               4 :                 printMsg(lvlInfo,
     617                 :                     format("uninstalling `%1%'") % i->name);
     618               4 :                 found = true;
     619               4 :                 break;
     620                 :             }
     621               5 :         if (!found) newElems.push_back(*i);
     622                 :     }
     623                 : 
     624               5 :     if (globals.dryRun) return;
     625                 : 
     626               5 :     createUserEnv(globals.state, newElems,
     627                 :         profile, globals.keepDerivations);
     628                 : }
     629                 : 
     630                 : 
     631                 : static void opUninstall(Globals & globals,
     632                 :     Strings opFlags, Strings opArgs)
     633               5 : {
     634               5 :     if (opFlags.size() > 0)
     635               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
     636                 : 
     637               5 :     DrvNames drvNames = drvNamesFromArgs(opArgs);
     638                 : 
     639               5 :     uninstallDerivations(globals, drvNames,
     640                 :         globals.profile);
     641                 : }
     642                 : 
     643                 : 
     644                 : static bool cmpChars(char a, char b)
     645             176 : {
     646             176 :     return toupper(a) < toupper(b);
     647                 : }
     648                 : 
     649                 : 
     650                 : static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b)
     651              32 : {
     652              32 :     return lexicographical_compare(
     653                 :         a.name.begin(), a.name.end(),
     654                 :         b.name.begin(), b.name.end(), cmpChars);
     655                 : }
     656                 : 
     657                 : 
     658                 : typedef list<Strings> Table;
     659                 : 
     660                 : 
     661                 : void printTable(Table & table)
     662              25 : {
     663              25 :     unsigned int nrColumns = table.size() > 0 ? table.front().size() : 0;
     664                 :     
     665              25 :     vector<unsigned int> widths;
     666              25 :     widths.resize(nrColumns);
     667                 :     
     668              63 :     for (Table::iterator i = table.begin(); i != table.end(); ++i) {
     669              38 :         assert(i->size() == nrColumns);
     670              38 :         Strings::iterator j;
     671              38 :         unsigned int column;
     672              81 :         for (j = i->begin(), column = 0; j != i->end(); ++j, ++column)
     673              43 :             if (j->size() > widths[column]) widths[column] = j->size();
     674                 :     }
     675                 : 
     676              63 :     for (Table::iterator i = table.begin(); i != table.end(); ++i) { 
     677              38 :         Strings::iterator j;
     678              38 :         unsigned int column;
     679              81 :         for (j = i->begin(), column = 0; j != i->end(); ++j, ++column)
     680                 :         {
     681              43 :             cout << *j;
     682              43 :             if (column < nrColumns - 1)
     683               5 :                 cout << string(widths[column] - j->size() + 2, ' ');
     684                 :         }
     685              38 :         cout << std::endl;
     686                 :     }
     687                 : }
     688                 : 
     689                 : 
     690                 : /* This function compares the version of a element against the
     691                 :    versions in the given set of elements.  `cvLess' means that only
     692                 :    lower versions are in the set, `cvEqual' means that at most an
     693                 :    equal version is in the set, and `cvGreater' means that there is at
     694                 :    least one element with a higher version in the set.  `cvUnavail'
     695                 :    means that there are no elements with the same name in the set. */
     696                 : 
     697                 : typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff;
     698                 : 
     699                 : static VersionDiff compareVersionAgainstSet(
     700                 :     const DrvInfo & elem, const DrvInfos & elems, string & version)
     701               0 : {
     702               0 :     DrvName name(elem.name);
     703                 :     
     704               0 :     VersionDiff diff = cvUnavail;
     705               0 :     version = "?";
     706                 :     
     707               0 :     for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) {
     708               0 :         DrvName name2(i->name);
     709               0 :         if (name.name == name2.name) {
     710               0 :             int d = compareVersions(name.version, name2.version);
     711               0 :             if (d < 0) {
     712               0 :                 diff = cvGreater;
     713               0 :                 version = name2.version;
     714                 :             }
     715               0 :             else if (diff != cvGreater && d == 0) {
     716               0 :                 diff = cvEqual;
     717               0 :                 version = name2.version;
     718                 :             }
     719               0 :             else if (diff != cvGreater && diff != cvEqual && d > 0) {
     720               0 :                 diff = cvLess;
     721               0 :                 if (version == "" || compareVersions(version, name2.version) < 0)
     722               0 :                     version = name2.version;
     723                 :             }
     724                 :         }
     725                 :     }
     726                 : 
     727               0 :     return diff;
     728                 : }
     729                 : 
     730                 : 
     731                 : static string colorString(const string & s)
     732               0 : {
     733               0 :     if (!isatty(STDOUT_FILENO)) return s;
     734               0 :     return "\e[1;31m" + s + "\e[0m";
     735                 : }
     736                 : 
     737                 : 
     738                 : static void opQuery(Globals & globals,
     739                 :     Strings opFlags, Strings opArgs)
     740              28 : {
     741                 :     typedef vector< map<string, string> > ResultSet;
     742                 :         
     743              28 :     bool printStatus = false;
     744              28 :     bool printName = true;
     745              28 :     bool printAttrPath = false;
     746              28 :     bool printSystem = false;
     747              28 :     bool printDrvPath = false;
     748              28 :     bool printOutPath = false;
     749              28 :     bool printDescription = false;
     750              28 :     bool compareVersions = false;
     751              28 :     bool xmlOutput = false;
     752                 : 
     753              28 :     enum { sInstalled, sAvailable } source = sInstalled;
     754                 : 
     755              28 :     readOnlyMode = true; /* makes evaluation a bit faster */
     756                 : 
     757              37 :     for (Strings::iterator i = opFlags.begin();
     758                 :          i != opFlags.end(); ++i)
     759              10 :         if (*i == "--status" || *i == "-s") printStatus = true;
     760              10 :         else if (*i == "--no-name") printName = false;
     761               7 :         else if (*i == "--system") printSystem = true;
     762               7 :         else if (*i == "--description") printDescription = true;
     763               6 :         else if (*i == "--compare-versions" || *i == "-c") compareVersions = true;
     764               6 :         else if (*i == "--drv-path") printDrvPath = true;
     765               6 :         else if (*i == "--out-path") printOutPath = true;
     766               3 :         else if (*i == "--installed") source = sInstalled;
     767               3 :         else if (*i == "--available" || *i == "-a") source = sAvailable;
     768               1 :         else if (*i == "--xml") xmlOutput = true;
     769               1 :         else throw UsageError(format("unknown flag `%1%'") % *i);
     770                 : 
     771              27 :     if (globals.instSource.type == srcAttrPath) printAttrPath = true; /* hack */
     772                 : 
     773              27 :     if (opArgs.size() == 0) {
     774               0 :         printMsg(lvlInfo, "warning: you probably meant to specify the argument '*' to show all packages");
     775                 :     }
     776                 : 
     777                 :     
     778                 :     /* Obtain derivation information from the specified source. */
     779              27 :     DrvInfos availElems, installedElems;
     780                 : 
     781              27 :     if (source == sInstalled || compareVersions || printStatus) {
     782              25 :         installedElems = queryInstalled(globals.state, globals.profile);
     783                 :     }
     784                 : 
     785              27 :     if (source == sAvailable || compareVersions) {
     786               2 :         loadDerivations(globals.state, globals.instSource.nixExprPath,
     787                 :             globals.instSource.systemFilter, globals.instSource.autoArgs,
     788                 :             availElems);
     789                 :     }
     790                 : 
     791                 :     DrvInfos elems = filterBySelector(globals.state,
     792                 :         source == sInstalled ? installedElems : availElems,
     793              27 :         opArgs, false);
     794                 :     
     795              25 :     DrvInfos & otherElems(source == sInstalled ? availElems : installedElems);
     796                 : 
     797                 :     
     798                 :     /* Sort them by name. */
     799                 :     /* !!! */
     800              25 :     vector<DrvInfo> elems2;
     801              63 :     for (DrvInfos::iterator i = elems.begin(); i != elems.end(); ++i)
     802              38 :         elems2.push_back(*i);
     803              25 :     sort(elems2.begin(), elems2.end(), cmpElemByName);
     804                 : 
     805                 :     
     806                 :     /* We only need to know the installed paths when we are querying
     807                 :        the status of the derivation. */
     808              25 :     PathSet installed; /* installed paths */
     809                 :     
     810              25 :     if (printStatus) {
     811               0 :         for (DrvInfos::iterator i = installedElems.begin();
     812                 :              i != installedElems.end(); ++i)
     813               0 :             installed.insert(i->queryOutPath(globals.state));
     814                 :     }
     815                 : 
     816                 :     
     817                 :     /* Print the desired columns, or XML output. */
     818              75 :     Table table;
     819              25 :     std::ostringstream dummy;
     820              25 :     XMLWriter xml(true, *(xmlOutput ? &cout : &dummy));
     821              25 :     XMLOpenElement xmlRoot(xml, "items");
     822                 :     
     823              63 :     for (vector<DrvInfo>::iterator i = elems2.begin();
     824                 :          i != elems2.end(); ++i)
     825                 :     {
     826              38 :         try {
     827                 : 
     828                 :             /* For table output. */
     829              38 :             Strings columns;
     830                 : 
     831                 :             /* For XML output. */
     832              38 :             XMLAttrs attrs;
     833                 :         
     834              38 :             if (printStatus) {
     835             164 :                 Substitutes subs = querySubstitutes(noTxn, i->queryOutPath(globals.state));
     836               0 :                 bool isInstalled = installed.find(i->queryOutPath(globals.state)) != installed.end();
     837               0 :                 bool isValid = isValidPath(i->queryOutPath(globals.state));
     838               0 :                 if (xmlOutput) {
     839               0 :                     attrs["installed"] = isInstalled ? "1" : "0";
     840               0 :                     attrs["valid"] = isValid ? "1" : "0";
     841               0 :                     attrs["substitutable"] = !subs.empty() ? "1" : "0";
     842                 :                 } else
     843               0 :                     columns.push_back(
     844                 :                         (string) (isInstalled ? "I" : "-")
     845                 :                         + (isValid ? "P" : "-")
     846                 :                         + (!subs.empty() ? "S" : "-"));
     847                 :             }
     848                 : 
     849              38 :             if (xmlOutput)
     850               0 :                 attrs["attrPath"] = i->attrPath;
     851              38 :             else if (printAttrPath)
     852               0 :                 columns.push_back(i->attrPath);
     853                 : 
     854              38 :             if (xmlOutput)
     855               0 :                 attrs["name"] = i->name;
     856              38 :             else if (printName)
     857              35 :                 columns.push_back(i->name);
     858                 : 
     859              38 :             if (compareVersions) {
     860                 :                 /* Compare this element against the versions of the
     861                 :                    same named packages in either the set of available
     862                 :                    elements, or the set of installed elements.  !!!
     863                 :                    This is O(N * M), should be O(N * lg M). */
     864               0 :                 string version;
     865               0 :                 VersionDiff diff = compareVersionAgainstSet(*i, otherElems, version);
     866                 : 
     867               0 :                 char ch;
     868               0 :                 switch (diff) {
     869               0 :                     case cvLess: ch = '>'; break;
     870               0 :                     case cvEqual: ch = '='; break;
     871               0 :                     case cvGreater: ch = '<'; break;
     872               0 :                     case cvUnavail: ch = '-'; break;
     873               0 :                     default: abort();
     874                 :                 }
     875                 : 
     876               0 :                 if (xmlOutput) {
     877               0 :                     if (diff != cvUnavail) {
     878               0 :                         attrs["versionDiff"] = ch;
     879               0 :                         attrs["maxComparedVersion"] = version;
     880                 :                     }
     881                 :                 } else {
     882               0 :                     string column = (string) "" + ch + " " + version;
     883               0 :                     if (diff == cvGreater) column = colorString(column);
     884               0 :                     columns.push_back(column);
     885                 :                 }
     886                 :             }
     887                 : 
     888              38 :             if (xmlOutput) {
     889               0 :                 if (i->system != "") attrs["system"] = i->system;
     890                 :             }
     891              38 :             else if (printSystem) 
     892               0 :                 columns.push_back(i->system);
     893                 : 
     894              38 :             if (printDrvPath) {
     895               0 :                 string drvPath = i->queryDrvPath(globals.state);
     896               0 :                 if (xmlOutput) {
     897               0 :                     if (drvPath != "") attrs["drvPath"] = drvPath;
     898                 :                 } else
     899               0 :                     columns.push_back(drvPath == "" ? "-" : drvPath);
     900                 :             }
     901                 :         
     902              38 :             if (printOutPath) {
     903               3 :                 string outPath = i->queryOutPath(globals.state);
     904               3 :                 if (xmlOutput) {
     905               0 :                     if (outPath != "") attrs["outPath"] = outPath;
     906                 :                 } else
     907               3 :                     columns.push_back(outPath);
     908                 :             }
     909                 : 
     910              38 :             if (printDescription) {
     911               5 :                 MetaInfo meta = i->queryMetaInfo(globals.state);
     912               5 :                 string descr = meta["description"];
     913               5 :                 if (xmlOutput) {
     914               0 :                     if (descr != "") attrs["description"] = descr;
     915                 :                 } else
     916               5 :                     columns.push_back(descr);
     917                 :             }
     918                 : 
     919              38 :             if (xmlOutput)
     920               0 :                 xml.writeEmptyElement("item", attrs);
     921                 :             else
     922              38 :                 table.push_back(columns);
     923                 : 
     924               0 :         } catch (AssertionError & e) {
     925                 :             /* !!! hm, maybe we should give some sort of warning here? */
     926                 :         }
     927                 :     }
     928                 : 
     929              25 :     if (!xmlOutput) printTable(table);
     930                 : }
     931                 : 
     932                 : 
     933                 : static void opSwitchProfile(Globals & globals,
     934                 :     Strings opFlags, Strings opArgs)
     935               0 : {
     936               0 :     if (opFlags.size() > 0)
     937               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
     938               0 :     if (opArgs.size() != 1)
     939               0 :         throw UsageError(format("exactly one argument expected"));
     940                 : 
     941               0 :     Path profile = opArgs.front();
     942               0 :     Path profileLink = getHomeDir() + "/.nix-profile";
     943                 : 
     944               0 :     SwitchToOriginalUser sw;
     945               0 :     switchLink(profileLink, profile);
     946                 : }
     947                 : 
     948                 : 
     949                 : static const int prevGen = -2;
     950                 : 
     951                 : 
     952                 : static void switchGeneration(Globals & globals, int dstGen)
     953               2 : {
     954               2 :     PathLocks lock;
     955               2 :     lockProfile(lock, globals.profile);
     956                 :     
     957               2 :     int curGen;
     958            1732 :     Generations gens = findGenerations(globals.profile, curGen);
     959                 : 
     960             222 :     Generation dst;
     961              12 :     for (Generations::iterator i = gens.begin(); i != gens.end(); ++i)
     962              10 :         if ((dstGen == prevGen && i->number < curGen) ||
     963                 :             (dstGen >= 0 && i->number == dstGen))
     964              21 :             dst = *i;
     965                 : 
     966               2 :     if (!dst)
     967               0 :         if (dstGen == prevGen)
     968               0 :             throw Error(format("no generation older than the current (%1%) exists")
     969                 :                 % curGen);
     970                 :         else
     971               0 :             throw Error(format("generation %1% does not exist") % dstGen);
     972                 : 
     973               2 :     printMsg(lvlInfo, format("switching from generation %1% to %2%")
     974                 :         % curGen % dst.number);
     975                 :     
     976               2 :     if (globals.dryRun) return;
     977                 :     
     978               2 :     switchLink(globals.profile, dst.path);
     979                 : }
     980                 : 
     981                 : 
     982                 : static void opSwitchGeneration(Globals & globals,
     983                 :     Strings opFlags, Strings opArgs)
     984               0 : {
     985               0 :     if (opFlags.size() > 0)
     986               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
     987               0 :     if (opArgs.size() != 1)
     988               0 :         throw UsageError(format("exactly one argument expected"));
     989                 : 
     990               0 :     int dstGen;
     991               0 :     if (!string2Int(opArgs.front(), dstGen))
     992               0 :         throw UsageError(format("expected a generation number"));
     993                 : 
     994               0 :     switchGeneration(globals, dstGen);
     995                 : }
     996                 : 
     997                 : 
     998                 : static void opRollback(Globals & globals,
     999                 :     Strings opFlags, Strings opArgs)
    1000               2 : {
    1001               2 :     if (opFlags.size() > 0)
    1002               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
    1003               2 :     if (opArgs.size() != 0)
    1004               0 :         throw UsageError(format("no arguments expected"));
    1005                 : 
    1006               2 :     switchGeneration(globals, prevGen);
    1007                 : }
    1008                 : 
    1009                 : 
    1010                 : static void opListGenerations(Globals & globals,
    1011                 :     Strings opFlags, Strings opArgs)
    1012               1 : {
    1013               1 :     if (opFlags.size() > 0)
    1014               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
    1015               1 :     if (opArgs.size() != 0)
    1016               0 :         throw UsageError(format("no arguments expected"));
    1017                 : 
    1018               1 :     PathLocks lock;
    1019               1 :     lockProfile(lock, globals.profile);
    1020                 :     
    1021               1 :     int curGen;
    1022               1 :     Generations gens = findGenerations(globals.profile, curGen);
    1023                 : 
    1024               6 :     for (Generations::iterator i = gens.begin(); i != gens.end(); ++i) {
    1025               5 :         tm t;
    1026               5 :         if (!localtime_r(&i->creationTime, &t)) throw Error("cannot convert time");
    1027               5 :         cout << format("%|4|   %|4|-%|02|-%|02| %|02|:%|02|:%|02|   %||\n")
    1028                 :             % i->number
    1029                 :             % (t.tm_year + 1900) % (t.tm_mon + 1) % t.tm_mday
    1030                 :             % t.tm_hour % t.tm_min % t.tm_sec
    1031                 :             % (i->number == curGen ? "(current)" : "");
    1032                 :     }
    1033                 : }
    1034                 : 
    1035                 : 
    1036                 : static void deleteGeneration2(const Path & profile, unsigned int gen)
    1037               6 : {
    1038               6 :     printMsg(lvlInfo, format("removing generation %1%") % gen);
    1039               6 :     deleteGeneration(profile, gen);
    1040                 : }
    1041                 : 
    1042                 : 
    1043                 : static void opDeleteGenerations(Globals & globals,
    1044                 :     Strings opFlags, Strings opArgs)
    1045               2 : {
    1046               2 :     if (opFlags.size() > 0)
    1047               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
    1048                 : 
    1049               2 :     PathLocks lock;
    1050               2 :     lockProfile(lock, globals.profile);
    1051                 :     
    1052               2 :     int curGen;
    1053               2 :     Generations gens = findGenerations(globals.profile, curGen);
    1054                 : 
    1055               4 :     for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i) {
    1056                 : 
    1057               2 :         if (*i == "old") {
    1058              10 :             for (Generations::iterator j = gens.begin(); j != gens.end(); ++j)
    1059               8 :                 if (j->number != curGen)
    1060               6 :                     deleteGeneration2(globals.profile, j->number);
    1061                 :         }
    1062                 : 
    1063                 :         else {
    1064               0 :             int n;
    1065               0 :             if (!string2Int(*i, n) || n < 0)
    1066               0 :                 throw UsageError(format("invalid generation specifier `%1%'")  % *i);
    1067               0 :             bool found = false;
    1068               0 :             for (Generations::iterator j = gens.begin(); j != gens.end(); ++j) {
    1069               0 :                 if (j->number == n) {
    1070               0 :                     deleteGeneration2(globals.profile, j->number);
    1071               0 :                     found = true;
    1072               0 :                     break;
    1073                 :                 }
    1074                 :             }
    1075               0 :             if (!found)
    1076               0 :                 printMsg(lvlError, format("generation %1% does not exist") % n);
    1077                 :         }
    1078                 :     }
    1079                 : }
    1080                 : 
    1081                 : 
    1082                 : static void opDefaultExpr(Globals & globals,
    1083                 :     Strings opFlags, Strings opArgs)
    1084               0 : {
    1085               0 :     if (opFlags.size() > 0)
    1086               0 :         throw UsageError(format("unknown flag `%1%'") % opFlags.front());
    1087               0 :     if (opArgs.size() != 1)
    1088               0 :         throw UsageError(format("exactly one argument expected"));
    1089                 : 
    1090               0 :     Path defNixExpr = absPath(opArgs.front());
    1091               0 :     Path defNixExprLink = getDefNixExprPath();
    1092                 :     
    1093               0 :     SwitchToOriginalUser sw;
    1094               0 :     switchLink(defNixExprLink, defNixExpr);
    1095                 : }
    1096                 : 
    1097                 : 
    1098                 : static string needArg(Strings::iterator & i,
    1099                 :     Strings & args, const string & arg)
    1100              64 : {
    1101              64 :     ++i;
    1102              64 :     if (i == args.end()) throw UsageError(
    1103                 :         format("`%1%' requires an argument") % arg);
    1104              64 :     return *i;
    1105                 : }
    1106                 : 
    1107                 : 
    1108                 : void run(Strings args)
    1109              50 : {
    1110              50 :     Strings opFlags, opArgs;
    1111              50 :     Operation op = 0;
    1112                 :     
    1113             586 :     Globals globals;
    1114                 :     
    1115              50 :     globals.instSource.type = srcUnknown;
    1116              50 :     globals.instSource.nixExprPath = getDefNixExprPath();
    1117              50 :     globals.instSource.systemFilter = thisSystem;
    1118                 :     
    1119              50 :     globals.dryRun = false;
    1120              50 :     globals.preserveInstalled = false;
    1121                 : 
    1122              50 :     globals.keepDerivations =
    1123                 :         queryBoolSetting("env-keep-derivations", false);
    1124                 :     
    1125             220 :     for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
    1126             170 :         string arg = *i;
    1127                 : 
    1128             170 :         Operation oldOp = op;
    1129                 : 
    1130             170 :         if (arg == "--install" || arg == "-i")
    1131              10 :             op = opInstall;
    1132             160 :         else if (arg == "--from-expression" || arg == "-E")
    1133               0 :             globals.instSource.type = srcNixExprs;
    1134             160 :         else if (arg == "--from-profile") {
    1135               0 :             globals.instSource.type = srcProfile;
    1136               0 :             globals.instSource.profile = needArg(i, args, arg);
    1137                 :         }
    1138             160 :         else if (arg == "--attr" || arg == "-A")
    1139               0 :             globals.instSource.type = srcAttrPath;
    1140             160 :         else if (arg == "--arg") { /* !!! code duplication from nix-instantiate */
    1141               0 :             i++;
    1142               0 :             if (i == args.end())
    1143               0 :                 throw UsageError("`--arg' requires two arguments");
    1144               0 :             string name = *i++;
    1145               0 :             if (i == args.end())
    1146               0 :                 throw UsageError("`--arg' requires two arguments");
    1147               0 :             Expr value = parseExprFromString(globals.state, *i, absPath("."));
    1148               0 :             globals.instSource.autoArgs.set(toATerm(name), value);
    1149                 :         }
    1150             160 :         else if (arg == "--force-name") // undocumented flag for nix-install-package
    1151               2 :             globals.forceName = needArg(i, args, arg);
    1152             158 :         else if (arg == "--uninstall" || arg == "-e")
    1153               5 :             op = opUninstall;
    1154             153 :         else if (arg == "--upgrade" || arg == "-u")
    1155               1 :             op = opUpgrade;
    1156             152 :         else if (arg == "--query" || arg == "-q")
    1157              28 :             op = opQuery;
    1158             124 :         else if (arg == "--import" || arg == "-I") /* !!! bad name */
    1159               0 :             op = opDefaultExpr;
    1160             124 :         else if (arg == "--profile" || arg == "-p") {
    1161              48 :             globals.profile = absPath(needArg(i, args, arg));
    1162                 :         }
    1163              76 :         else if (arg == "--file" || arg == "-f") {
    1164              14 :             globals.instSource.nixExprPath = absPath(needArg(i, args, arg));
    1165                 :         }
    1166              62 :         else if (arg == "--switch-profile" || arg == "-S")
    1167               0 :             op = opSwitchProfile;
    1168              62 :         else if (arg == "--switch-generation" || arg == "-G")
    1169               0 :             op = opSwitchGeneration;
    1170              62 :         else if (arg == "--rollback")
    1171               2 :             op = opRollback;
    1172              60 :         else if (arg == "--list-generations")
    1173               1 :             op = opListGenerations;
    1174              59 :         else if (arg == "--delete-generations")
    1175               2 :             op = opDeleteGenerations;
    1176              57 :         else if (arg == "--dry-run") {
    1177               0 :             printMsg(lvlInfo, "(dry run; not doing anything)");
    1178               0 :             globals.dryRun = true;
    1179                 :         }
    1180              57 :         else if (arg == "--preserve-installed" || arg == "-P")
    1181               0 :             globals.preserveInstalled = true;
    1182              57 :         else if (arg == "--system-filter") {
    1183               0 :             globals.instSource.systemFilter = needArg(i, args, arg);
    1184                 :         }
    1185              57 :         else if (arg[0] == '-')
    1186              11 :             opFlags.push_back(arg);
    1187                 :         else
    1188              46 :             opArgs.push_back(arg);
    1189                 : 
    1190             170 :         if (oldOp && oldOp != op)
    1191               0 :             throw UsageError("only one operation may be specified");
    1192                 :     }
    1193                 : 
    1194              50 :     if (!op) throw UsageError("no operation specified");
    1195                 : 
    1196              49 :     if (globals.profile == "") {
    1197               1 :         SwitchToOriginalUser sw;
    1198               1 :         Path profileLink = getHomeDir() + "/.nix-profile";
    1199               1 :         globals.profile = pathExists(profileLink)
    1200                 :             ? absPath(readLink(profileLink), dirOf(profileLink))
    1201                 :             : canonPath(nixStateDir + "/profiles/default");
    1202                 :     }
    1203                 :     
    1204              49 :     openDB();
    1205                 : 
    1206              49 :     op(globals, opFlags, opArgs);
    1207                 : 
    1208              45 :     printEvalStats(globals.state);
    1209                 : }
    1210                 : 
    1211                 : 
    1212             104 : string programId = "nix-env";

Generated by: LTP GCOV extension version 1.1