* nix-env: allow ~/.nix-defexpr to be a directory. If it is, then the

Nix expressions in that directory are combined into an attribute set
  {file1 = import file1; file2 = import file2; ...}, i.e. each Nix
  expression is an attribute with the file name as the attribute
  name.  Also recurses into directories.

* nix-env: removed the "--import" (-I) option which set the
  ~/.nix-defexpr symlink.

* nix-channel: don't use "nix-env --import", instead symlink
  ~/.nix-defexpr/channels.  So finally nix-channel --update doesn't
  override any default Nix expressions but combines with them.

  This means that you can have (say) a local Nixpkgs SVN tree and use
  it as a default for nix-env:

  $ ln -s .../path-to-nixpkgs-tree ~/.nix-defexpr/nixpkgs_svn

  and be subscribed to channels (including Nixpkgs) at the same time.
  (If there is any ambiguity, the -A flag can be used to
  disambiguate, e.g. "nix-env -i -A nixpkgs_svn.pan".)
This commit is contained in:
Eelco Dolstra 2007-09-17 16:08:24 +00:00
parent 3339f85447
commit 055608227f
6 changed files with 66 additions and 78 deletions

View file

@ -4,9 +4,6 @@
@coreutils@/mkdir $out/tmp @coreutils@/mkdir $out/tmp
cd $out/tmp cd $out/tmp
expr=$out/default.nix
echo '{' > $expr
inputs=($inputs) inputs=($inputs)
for ((n = 0; n < ${#inputs[*]}; n += 2)); do for ((n = 0; n < ${#inputs[*]}; n += 2)); do
channelName=${inputs[n]} channelName=${inputs[n]}
@ -15,19 +12,15 @@ for ((n = 0; n < ${#inputs[*]}; n += 2)); do
@bunzip2@ < $channelTarball | @tar@ xf - @bunzip2@ < $channelTarball | @tar@ xf -
nr=1 nr=1
dirName=$channelName attrName=$(echo $channelName | @tr@ -- '- ' '__')
dirName=$attrName
while test -e ../$dirName; do while test -e ../$dirName; do
nr=$((nr+1)) nr=$((nr+1))
dirName=$channelName-$nr dirName=$attrName-$nr
done done
@coreutils@/mv * ../$dirName # !!! hacky @coreutils@/mv * ../$dirName # !!! hacky
attrName=$(echo $dirName | @tr@ -- '- ' '__')
echo "$attrName = let e = import ./$dirName; in if builtins.isFunction e then e {} else e;" >> $expr
done done
echo '} // {_combineChannels = true;}' >> $expr
cd .. cd ..
@coreutils@/rmdir tmp @coreutils@/rmdir tmp

View file

@ -142,14 +142,14 @@ linkend="sec-common-options" />.</para>
<variablelist> <variablelist>
<varlistentry><term><filename>~/.nix-defexpr</filename></term> <varlistentry><term><filename>~/.nix-defexpr</filename></term>
<!-- !!! .nix-defexpr can be a directory now -->
<listitem><para>The default Nix expression used by the <listitem><para>The default Nix expression used by the
<option>--install</option>, <option>--upgrade</option>, and <option>--install</option>, <option>--upgrade</option>, and
<option>--query --available</option> operations to obtain <option>--query --available</option> operations to obtain
derivations. It is generally a symbolic link to some other derivations. The <option>--file</option> option may be used to
location set using the <option>--import</option> operation. The override this default.</para></listitem>
<option>--file</option> option may be used to override this
default.</para></listitem>
</varlistentry> </varlistentry>
@ -1061,43 +1061,4 @@ error: no generation older than the current (91) exists</screen>
<!--######################################################################-->
<refsection><title>Operation <option>--import</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-env</command>
<group choice='req'>
<arg choice='plain'><option>--import</option></arg>
<arg choice='plain'><option>-I</option></arg>
</group>
<arg choice='req'><replaceable>path</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>This operation makes <replaceable>path</replaceable> the default
active Nix expression for the user. That is, the symlink
<filename>~/.nix-userenv</filename> is made to point to
<replaceable>path</replaceable>.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
$ nix-env -I ~/nixpkgs-0.5/</screen>
</refsection>
</refsection>
</refentry> </refentry>

View file

@ -18,6 +18,8 @@ $ENV{'NIX_DOWNLOAD_CACHE'} = $channelCache if -W $channelCache;
my $home = $ENV{"HOME"}; my $home = $ENV{"HOME"};
die '$HOME not set' unless defined $home; die '$HOME not set' unless defined $home;
my $channelsList = "$home/.nix-channels"; my $channelsList = "$home/.nix-channels";
my $nixDefExpr = "$home/.nix-defexpr";
my @channels; my @channels;
@ -136,9 +138,12 @@ sub update {
unlink "$rootFile.tmp"; unlink "$rootFile.tmp";
# Make it the default Nix expression for `nix-env'. # Make the channels appear in nix-env.
system("@bindir@/nix-env", "--import", "$outPath") == 0 unlink $nixDefExpr if -l $nixDefExpr; # old-skool ~/.nix-defexpr
or die "cannot pull set default Nix expression to `$outPath'"; mkdir $nixDefExpr or die "cannot create directory `$nixDefExpr'" if !-e $nixDefExpr;
my $channelLink = "$nixDefExpr/channels";
unlink $channelLink; # !!! not atomic
symlink($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'";
} }

View file

@ -171,8 +171,8 @@ static void getDerivations(EvalState & state, Expr e,
ATermMap drvMap(ATgetLength(es)); ATermMap drvMap(ATgetLength(es));
queryAllAttrs(e, drvMap); queryAllAttrs(e, drvMap);
/* !!! undocumented hackery to support /* !!! undocumented hackery to support combining channels in
corepkgs/channels/unpack.sh. */ nix-env.cc. */
Expr e2 = drvMap.get(toATerm("_combineChannels")); Expr e2 = drvMap.get(toATerm("_combineChannels"));
bool combineChannels = e2 && evalBool(state, e2); bool combineChannels = e2 && evalBool(state, e2);

View file

@ -154,6 +154,7 @@ bool pathExists(const Path & path)
Path readLink(const Path & path) Path readLink(const Path & path)
{ {
checkInterrupt();
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path); throw SysError(format("getting status of `%1%'") % path);

View file

@ -22,6 +22,8 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -72,11 +74,53 @@ void printHelp()
} }
static bool isNixExpr(const Path & path)
{
struct stat st;
if (stat(path.c_str(), &st) == -1)
throw SysError(format("getting information about `%1%'") % path);
return !S_ISDIR(st.st_mode) || pathExists(path + "/default.nix");
}
static void getAllExprs(EvalState & state,
const Path & path, ATermMap & attrs)
{
Strings names = readDirectory(path);
for (Strings::iterator i = names.begin(); i != names.end(); ++i) {
Path path2 = path + "/" + *i;
if (isNixExpr(path2))
attrs.set(toATerm(*i), makeAttrRHS(
parseExprFromFile(state, absPath(path2)), makeNoPos()));
else
getAllExprs(state, path2, attrs);
}
}
static Expr loadSourceExpr(EvalState & state, const Path & path)
{
if (isNixExpr(path)) return parseExprFromFile(state, absPath(path));
/* The path is a directory. Put the Nix expressions in the
directory in an attribute set, with the file name of each
expression as the attribute name. Recurse into subdirectories
(but keep the attribute set flat, not nested, to make it easier
for a user to have a ~/.nix-defexpr directory that includes
some system-wide directory). */
ATermMap attrs;
attrs.set(toATerm("_combineChannels"), makeAttrRHS(eTrue, makeNoPos()));
getAllExprs(state, path, attrs);
return makeAttrs(attrs);
}
static void loadDerivations(EvalState & state, Path nixExprPath, static void loadDerivations(EvalState & state, Path nixExprPath,
string systemFilter, const ATermMap & autoArgs, DrvInfos & elems) string systemFilter, const ATermMap & autoArgs, DrvInfos & elems)
{ {
getDerivations(state, getDerivations(state, loadSourceExpr(state, nixExprPath), "", autoArgs, elems);
parseExprFromFile(state, absPath(nixExprPath)), "", autoArgs, elems);
/* Filter out all derivations not applicable to the current /* Filter out all derivations not applicable to the current
system. */ system. */
@ -365,9 +409,7 @@ static void queryInstSources(EvalState & state,
(import ./foo.nix)' = `(import ./foo.nix).bar'. */ (import ./foo.nix)' = `(import ./foo.nix).bar'. */
case srcNixExprs: { case srcNixExprs: {
Expr e1 = loadSourceExpr(state, instSource.nixExprPath);
Expr e1 = parseExprFromFile(state,
absPath(instSource.nixExprPath));
for (Strings::const_iterator i = args.begin(); for (Strings::const_iterator i = args.begin();
i != args.end(); ++i) i != args.end(); ++i)
@ -429,7 +471,7 @@ static void queryInstSources(EvalState & state,
i != args.end(); ++i) i != args.end(); ++i)
getDerivations(state, getDerivations(state,
findAlongAttrPath(state, *i, instSource.autoArgs, findAlongAttrPath(state, *i, instSource.autoArgs,
parseExprFromFile(state, instSource.nixExprPath)), loadSourceExpr(state, instSource.nixExprPath)),
"", instSource.autoArgs, elems); "", instSource.autoArgs, elems);
break; break;
} }
@ -1218,18 +1260,6 @@ static void opDeleteGenerations(Globals & globals,
} }
static void opDefaultExpr(Globals & globals,
Strings opFlags, Strings opArgs)
{
if (opFlags.size() > 0)
throw UsageError(format("unknown flag `%1%'") % opFlags.front());
if (opArgs.size() != 1)
throw UsageError(format("exactly one argument expected"));
switchLink(getDefNixExprPath(), absPath(opArgs.front()));
}
static string needArg(Strings::iterator & i, static string needArg(Strings::iterator & i,
Strings & args, const string & arg) Strings & args, const string & arg)
{ {
@ -1286,8 +1316,6 @@ void run(Strings args)
op = opSet; op = opSet;
else if (arg == "--query" || arg == "-q") else if (arg == "--query" || arg == "-q")
op = opQuery; op = opQuery;
else if (arg == "--import" || arg == "-I") /* !!! bad name */
op = opDefaultExpr;
else if (arg == "--profile" || arg == "-p") else if (arg == "--profile" || arg == "-p")
globals.profile = absPath(needArg(i, args, arg)); globals.profile = absPath(needArg(i, args, arg));
else if (arg == "--file" || arg == "-f") else if (arg == "--file" || arg == "-f")