- Take into account the requirements of all obsoleted packages uninstall
[platform/upstream/libzypp.git] / zypp / solver / detail / InstallOrder.cc
index 3cec612..68925f2 100644 (file)
 /-*/
 
 #include "zypp/solver/detail/InstallOrder.h"
-#include "zypp/base/Logger.h"
+#include "zypp/base/LogTools.h"
 #include "zypp/base/Iterator.h"
 #include "zypp/base/Algorithm.h"
 
+#include "zypp/solver/detail/SATResolver.h"
+
 #include "zypp/ResFilters.h"
 #include "zypp/ResStatus.h"
+#include "zypp/NameKindProxy.h"
+#include "zypp/sat/Pool.h"
+#include <zypp/sat/WhatObsoletes.h>
 
 /////////////////////////////////////////////////////////////////////////
 namespace zypp
@@ -64,7 +69,7 @@ InstallOrder::InstallOrder( const ResPool & pool, const PoolItemSet & toinstall,
 
 //-----------------------------------------------------------------------------
 
-const void
+void
 InstallOrder::printAdj (std::ostream& os, bool reversed) const
 {
     const Graph& g = (reversed ? _rgraph : _graph);
@@ -98,9 +103,9 @@ InstallOrder::computeNextSet()
     for (Nodes::iterator it = _nodes.begin(); it != _nodes.end(); ++it)
     {
        if (it->second.order == 0
-           && it->second.item)                 // the default Nodes constructor leaves this empty 
+           && it->second.item)                 // the default Nodes constructor leaves this empty
        {
-           DBG << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl;
+           XXX << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl;
 
            newlist.push_back(it->second.item);
        }
@@ -112,13 +117,13 @@ InstallOrder::computeNextSet()
 
 // decrease order of every adjacent node
 void
-InstallOrder::setInstalled(PoolItem_Ref item )
+InstallOrder::setInstalled(PoolItem item )
 {
     _dirty = true;
 
     PoolItemList adj = _rgraph[item];
 
-    DBG << "InstallOrder::setInstalled " << ITEMNAME(item) << endl;
+    XXX << "InstallOrder::setInstalled " << ITEMNAME(item) << endl;
 
     // order will be < 0
     _nodes[item].order--;
@@ -131,7 +136,7 @@ InstallOrder::setInstalled(PoolItem_Ref item )
        info.order--;
        if (info.order < 0)
        {
-           DBG << "order of node " << (*it) << " is < 0" << endl;
+           WAR << "order of node " << (*it) << " is < 0" << endl;
        }
     }
 }
@@ -149,19 +154,19 @@ InstallOrder::setInstalled( const PoolItemList & rl )
 //-----------------------------------------------------------------------------
 
 bool
-InstallOrder::doesProvide( const Capability requirement, PoolItem_Ref item ) const
+InstallOrder::doesProvide( const Capability requirement, PoolItem item ) const
 {
-    CapSet::const_iterator pend = item->dep( Dep::PROVIDES ).end();
-    for( CapSet::const_iterator pit = item->dep( Dep::PROVIDES ).begin(); pit != pend; ++pit) {
+    Capabilities::const_iterator pend = item->dep( Dep::PROVIDES ).end();
+    for( Capabilities::const_iterator pit = item->dep( Dep::PROVIDES ).begin(); pit != pend; ++pit) {
        if( pit->matches( requirement ) == CapMatch::yes ) {
            return item;
        }
     }
-    return PoolItem_Ref();
+    return PoolItem();
 }
 
 
-PoolItem_Ref
+PoolItem
 InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const
 {
     for( PoolItemSet::const_iterator citer = candidates.begin(); citer != candidates.end(); citer++) {
@@ -170,53 +175,19 @@ InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet
        }
     }
 
-    return PoolItem_Ref();
+    return PoolItem();
 }
 
-struct CollectProviders : public resfilter::OnCapMatchCallbackFunctor
-{
-    const PoolItem_Ref requestor;
-    PoolItemList & tovisit;   
-    PoolItemSet & toinstall;
-    PoolItemSet & installed;
-
-    CollectProviders (const PoolItem_Ref pi, PoolItemList & tv, PoolItemSet & ti, PoolItemSet & i)
-       : requestor (pi)
-       , tovisit (tv)
-       , toinstall (ti)
-       , installed (i)
-    { }
-
-
-    bool operator()( PoolItem_Ref provider, const Capability & match )
-    {
-       // item provides cap which matches a requirement from info->requestor
-       //   this function gets _all_ providers and filter out those which are
-       //   either installed or in our toinstall input list
-       //
-XXX << "info(" << provider <<")"<< endl;
-       if ((provider.resolvable() != requestor.resolvable())           // resolvable could provide its own requirement
-           && (toinstall.find( provider ) != toinstall.end()           // only look at resolvables
-               || installed.find( provider ) != installed.end())) {    //   we are currently considering anyways
-           XXX << "tovisit " << ITEMNAME(provider) << endl;
-           tovisit.push_back (provider);
-       }
-
-       return true;
-    }
-
-};
-
 //-----------------------------------------------------------------------------
 
 
 void
-InstallOrder::rdfsvisit (const PoolItem_Ref item)
+InstallOrder::rdfsvisit (const PoolItem item)
 {
     typedef list<Capability> CapList;
     CapList requires;
 
-    DBG << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl;
+    XXX << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl;
 
     NodeInfo& nodeinfo = _nodes[item];
 
@@ -224,69 +195,78 @@ InstallOrder::rdfsvisit (const PoolItem_Ref item)
     nodeinfo.begintime = _rdfstime;
     _rdfstime++;
 
+    // items prereq
+    CapabilitySet prq( item->dep(Dep::PREREQUIRES).begin(), item->dep(Dep::PREREQUIRES).end() );
+    // any obsoleted items prereq (in case they are reqired for uninstall scripts)
+    sat::WhatObsoletes obs( item );
+    for_( it, obs.begin(), obs.end() )
+    {
+      Capabilities p( it->prerequires() );
+      prq.insert( p.begin(), p.end() );
+    }
     // put prerequires first and requires last on list to ensure
     // that prerequires are processed first
-
-    for (CapSet::const_iterator it = item->dep (Dep::PREREQUIRES).begin(); it != item->dep (Dep::PREREQUIRES).end(); ++it)
+    for (CapabilitySet::const_iterator it = prq.begin(); it != prq.end(); ++it)
     {
-       const Capability cap = *it;
-       requires.push_back(cap);
+       requires.push_back(*it);
     }
 
-    for (CapSet::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it)
-    {
-       const Capability cap = *it;
-       requires.push_back(cap);
-    }
+    // Product requirements are ignored to assert Product gets installed
+    // as early as possible. Some stuff depends on it (e.g. registration).
+    if ( ! isKind<Product>( item.resolvable() ) )
+      {
+        for (Capabilities::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it)
+          {
+            requires.push_back(*it);
+          }
+      }
 
     for (CapList::const_iterator iter = requires.begin(); iter != requires.end(); ++iter)
     {
+        bool goBack = false;
        const Capability requirement = *iter;
+        PoolItemList providers;
+
        XXX << "check requirement " << requirement << " of " << ITEMNAME(item) << endl;
+        SATResolver satResolver(_pool, sat::Pool::instance().get());
        PoolItemList tovisit;
-
-#if 0
-       // _world->foreachProvidingResItem (requirement, collect_providers, &info);
-       Dep dep (Dep::PROVIDES);
-       invokeOnEach( _pool.byCapabilityIndexBegin( requirement.index(), dep ),
-                     _pool.byCapabilityIndexEnd( requirement.index(), dep ),
-                     resfilter::callOnCapMatchIn( dep, requirement, functor::functorRef<bool,PoolItem,Capability>(info) ) );
-#endif
-#if 1
-       CollectProviders info ( item, tovisit, _toinstall, _installed );
-
-       ResPool::const_indexiterator pend = _pool.providesend(requirement.index());
-       for (ResPool::const_indexiterator it = _pool.providesbegin(requirement.index()); it != pend; ++it) {
-           if (it->second.second->arch() == Arch_src)
-               continue;
-           if (requirement.matches (it->second.first) == CapMatch::yes) {
-               if (!info( it->second.second, it->second.first))
-                   break;
-           }
-       }
-#endif
-#if 0
-       // item could provide its own requirement
-       if( doesProvide( requirement, item ) ) {
-               XXX << "self-provides " << endl;
-//             tovisit.push_back(node);
+        sat::WhatProvides possibleProviders(requirement);
+
+       // first, look in _installed
+        for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
+            PoolItem provider = ResPool::instance().find( *iter );
+            if ( provider == item )
+            {
+              goBack = true;
+              break;
+            }
+            if (_installed.find( provider ) != _installed.end())       // and is not installed
+            {
+                XXX << "tovisit " << ITEMNAME(provider) << endl;
+                providers.push_back (provider);
+            }
+        }
+
+        if ( goBack )
+          continue;
+
+       // if not found in _installed, look in _toinstall
+
+       if (providers.empty()) {
+            for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
+                PoolItem provider = ResPool::instance().find( *iter );
+                if ((provider.resolvable() != item.resolvable())               // resolvable could provide its own requirement
+                    && (_toinstall.find( provider ) != _toinstall.end()))      // and is not to be installed
+                {
+                    XXX << "tovisit " << ITEMNAME(provider) << endl;
+                    tovisit.push_back (provider);
+                }
+            }
        }
-       else {
-           PoolItem_Ref provider = findProviderInSet( requirement, _installed );
 
-           if (!provider)
-           {
-               provider = findProviderInSet( requirement, _toinstall );
-               if (provider) {
-                   XXX << "provided by " << ITEMNAME(provider) << endl;
-                   tovisit.push_back( provider );
-               }
-           }
-       }
-#endif
        for (PoolItemList::iterator it = tovisit.begin(); it != tovisit.end(); ++it)
        {
-           const PoolItem_Ref must_visit = *it;
+           const PoolItem must_visit = *it;
            if (_nodes[must_visit].visited == false)
            {
                nodeinfo.order++;
@@ -298,9 +278,14 @@ InstallOrder::rdfsvisit (const PoolItem_Ref item)
            {
                if (must_visit != item)
                {
-                   ERR << "*************************************************************" << endl;
-                   ERR << "** dependency loop: " << ITEMNAME(item) << " -> " << ITEMNAME(must_visit) << endl;
-                   ERR << "*************************************************************" << endl;
+                 // log only the 1st occurrence.
+                 std::string lstr( ITEMNAME(item) );
+                 lstr += " -> ";
+                 lstr += ITEMNAME(must_visit);
+                 if ( _logset.insert( lstr ).second )
+                 {
+                   WAR << "** dependency loop: " << lstr << endl;
+                 }
                }
            }
            else
@@ -323,7 +308,7 @@ InstallOrder::rdfsvisit (const PoolItem_Ref item)
     _nodes[item].endtime = _rdfstime;
     _rdfstime++;
 
-    DBG << ITEMNAME(item) << " done" << endl;
+    XXX << ITEMNAME(item) << " done" << endl;
 }
 
 
@@ -339,12 +324,12 @@ InstallOrder::startrdfs()
     _topsorted.clear();
 
     _numrun++;
-    DBG << "run #" << _numrun << endl;
+    XXX << "run #" << _numrun << endl;
 
     // initialize all nodes
     for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
     {
-       PoolItem_Ref item = *it;
+       PoolItem item = *it;
        _nodes[item] = NodeInfo (item);
        _rgraph[item] = PoolItemList();
        _graph[item] = PoolItemList();
@@ -353,10 +338,10 @@ InstallOrder::startrdfs()
     // visit all nodes
     for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
     {
-       const PoolItem_Ref item = *it;
+       const PoolItem item = *it;
        if (_nodes[item].visited == false)
        {
-           DBG << "start recursion on " << ITEMNAME(item) << endl;
+           XXX << "start recursion on " << ITEMNAME(item) << endl;
            rdfsvisit (item);
        }
     }