about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2007-05-01T20·33+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2007-05-01T20·33+0000
commita9d15d4f434fece269852a65be836d1338ed787d (patch)
tree2b911d71e4641da7d164c4f8aeab930acef6a9a3
parentcbfac2fdccc83b04d9c2027e9e21070d4ac7c7e5 (diff)
* nix-env -i: instead of breaking package ties by version, break them
  by priority and version install.  That is, if there are multiple
  packages with the same name, then pick the package with the highest
  priority, and only use the version if there are multiple packages
  with the same priority.

  This makes it possible to mark specific versions/variant in Nixpkgs
  more or less desirable than others.  A typical example would be a
  beta version of some package (e.g., "gcc-4.2.0rc1") which should not
  be installed even though it is the highest version, except when it
  is explicitly selected (e.g., "nix-env -i gcc-4.2.0rc1").

* Idem for nix-env -u, only the semantics are a bit trickier since we
  also need to take into account the priority of the currently
  installed package (we never upgrade to a lower priority, unless
  --always is given).

-rw-r--r--doc/manual/release-notes.xml6
-rw-r--r--src/libexpr/get-drvs.cc9
-rw-r--r--src/libexpr/get-drvs.hh1
-rw-r--r--src/nix-env/nix-env.cc51
4 files changed, 54 insertions, 13 deletions
diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml
index da8c47588b9b..43358fe5537a 100644
--- a/doc/manual/release-notes.xml
+++ b/doc/manual/release-notes.xml
@@ -70,10 +70,16 @@
   info about installed packages in user environments.  <option>-q
   --xml --meta</option> to show all meta info.</para></listitem>
 
+  
   <listitem><para>TODO: <command>nix-env</command>
   <option>--set-flag</option>.  Specific flags:
   <literal>active</literal>, <literal>priority</literal>,
   <literal>keep</literal>.</para></listitem>
+
+  
+  <listitem><para>TODO: <command>nix-env</command> <option>-i</option>
+  / <option>-u</option> take package priorities into
+  account.</para></listitem>
   
 
   <listitem><para><command>nix-env -q</command> now has a flag
diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc
index bd0ec4781cfe..daa987fe713b 100644
--- a/src/libexpr/get-drvs.cc
+++ b/src/libexpr/get-drvs.cc
@@ -60,6 +60,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;
diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh
index 920197d1fb37..46dc51a568af 100644
--- a/src/libexpr/get-drvs.hh
+++ b/src/libexpr/get-drvs.hh
@@ -34,6 +34,7 @@ public:
     string queryDrvPath(EvalState & state) const;
     string queryOutPath(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 9f965bd2872f..7733ab16b9ec 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -232,6 +232,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)
@@ -258,8 +268,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) {
 
@@ -270,13 +282,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();
@@ -549,9 +570,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();
@@ -559,16 +581,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;
                     }