diff --git a/configure.ac b/configure.ac
index 5af239cbd..1842b1e15 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,6 +139,7 @@ fi
AC_MSG_RESULT(yes)
NEED_PROG(cat, cat)
+NEED_PROG(tr, tr)
AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
[path of cat, mkdir, etc.]),
coreutils=$withval, coreutils=$(dirname $cat))
diff --git a/corepkgs/channels/unpack.sh.in b/corepkgs/channels/unpack.sh.in
index 80c177024..03c6e5b2f 100644
--- a/corepkgs/channels/unpack.sh.in
+++ b/corepkgs/channels/unpack.sh.in
@@ -5,18 +5,29 @@
cd $out/tmp
expr=$out/default.nix
-echo '[' > $expr
+echo '{' > $expr
-nr=0
-for i in $inputs; do
- echo "unpacking $i"
- @bunzip2@ < $i | @tar@ xf -
- @coreutils@/mv * ../$nr # !!! hacky
- echo "(import ./$nr)" >> $expr
- nr=$(($nr + 1))
+inputs=($inputs)
+for ((n = 0; n < ${#inputs[*]}; n += 2)); do
+ channelName=${inputs[n]}
+ channelTarball=${inputs[n+1]}
+ echo "unpacking channel $channelName"
+ @bunzip2@ < $channelTarball | @tar@ xf -
+
+ nr=1
+ dirName=$channelName
+ while test -e ../$dirName; do
+ nr=$((nr+1))
+ dirName=$channelName-$nr
+ done
+
+ @coreutils@/mv * ../$dirName # !!! hacky
+
+ attrName=$(echo $dirName | @tr@ -- '- ' '__')
+ echo "$attrName = import ./$dirName {};" >> $expr
done
-echo ']' >> $expr
+echo '} // {_combineChannels = true;}' >> $expr
cd ..
@coreutils@/rmdir tmp
diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml
index da8c47588..43358fe55 100644
--- a/doc/manual/release-notes.xml
+++ b/doc/manual/release-notes.xml
@@ -70,10 +70,16 @@
info about installed packages in user environments. to show all meta info.
+
TODO: nix-env
. Specific flags:
active, priority,
keep.
+
+
+ TODO: nix-env
+ / take package priorities into
+ account.
nix-env -q now has a flag
diff --git a/scripts/nix-channel.in b/scripts/nix-channel.in
index 73096a12b..095f36d79 100644
--- a/scripts/nix-channel.in
+++ b/scripts/nix-channel.in
@@ -89,21 +89,22 @@ sub update {
# Create a Nix expression that fetches and unpacks the channel Nix
# expressions.
- my $nixExpr = "[";
+ my $inputs = "[";
foreach my $url (@channels) {
+ $url =~ /\/([^\/]+)\/?$/;
+ my $channelName = $1;
+ $channelName = "unnamed" unless defined $channelName;
+ print "$channelName\n";
+
my $fullURL = "$url/nixexprs.tar.bz2";
print "downloading Nix expressions from `$fullURL'...\n";
$ENV{"PRINT_PATH"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL' 2> /dev/null`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
- $nixExpr .= $path . " ";
+ $inputs .= '"' . $channelName . '"' . " " . $path . " ";
}
- $nixExpr .= "]";
-
- $nixExpr =
- "(import @datadir@/nix/corepkgs/channels/unpack.nix) " .
- "{inputs = $nixExpr; system = \"@system@\";}";
+ $inputs .= "]";
# Figure out a name for the GC root.
my $userName = getpwuid($<);
@@ -113,7 +114,7 @@ sub update {
# Instantiate the Nix expression.
print "unpacking channel Nix expressions...\n";
- my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate --add-root '$rootFile'.tmp -`
+ my $storeExpr = `@bindir@/nix-instantiate --add-root '$rootFile'.tmp @datadir@/nix/corepkgs/channels/unpack.nix --argstr system @system@ --arg inputs '$inputs'`
or die "cannot instantiate Nix expression";
chomp $storeExpr;
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index 7c16a7798..f79b2fd0e 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -107,6 +107,15 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
}
+string DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
+{
+ /* !!! evaluates all meta attributes => inefficient */
+ MetaInfo meta = queryMetaInfo(state);
+ MetaInfo::iterator i = meta.find(name);
+ return i == meta.end() ? "" : i->second;
+}
+
+
void DrvInfo::setMetaInfo(const MetaInfo & meta)
{
ATermMap metaAttrs;
@@ -214,12 +223,21 @@ static void getDerivations(EvalState & state, Expr e,
if (matchAttrs(e, es)) {
ATermMap drvMap(ATgetLength(es));
queryAllAttrs(e, drvMap);
+
+ /* !!! undocumented hackery to support
+ corepkgs/channels/unpack.sh. */
+ Expr e2 = drvMap.get(toATerm("_combineChannels"));
+ bool combineChannels = e2 && evalBool(state, e2);
for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
startNest(nest, lvlDebug,
format("evaluating attribute `%1%'") % aterm2String(i->key));
string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key));
- if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
+ if (combineChannels) {
+ if (((string) aterm2String(i->key)) != "_combineChannels")
+ getDerivations(state, i->value, pathPrefix2, autoArgs, drvs, doneExprs);
+ }
+ else if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
/* If the value of this attribute is itself an
attribute set, should we recurse into it? => Only
if it has a `recurseForDerivations = true'
@@ -229,8 +247,8 @@ static void getDerivations(EvalState & state, Expr e,
if (matchAttrs(e, es)) {
ATermMap attrs(ATgetLength(es));
queryAllAttrs(e, attrs, false);
- Expr e2 = attrs.get(toATerm("recurseForDerivations"));
- if (e2 && evalBool(state, e2))
+ if (((e2 = attrs.get(toATerm("recurseForDerivations")))
+ && evalBool(state, e2)))
getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
}
}
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index 5fffd434a..ccce36bf6 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -38,6 +38,7 @@ public:
string queryStateIdentifier(EvalState & state) const;
string queryRuntimeStateArgs(EvalState & state) const;
MetaInfo queryMetaInfo(EvalState & state) const;
+ string queryMetaInfo(EvalState & state, const string & name) const;
void setDrvPath(const string & s)
{
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 3a1fbba8b..93741ca6b 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -252,6 +252,16 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
}
+static int comparePriorities(EvalState & state,
+ const DrvInfo & drv1, const DrvInfo & drv2)
+{
+ int prio1, prio2;
+ if (!string2Int(drv1.queryMetaInfo(state, "priority"), prio1)) prio1 = 0;
+ if (!string2Int(drv2.queryMetaInfo(state, "priority"), prio2)) prio2 = 0;
+ return prio2 - prio1; /* higher number = lower priority, so negate */
+}
+
+
static DrvInfos filterBySelector(EvalState & state,
const DrvInfos & allElems,
const Strings & args, bool newestOnly)
@@ -278,8 +288,10 @@ static DrvInfos filterBySelector(EvalState & state,
}
/* If `newestOnly', if a selector matches multiple derivations
- with the same name, pick the one with the highest version.
- If there are multiple derivations with the same name *and*
+ with the same name, pick the one with the highest priority.
+ If there are multiple derivations with the same priority,
+ pick the one with the highest version. If there are
+ multiple derivations with the same priority and name and
version, then pick the first one. */
if (newestOnly) {
@@ -290,13 +302,22 @@ static DrvInfos filterBySelector(EvalState & state,
for (Matches::iterator j = matches.begin(); j != matches.end(); ++j) {
DrvName drvName(j->first.name);
+ int d = 1;
+
Newest::iterator k = newest.find(drvName.name);
+
if (k != newest.end()) {
- int d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
- if (d > 0) newest[drvName.name] = *j;
- else if (d == 0) multiple.insert(j->first.name);
- } else
+ d = comparePriorities(state, j->first, k->second.first);
+ if (d == 0)
+ d = compareVersions(drvName.version, DrvName(k->second.first.name).version);
+ }
+
+ if (d > 0) {
newest[drvName.name] = *j;
+ multiple.erase(j->first.name);
+ } else if (d == 0) {
+ multiple.insert(j->first.name);
+ }
}
matches.clear();
@@ -712,9 +733,10 @@ static void upgradeDerivations(Globals & globals,
if (meta["keep"] == "true") continue;
/* Find the derivation in the input Nix expression with the
- same name and satisfying the version constraints specified
+ same name that satisfies the version constraints specified
by upgradeType. If there are multiple matches, take the
- one with highest version. */
+ one with the highest priority. If there are still multiple
+ matches, take the one with the highest version. */
DrvInfos::iterator bestElem = availElems.end();
DrvName bestName;
for (DrvInfos::iterator j = availElems.begin();
@@ -722,16 +744,19 @@ static void upgradeDerivations(Globals & globals,
{
DrvName newName(j->name);
if (newName.name == drvName.name) {
- int d = compareVersions(drvName.version, newName.version);
+ int d = comparePriorities(globals.state, *i, *j);
+ if (d == 0) d = compareVersions(drvName.version, newName.version);
if (upgradeType == utLt && d < 0 ||
upgradeType == utLeq && d <= 0 ||
upgradeType == utEq && d == 0 ||
upgradeType == utAlways)
{
- if ((bestElem == availElems.end() ||
- compareVersions(
- bestName.version, newName.version) < 0))
- {
+ int d2 = -1;
+ if (bestElem != availElems.end()) {
+ d2 = comparePriorities(globals.state, *bestElem, *j);
+ if (d2 == 0) d2 = compareVersions(bestName.version, newName.version);
+ }
+ if (d2 < 0) {
bestElem = j;
bestName = newName;
}
diff --git a/substitute.mk b/substitute.mk
index 5038bd4bf..bdc9c4350 100644
--- a/substitute.mk
+++ b/substitute.mk
@@ -17,6 +17,7 @@
-e "s^@perl\@^$(perl)^g" \
-e "s^@coreutils\@^$(coreutils)^g" \
-e "s^@tar\@^$(tar)^g" \
+ -e "s^@tr\@^$(tr)^g" \
-e "s^@dot\@^$(dot)^g" \
-e "s^@xmllint\@^$(xmllint)^g" \
-e "s^@xmlflags\@^$(xmlflags)^g" \