[Apt-Rpm] multiple good providers, how does apt pick the right one?

Panu Matilainen pmatilai at laiskiainen.org
Sun Feb 24 05:56:43 PST 2008


On Sat, 23 Feb 2008, Panu Matilainen wrote:
>
> Whether it's reasonably possible to have Lua-hook in the lowlevel depsolve
> logic remains to be seen, but a C++-level callback shouldn't have such
> problems. It'd be sad if Lua can't be used but (optional) app-specific
> callback would still enable what you want, so not all hope is lost anyway
> :)

...and here's the first rough-cut of the C++ callback approach this time 
batter^H^H^H^H^H^H patch included.

There are all sorts of nitty details to sort out, such as dealing with -y 
and it's variants in semi-intelligent manner and probably some more 
fundamental issues too but at least you'll get to play around with it a 
bit.

Haven't done any extensive testing, just some basic "seems to do what 
intended" runs so watch out for any falling pieces :)

 	- Panu -
-------------- next part --------------
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 758612c..40dea40 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -26,15 +26,27 @@
     
 #include <apti18n.h>    
 									/*}}}*/
+/*
+ * Default callback for multiple good providers: just pick whatever's first..
+ */
+static pkgCache::Package * pkgDefaultProviderCb(
+                                  pkgDepCache * const Cache,
+                                  pkgCache::DepIterator Dep,
+                                  const vector<pkgCache::Package *> Providers)
+{
+   return Providers[0];
+}
 
 // DepCache::pkgDepCache - Constructors					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
-                Cache(pCache), PkgState(0), DepState(0)
+                Cache(pCache), PkgState(0), DepState(0),
+	        SelectProvider(pkgDefaultProviderCb)
 {
    delLocalPolicy = 0;
    LocalPolicy = Plcy;
+   
    if (LocalPolicy == 0)
       delLocalPolicy = LocalPolicy = new Policy;
 }
@@ -109,6 +121,13 @@ bool pkgDepCache::Init(OpProgress *Prog)
    return true;
 } 
 									/*}}}*/
+pkgSelectProviderFunction pkgDepCache::SetProviderCallback(pkgSelectProviderFunction cb)
+{
+   pkgSelectProviderFunction oldCb = SelectProvider;
+   SelectProvider = cb;
+   return oldCb;
+}
+
 
 // DepCache::CheckDep - Checks a single dependency			/*{{{*/
 // ---------------------------------------------------------------------
@@ -733,6 +752,7 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge)
    Update(Pkg);
    AddSizes(Pkg);
 }
+
 									/*}}}*/
 // DepCache::MarkInstall - Put the package in the install state		/*{{{*/
 // ---------------------------------------------------------------------
@@ -849,14 +869,29 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
 	 // Select the highest priority providing package
 	 if (InstPkg.end() == true)
 	 {
+	    vector<pkgCache::Package *> Providers;
 	    pkgPrioSortList(*Cache,Cur);
 	    for (; *Cur != 0; Cur++)
 	    {
 	       PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
 	       if (PkgState[Pkg->ID].CandidateVer != *Cur)
 		  continue;
-	       InstPkg = Pkg;
-	       break;
+	       Providers.push_back(Pkg);
+	    }
+
+	    int numprov = Providers.size();
+	    if (numprov == 1) {
+	       pkgCache::PkgIterator GoodPkg(*Cache, Providers[0]);
+	       InstPkg = GoodPkg;
+	    } else if (numprov > 1) {
+	       pkgCache::Package * selected;
+	       selected = SelectProvider(this, Start, Providers);
+	       if (! selected) {
+		  cout << "Oops, SelectProvider() didn't select" << endl;
+		  selected = pkgDefaultProviderCb(this, Start, Providers);
+	       }
+	       pkgCache::PkgIterator GoodPkg(*Cache, selected);
+	       InstPkg = GoodPkg;
 	    }
 	 }
 	 
@@ -1093,6 +1128,5 @@ void pkgDepCache::State::UnIgnoreAll()
    memset(PkgIgnore, 0, Dep->Head().PackageCount*sizeof(*PkgIgnore));
 }
 
-									/*}}}*/
 
 // vim:sts=3:sw=3
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
index 8f814e7..da11dc7 100644
--- a/apt-pkg/depcache.h
+++ b/apt-pkg/depcache.h
@@ -42,9 +42,20 @@
 #pragma interface "apt-pkg/depcache.h"
 #endif
 
+#include <vector>
+
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/progress.h>
 
+using std::vector;
+
+class pkgDepCache;
+class pkgCache;
+typedef pkgCache::Package * (*pkgSelectProviderFunction) 
+			    (pkgDepCache * const Cache,
+			     pkgCache::DepIterator Dep,
+			     const vector<pkgCache::Package *> Providers);
+
 class pkgDepCache : protected pkgCache::Namespace
 {
    public:
@@ -141,6 +152,8 @@ class pkgDepCache : protected pkgCache::Namespace
    
    Policy *delLocalPolicy;           // For memory clean up..
    Policy *LocalPolicy;
+ 
+   pkgSelectProviderFunction SelectProvider;
    
    // Check for a matching provides
    bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res);
@@ -165,9 +178,10 @@ class pkgDepCache : protected pkgCache::Namespace
    inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);}
    void AddStates(const PkgIterator &Pkg,int Add = 1);
    inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);}
-   
+
    public:
 
+   pkgSelectProviderFunction SetProviderCallback(pkgSelectProviderFunction cb);
    // CNC:2003-02-23 - See below.
    class State;
    friend class State;
@@ -280,7 +294,6 @@ class pkgDepCache::State
       }
 };
 
-
 /* This is an exact copy of the structure above, nested in pkgDepCache.
  * This is defined again here since SWIG doesn't know how to handle nested
  * structures yet. It will be dropped once that situation changes. */
diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc
index 031950b..a3b1f56 100644
--- a/cmdline/apt-get.cc
+++ b/cmdline/apt-get.cc
@@ -90,6 +90,8 @@ class CacheFile : public cmdCacheFile
       if (pkgCacheFile::Open(Prog,WithLock) == false)
 	 return false;
       Sort();
+
+      DCache->SetProviderCallback(cmdSelectProvider);
       
       return true;
    }
diff --git a/cmdline/cmdline.cc b/cmdline/cmdline.cc
index 71fd14e..284a2a4 100644
--- a/cmdline/cmdline.cc
+++ b/cmdline/cmdline.cc
@@ -1935,4 +1935,36 @@ bool cmdChangeLog(CommandLine &CmdL, pkgCache &Cache)
    return true;
 }
 
+pkgCache::Package * cmdSelectProvider(
+                                  pkgDepCache * const Cache,
+                                  pkgCache::DepIterator Dep,
+                                  const vector<pkgCache::Package *> Providers)
+{
+   ioprintf(cout,_("Package %s is a virtual package provided by:\n"),
+	    Dep.TargetPkg().Name());
+
+   size_t numProv = Providers.size();
+   vector<pkgCache::Package *>::const_iterator P = Providers.begin();
+   for (; P != Providers.end(); P++) {
+      pkgCache::PkgIterator GoodPkg(*Cache, (*P));
+      cout << (P - Providers.begin()) + 1 << ". " << GoodPkg.Name() << endl;
+   }
+
+   size_t selection = 0;
+   while (selection < 1) {
+      size_t inp;
+      ioprintf(cout, _("Select one of 1-%zu: "), numProv);
+      if (!(cin >> inp)) {
+	 cin.clear();
+	 cin.ignore(256,'\n');
+	 continue;
+      }
+      if (inp > 0 && inp <= numProv)
+	 selection = inp;
+   }
+
+   return Providers[selection-1];
+}
+
+
 // vim:sts=3:sw=3
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 7f7808a..b7d884e 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -93,5 +93,9 @@ bool cmdSearchFile(CommandLine &CmdL, pkgCache &Cache);
 bool cmdFileList(CommandLine &CmdL, pkgCache &Cache);
 bool cmdChangeLog(CommandLine &CmdL, pkgCache &Cache);
 
+pkgCache::Package * cmdSelectProvider(
+                                  pkgDepCache * const Cache,
+                                  pkgCache::DepIterator Dep,
+                                  const vector<pkgCache::Package *> Providers);
 
 // vim:sts=3:sw=3


More information about the Apt-Rpm mailing list