- fixing package selection (update candidate)
authorJan Kupec <jkupec@suse.cz>
Mon, 27 Oct 2008 12:37:37 +0000 (12:37 +0000)
committerJan Kupec <jkupec@suse.cz>
Mon, 27 Oct 2008 12:37:37 +0000 (12:37 +0000)
- preparing for install by arch (using .arch suffix)

src/install.cc
src/update.cc
src/update.h

index 980aa34..2f4f9ba 100755 (executable)
@@ -1,5 +1,5 @@
 #include <boost/format.hpp>
-
+//#include <iostream>
 #include "zypp/ZYppFactory.h"
 #include "zypp/base/Logger.h"
 #include "zypp/base/Algorithm.h"
@@ -35,26 +35,34 @@ static PoolItem findInstalledItemInRepos(const PoolItem & installed)
   return result;
 }
 
-// TODO edition, arch ?
-static void mark_for_install(Zypper & zypper,
+// TODO edition - need solver API
+static void
+mark_for_install(Zypper & zypper,
                       const ResObject::Kind &kind,
-                      const std::string &name,
-                      const std::string & repo = "")
+                      const string &name,
+                      const string & repo = "",
+                      const string & arch = "")
 {
   // name and kind match:
-  DBG << "Iterating over [" << kind << "]" << name << endl;
+  DBG << "Iterating over [" << kind << "] " << name;
+  if (!repo.empty())
+    DBG << ", repo: " << repo;
+  if (!arch.empty())
+    DBG << ", arch: " << arch;
+  DBG << "...";
 
   PoolQuery q;
   q.addAttribute(sat::SolvAttr::name, name);
   if (!repo.empty())
     q.addRepo(repo);
+  if (!arch.empty())
+    q.addAttribute(sat::SolvAttr::arch, arch);
   q.setCaseSensitive(false);
   q.setMatchExact();
 
-  DBG << "... done" << endl;
-
   if (q.empty())
   {
+    DBG << "... done" << endl;
     zypper.out().error(
       // translators: meaning a package %s or provider of capability %s
       str::form(_("'%s' not found"), name.c_str()));
@@ -66,36 +74,24 @@ static void mark_for_install(Zypper & zypper,
   }
 
   ui::Selectable::Ptr s = *q.selectableBegin();
+  DBG << "... done" << endl;
+/*
+  for_(it, s->installedBegin(), s->installedEnd())
+  { cout << *it << endl; }
+  for_(it, s->availableBegin(), s->availableEnd())
+  { cout << *it << endl; }
+*/
   bool force = copts.count("force");
 
+
 #if USE_THE_ONE
   PoolItem candidate = s->candidateObj();
 #else
-  PoolItem candidate = findUpdateItem(God->pool(), s->installedObj());
-  if (!candidate)
-  {
-    if (force)
-    {
-      candidate = findInstalledItemInRepos(s->installedObj());
-      if (!candidate)
-      {
-        zypper.out().info(str::form(
-            // translators: %s-%s.%s is name-version.arch
-            _("Package %s-%s.%s not found in repositories, cannot reinstall."),
-            s->name().c_str(), s->installedObj().resolvable()->edition().c_str(),
-            s->installedObj().resolvable()->arch().c_str()));
-        zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-        return;
-      }
-    }
-    else
-      candidate = s->installedObj();
-  }
+  PoolItem candidate = findTheBest(God->pool(), *s);
 #endif
 
   if (s->installedObj() &&
-      s->installedObj().resolvable()->edition() == candidate.resolvable()->edition() &&
-      s->installedObj().resolvable()->arch() == candidate.resolvable()->arch() &&
+      equalNVRA(*s->installedObj().resolvable(), *candidate.resolvable()) &&
       !force)
   {
     // if it is broken install anyway, even if it is installed
@@ -108,12 +104,32 @@ static void mark_for_install(Zypper & zypper,
         _("skipping %s '%s' (the newest version already installed)"))
         % kind_to_string_localized(kind,1) % name));
   }
-  else if (!candidate.status().setToBeInstalled(zypp::ResStatus::USER) && !force)
+  else
   {
-      zypper.out().error(boost::str(
-        format(_("Failed to add '%s' to the list of packages to be installed."))
-        % name));
-      ERR << "Could not set " << name << " as to-be-installed" << endl;
+    if (force && !s->installedEmpty())
+    {
+      PoolItem repoitem = findInstalledItemInRepos(s->installedObj());
+      if (!repoitem)
+      {
+        zypper.out().info(str::form(
+            // translators: %s-%s.%s is name-version.arch
+            _("Package %s-%s.%s not found in repositories, cannot reinstall."),
+            s->name().c_str(), s->installedObj().resolvable()->edition().c_str(),
+            s->installedObj().resolvable()->arch().c_str()));
+        zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+        return;
+      }
+      else if (candidate.status().isInstalled())
+        candidate = repoitem;
+    }
+
+    if (!candidate.status().setToBeInstalled(zypp::ResStatus::USER) && !force)
+    {
+        zypper.out().error(boost::str(
+          format(_("Failed to add '%s' to the list of packages to be installed."))
+          % name));
+        ERR << "Could not set " << name << " as to-be-installed" << endl;
+    }
   }
 }
 
@@ -177,10 +193,11 @@ mark_by_name (Zypper & zypper,
               bool install_not_remove,
               const ResObject::Kind &kind,
               const string &name,
-              const string & repo = "")
+              const string & repo = "",
+              const string & arch = "")
 {
   if (install_not_remove)
-    mark_for_install(zypper, kind, name, repo);
+    mark_for_install(zypper, kind, name, repo, arch);
   else
     mark_for_uninstall(zypper, kind, name);
 }
@@ -281,14 +298,7 @@ mark_selectable(Zypper & zypper,
 #if USE_THE_ONE
   PoolItem theone = s.theObj();
 #else
-  PoolItem theone;
-  if (s.installedEmpty())
-    theone = *s.availableBegin();
-  else
-    theone = findUpdateItem(God->pool(), *s.installedBegin());
-
-  if (!theone)
-    theone = *s.installedBegin();
+  PoolItem theone = findTheBest(God->pool(), s);
 #endif
 
   DBG << "the One: " << theone << endl;
@@ -497,14 +507,22 @@ void install_remove(Zypper & zypper,
       force_by_name = true; // until there is a solver API for this
     }
 
-    //! \todo force arch with '.' or '@'???
-    if ((pos = str.find('.')) != string::npos)
-    { }
+    // force arch with '.'
+    if ((pos = str.rfind('.')) != string::npos)
+    {
+      arch = str.substr(pos + 1);
+      str = str.substr(0, pos);
+      if (Arch(arch).isBuiltIn())
+         force_by_name = true; // until there is a solver API for this
+      else
+        DBG << "Unknown arch (" << arch << ") in package " << str
+          << ", will treat it like capability name." << endl;
+    }
 
     // mark by name by force
     if (force_by_name)
     {
-      mark_by_name (zypper, install_not_remove, kind, str, repo);
+      mark_by_name (zypper, install_not_remove, kind, str, repo, arch);
       continue;
     }
 
index 14f98f2..67ea38c 100755 (executable)
@@ -171,7 +171,7 @@ static void list_patch_updates(Zypper & zypper)
         tr << patch->repoInfo().name();
         tr << res->name () << res->edition ().asString();
         tr << patch->category();
-        tr <<  _("Needed");        
+        tr <<  _("Needed");
 
         if (patch->restartSuggested ())
           pm_tbl << tr;
@@ -204,7 +204,7 @@ static void list_patch_updates(Zypper & zypper)
 
 /*
  * Collect items, select the best edition.
- * This is used to find the best available or installed pool item from a set. 
+ * This is used to find the best available or installed pool item from a set.
  */
 class SaveBetterEdition : public zypp::resfilter::PoolItemFilterFunctor
 {
@@ -228,7 +228,7 @@ public:
 
 // does not allow changing the arch (#222140).
 PoolItem
-findUpdateItem( const ResPool & pool, PoolItem item )
+findUpdateItem( const ResPool & pool, const PoolItem item )
 {
   SaveBetterEdition info;
 
@@ -246,6 +246,26 @@ findUpdateItem( const ResPool & pool, PoolItem item )
   return info.best;
 }
 
+PoolItem
+findTheBest( const ResPool & pool, const ui::Selectable & s)
+{
+  PoolItem theone;
+  if (s.installedEmpty())
+    theone = findUpdateItem(God->pool(), *s.availableBegin());
+  else
+    theone = findUpdateItem(God->pool(), *s.installedBegin());
+
+  if (!theone)
+  {
+    if (s.installedEmpty())
+      theone = *s.availableBegin();
+    else
+      theone = *s.installedBegin();
+  }
+
+  return theone;
+}
+
 // ----------------------------------------------------------------------------
 
 typedef set<PoolItem> Candidates;
@@ -575,7 +595,7 @@ mark_patch_updates( Zypper & zypper, bool skip_interactive )
     {
       DBG << "marking all needed patches" << endl;
 
-      for_(it, God->pool().proxy().byKindBegin(ResKind::patch), 
+      for_(it, God->pool().proxy().byKindBegin(ResKind::patch),
                God->pool().proxy().byKindEnd  (ResKind::patch))
       {
         if (mark_patch_update((*it)->candidateObj(), skip_interactive, ignore_affects_pm))
@@ -590,7 +610,7 @@ mark_patch_updates( Zypper & zypper, bool skip_interactive )
         PoolQuery q;
         q.addKind(ResKind::patch);
         q.addAttribute(sat::SolvAttr::name, *it);
-        //! \todo should we look for patches requiring packages with matching name instead? 
+        //! \todo should we look for patches requiring packages with matching name instead?
         //q.addAttribute(sat::SolvAttr::require, *it);
         q.setMatchGlob();
 
@@ -650,7 +670,7 @@ void mark_updates(Zypper & zypper, const ResKindSet & kinds, bool skip_interacti
           invokeOnEach (candidates.begin(), candidates.end(), require_item_update);
         else
           invokeOnEach (candidates.begin(), candidates.end(), mark_item_install);
-      } 
+      }
     }
   }
   // treat arguments as package names (+allow wildcards)
@@ -666,7 +686,7 @@ void mark_updates(Zypper & zypper, const ResKindSet & kinds, bool skip_interacti
         q.addAttribute(sat::SolvAttr::name, *it);
         q.setMatchGlob();
         q.setInstalledOnly();
-  
+
         if (q.empty())
         {
           if (it->find_first_of("?*") != string::npos) // wildcards used
@@ -684,14 +704,7 @@ void mark_updates(Zypper & zypper, const ResKindSet & kinds, bool skip_interacti
 #if USE_THE_ONE
             PoolItem theone = s.theObj();
 #else
-            PoolItem theone;
-            
-            if (s->installedEmpty())
-              theone = *s->availableBegin();
-            else
-              theone = findUpdateItem(God->pool(), *s->installedBegin());
-            if (!theone)
-              theone = *s->installedBegin();
+            PoolItem theone = findTheBest(God->pool(), *s);
 #endif
 
             if (equalNVRA(*s->installedObj().resolvable(), *theone.resolvable()))
index 0537e76..cc3fd16 100755 (executable)
@@ -14,7 +14,7 @@ void patch_check();
  * if repo_alias != "", restrict updates to this repository.
  * if best_effort == true, any version greater than the installed one will do.
  * Prints the table of updates to stdout.
- * 
+ *
  * \param kind  resolvable type
  * \param best_effort
  */
@@ -22,7 +22,7 @@ void list_updates(Zypper & zypper,
                   const ResKindSet & kinds,
                   bool best_effort);
 
-/** \todo remove from this header after xu is dropped */ 
+/** \todo remove from this header after xu is dropped */
 bool xml_list_patches();
 /** \todo remove from this header after xu is dropped */
 void xml_list_updates(const ResKindSet & kinds);
@@ -40,8 +40,18 @@ void mark_updates(Zypper & zypper,
 /**
  * Find best (according to edition) uninstalled item
  * with same kind/name/arch as \a item.
- * 
+ *
  * Similar to zypp::solver::detail::Helper::findUpdateItem()
  * but allows changing the vendor and does not allow chaning arch.
  */
-zypp::PoolItem findUpdateItem(const zypp::ResPool & pool, zypp::PoolItem item);
+zypp::PoolItem findUpdateItem(const zypp::ResPool & pool, const zypp::PoolItem item);
+
+/**
+ * Finds the best object in the Selectable.
+ *
+ * \todo FIXME if there is no installed object in the selectable, it chooses
+ *       a random arch from the available objects (the availableBegin()). Choose
+ *       the best compatible instead.
+ * \todo All of this should be done in libzypp, using defined policies.
+ */
+zypp::PoolItem findTheBest( const zypp::ResPool & pool, const zypp::ui::Selectable & s);