nix-env -i: Add a flag ‘--remove-all’ / ‘-r’

This is equivalent to running ‘nix-env -e '*'’ first, except that it
happens in a single transaction.  Thus, ‘nix-env -i pkgs...’ replaces
the profile with the specified set of packages.

The main motivation is to support declarative package management
(similar to environment.systemPackages in NixOS).  That is, if you
have a specification ‘profile.nix’ like this:

  with import <nixpkgs> {};
  [ thunderbird
    geeqie
    ...
  ]

then after any change to ‘profile.nix’, you can run:

  $ nix-env -f profile.nix -ir

to update the profile to match the specification.  (Without the ‘-r’
flag, if you remove a package from ‘profile.nix’, it won't be removed
from the actual profile.)

Suggested by @zefhemel.
This commit is contained in:
Eelco Dolstra 2013-09-03 21:15:47 +02:00
parent 88c07341a6
commit 2c1ecf8e81
2 changed files with 39 additions and 17 deletions

View File

@ -209,6 +209,10 @@ also <xref linkend="sec-common-options" />.</phrase></para>
<arg choice='plain'><option>--preserve-installed</option></arg>
<arg choice='plain'><option>-P</option></arg>
</group>
<group choice='opt'>
<arg choice='plain'><option>--remove-all</option></arg>
<arg choice='plain'><option>-r</option></arg>
</group>
<arg choice='plain' rep='repeat'><replaceable>args</replaceable></arg>
</cmdsynopsis>
@ -318,6 +322,16 @@ number of possible ways:
</varlistentry>
<varlistentry><term><option>--remove-all</option></term>
<term><option>-r</option></term>
<listitem><para>Remove all previously installed packages first.
This is equivalent to running <literal>nix-env -e '*'</literal>
first, except that everything happens in a single
transaction.</para></listitem>
</varlistentry>
</variablelist>
</refsection>

View File

@ -54,6 +54,7 @@ struct Globals
EvalState state;
bool dryRun;
bool preserveInstalled;
bool removeAll;
string forceName;
bool prebuiltOnly;
};
@ -489,29 +490,33 @@ static void installDerivations(Globals & globals,
newNames.insert(DrvName(i->name).name);
}
/* Add in the already installed derivations, unless they have the
same name as a to-be-installed element. */
while (true) {
string lockToken = optimisticLockProfile(profile);
DrvInfos installedElems = queryInstalled(globals.state, profile);
DrvInfos allElems(newElems);
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
MetaInfo meta = i->queryMetaInfo(globals.state);
if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() &&
!keep(meta))
printMsg(lvlInfo,
format("replacing old `%1%'") % i->name);
else
allElems.push_back(*i);
}
foreach (DrvInfos::iterator, i, newElems)
printMsg(lvlInfo, format("installing `%1%'") % i->name);
/* Add in the already installed derivations, unless they have
the same name as a to-be-installed element. */
if (!globals.removeAll) {
printMsg(lvlError, "FOO");
DrvInfos installedElems = queryInstalled(globals.state, profile);
foreach (DrvInfos::iterator, i, installedElems) {
DrvName drvName(i->name);
MetaInfo meta = i->queryMetaInfo(globals.state);
if (!globals.preserveInstalled &&
newNames.find(drvName.name) != newNames.end() &&
!keep(meta))
printMsg(lvlInfo, format("replacing old `%1%'") % i->name);
else
allElems.push_back(*i);
}
foreach (DrvInfos::iterator, i, newElems)
printMsg(lvlInfo, format("installing `%1%'") % i->name);
}
printMissing(globals.state, newElems);
@ -531,6 +536,8 @@ static void opInstall(Globals & globals,
if (parseInstallSourceOptions(globals, i, opFlags, arg)) ;
else if (arg == "--preserve-installed" || arg == "-P")
globals.preserveInstalled = true;
else if (arg == "--remove-all" || arg == "-r")
globals.removeAll = true;
else throw UsageError(format("unknown flag `%1%'") % arg);
}
@ -1298,6 +1305,7 @@ void run(Strings args)
globals.dryRun = false;
globals.preserveInstalled = false;
globals.removeAll = false;
globals.prebuiltOnly = false;
for (Strings::iterator i = args.begin(); i != args.end(); ) {