Do commit based on sat::Transaction.
authorMichael Andres <ma@suse.de>
Tue, 31 May 2011 15:25:08 +0000 (17:25 +0200)
committerMichael Andres <ma@suse.de>
Tue, 31 May 2011 15:25:08 +0000 (17:25 +0200)
zypp/ZYppCommitResult.cc
zypp/ZYppCommitResult.h
zypp/sat/Transaction.cc
zypp/sat/Transaction.h
zypp/target/TargetImpl.cc
zypp/target/TargetImpl.h

index 8431424..33a79ed 100644 (file)
@@ -11,6 +11,7 @@
 */
 
 #include <iostream>
+#include "zypp/base/LogTools.h"
 
 #include "zypp/ZYppCommitResult.h"
 
@@ -32,6 +33,8 @@ namespace zypp
 
     public:
       Pathname                 _root;
+      sat::Transaction          _transaction;
+      TransactionStepList       _transactionStepList;
       UpdateNotifications      _updateMessages;
 
     private:
@@ -57,22 +60,86 @@ namespace zypp
   const Pathname & ZYppCommitResult::root() const
   { return _pimpl->_root; }
 
+  const sat::Transaction & ZYppCommitResult::transaction() const
+  { return _pimpl->_transaction; }
+
+  sat::Transaction & ZYppCommitResult::rTransaction()
+  { return _pimpl->_transaction; }
+
+  const ZYppCommitResult::TransactionStepList & ZYppCommitResult::transactionStepList() const
+  { return _pimpl->_transactionStepList; }
+
+  ZYppCommitResult::TransactionStepList & ZYppCommitResult::rTransactionStepList()
+  { return _pimpl->_transactionStepList; }
+
   const UpdateNotifications & ZYppCommitResult::updateMessages() const
   { return _pimpl->_updateMessages; }
 
-  UpdateNotifications & ZYppCommitResult::setUpdateMessages()
+  UpdateNotifications & ZYppCommitResult::rUpdateMessages()
   { return _pimpl->_updateMessages; }
 
+  ZYppCommitResult::InsDelCnt ZYppCommitResult::totalCount() const
+  {
+    InsDelCnt ret;
+    for_( it, _pimpl->_transaction.actionBegin(), _pimpl->_transaction.actionEnd() )
+    {
+      ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? ret.second : ret.first );
+    }
+
+    return ret;
+  }
+
+  ZYppCommitResult::InsDelCnt ZYppCommitResult::stepStageCount( sat::Transaction::StepStage stage_r ) const
+  {
+    InsDelCnt ret;
+    for_( it, _pimpl->_transaction.actionBegin(), _pimpl->_transaction.actionEnd() )
+    {
+      if ( it->stepStage() != stage_r )
+       continue;
+      ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? ret.second : ret.first );
+    }
+    return ret;
+  }
+
+  void  ZYppCommitResult::resultCount( InsDelCnt & total_r, InsDelCnt & done_r, InsDelCnt & error_r, InsDelCnt & skipped_r ) const
+  {
+    total_r = done_r = error_r = skipped_r = InsDelCnt();
+    for_( it, _pimpl->_transaction.actionBegin(), _pimpl->_transaction.actionEnd() )
+    {
+      ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? total_r.second : total_r.first );
+      switch ( it->stepStage() )
+      {
+       case sat::Transaction::STEP_DONE:
+         ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? done_r.second : done_r.first );
+         break;
+       case sat::Transaction::STEP_ERROR:
+         ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? error_r.second : error_r.first );
+         break;
+       case sat::Transaction::STEP_TODO:
+         ++( it->stepType() == sat::Transaction::TRANSACTION_ERASE ? skipped_r.second : skipped_r.first );
+         break;
+      }
+    }
+  }
+
   ///////////////////////////////////////////////////////////////////
 
+  std::ostream & operator<<( std::ostream & str, const ZYppCommitResult::InsDelCnt & obj )
+  { return str << obj.first << '/' << obj.second; }
+
   std::ostream & operator<<( std::ostream & str, const ZYppCommitResult & obj )
   {
-    str << "CommitResult " << obj._result
-        << " (errors " << obj._errors.size()
-        << ", remaining " << obj._remaining.size()
-        << ", srcremaining " << obj._srcremaining.size()
+    ZYppCommitResult::InsDelCnt result[4];
+    obj.resultCount( result[0], result[1], result[2], result[3] );
+
+    str << "CommitResult "
+        << " (ins/del total " << result[0]
+        << ", done " << result[1]
+        << ", error " << result[2]
+        << ", skipped " << result[3]
         << ", updateMessages " << obj.updateMessages().size()
-        << ")";
+        << ")"
+        << std::endl << obj.transaction();
     return str;
   }
 
index 81f6559..23ec5c2 100644 (file)
 #define ZYPP_ZYPPCOMMITRESULT_H
 
 #include <iosfwd>
+#include <vector>
 #include <list>
 
 #include "zypp/PoolItem.h"
+#include "zypp/sat/Transaction.h"
+#include "zypp/base/DefaultIntegral.h"
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
+  namespace sat
+  {
+    class Transaction;
+  }
+
   /** Pair of \ref sat::Solvable and \ref Pathname. */
   class UpdateNotificationFile
   {
@@ -44,12 +52,19 @@ namespace zypp
   //
   /** Result returned from ZYpp::commit.
    *
+   * \note Transaction data are provided and maintained during commit.
+   * Though the interface does not inhibit manipulation of transaction
+   * data outside commit (those methods could have been made \c private:),
+   * this is not recommended as you may easily mess up things.
+   *
    * \see \ref ZYpp::commit
-   * \todo document fields.
    */
   class ZYppCommitResult
   {
     public:
+      typedef std::vector<sat::Transaction::Step> TransactionStepList;
+
+    public:
       ZYppCommitResult();
       ZYppCommitResult( const Pathname & root_r );
 
@@ -60,6 +75,26 @@ namespace zypp
       */
       const Pathname & root() const;
 
+      /** The full transaction list.
+       * The complete list including transaction steps that do not require
+       * any action (like obsoletes or non-package actions). Depending on
+       * \ref ZYppCommitPolicy::restrictToMedia only a subset of this
+       * transaction might have been executed.
+       * \see \ref transactionStepList.
+       */
+      const sat::Transaction & transaction() const;
+
+      /** Manipulate \ref transaction */
+      sat::Transaction & rTransaction();
+
+      /** List of \ref sat::Transaction::Step to be executed by commit.
+       * The list of transaction step commit actually tried to execute.
+       */
+      const TransactionStepList & transactionStepList() const;
+
+      /** Manipulate \ref transactionStepList. */
+      TransactionStepList & rTransactionStepList();
+
       /** List of update messages installed during this commit.
        * \Note Pathnames are relative to the targets root directory.
        * \code
@@ -89,32 +124,65 @@ namespace zypp
        */
       const UpdateNotifications & updateMessages() const;
 
-      /** Change list of update messages installed during this commit.
+      /** Manipulate \ref updateMessages
        * \Note Pathnames are relative to the targets root directory.
        */
-      UpdateNotifications & setUpdateMessages();
+      UpdateNotifications & rUpdateMessages();
+
+    public:
+
+      /** \name Some statistics based on \ref transaction
+       */
+      //@{
+       /** Basically std::pair<unsigned,unsigned>, but default ctor sets <0,0>. */
+       typedef std::pair<DefaultIntegral<unsigned,0>, DefaultIntegral<unsigned,0> > InsDelCnt;
+
+       /** Total number of install/delete actions to be performed. */
+       InsDelCnt totalCount() const;
+
+       /** Number of install/delete actions with result \a stage_r. */
+       InsDelCnt stepStageCount( sat::Transaction::StepStage stage_r ) const;
+
+       /** Number of install/delete actions done. */
+       InsDelCnt doneCount() const
+       { return stepStageCount( sat::Transaction::STEP_DONE ); }
+
+       /** Number of install/delete actions that failed with error. */
+       InsDelCnt errorCount() const
+       { return stepStageCount( sat::Transaction::STEP_ERROR ); }
+
+       /** Number of install/delete actions that were skipped (e.g. due to unwanted media). */
+       InsDelCnt skippedCount() const
+       { return stepStageCount( sat::Transaction::STEP_TODO ); }
+
+       /** All in one go. */
+       void resultCount( InsDelCnt & total_r, InsDelCnt & done_r, InsDelCnt & error_r, InsDelCnt & skipped_r ) const;
+      //@}
 
     public:
       /** \name Oldstlye interface to be removed asap.
+       * \deprecated PoolItem is not suitable for reporting errors about
+       * packages to be deteled, as reloading the rpm database after commit
+       * invalidates them.
        */
       //@{
       typedef std::list<PoolItem> PoolItemList;
       /**
        * number of committed resolvables
        **/
-      int          _result;
+      int          _result ZYPP_DEPRECATED;
       /**
        * list of resolvables with error
        **/
-      PoolItemList _errors;
+      PoolItemList _errors ZYPP_DEPRECATED;
       /**
        * list of resolvables remaining (due to wrong media)
        **/
-      PoolItemList _remaining;
+      PoolItemList _remaining ZYPP_DEPRECATED;
       /**
        * list of kind:source resolvables remaining (due to wrong media)
        **/
-      PoolItemList _srcremaining;
+      PoolItemList _srcremaining ZYPP_DEPRECATED;
       //@}
 
     public:
index 99ece4d..a4c19c8 100644 (file)
@@ -35,15 +35,36 @@ namespace zypp
   { /////////////////////////////////////////////////////////////////
 
     /** Transaction implementation.
-     * \todo check whether the pool serial number changed!
+     *
+     * \NOTE After commit the @System repo is reloaded. This invalidates
+     * the ids off all installed items in the transaction, including their
+     * stepType. Thats why some information (stepType, NVRA) is be stored
+     * for post mortem access (i.e. tell after commit which NVRA were deleted).
+     *
      */
     struct Transaction::Impl : protected detail::PoolMember
     {
       friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
 
       public:
-      typedef std::tr1::unordered_set<detail::IdType> set_type;
-      typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
+       typedef std::tr1::unordered_set<detail::IdType> set_type;
+       typedef std::tr1::unordered_map<detail::IdType,detail::IdType> map_type;
+
+       struct PostMortem
+       {
+         PostMortem()
+         {}
+         PostMortem( const sat::Solvable & solv_r )
+           : _ident( solv_r.ident() )
+           , _edition( solv_r.edition() )
+           , _arch( solv_r.arch() )
+         {}
+
+         IdString _ident;
+         Edition  _edition;
+         Arch     _arch;
+       };
+       typedef std::tr1::unordered_map<detail::IdType,PostMortem> pmmap_type;
 
       public:
        Impl()
@@ -60,6 +81,7 @@ namespace zypp
          for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
          {
            sat::Solvable solv( *it );
+           // buddy list:
            if ( ! solv.isKind<Package>() )
            {
              PoolItem pi( solv );
@@ -68,6 +90,16 @@ namespace zypp
                _linkMap[*it] = pi.buddy().id();
              }
            }
+           if ( solv.isSystem() )
+           {
+             // to delete list:
+             if ( stepType( solv ) == TRANSACTION_ERASE )
+             {
+               _systemErase.insert( *it );
+             }
+             // post mortem data
+             _pmMap[*it] = solv;
+           }
          }
        }
 
@@ -145,23 +177,15 @@ namespace zypp
        iterator find(const RW_pointer<Transaction::Impl> & self_r, const sat::Solvable & solv_r )
        { detail::IdType * it( _find( solv_r ) ); return it ? iterator( self_r, it ) : end( self_r ); }
 
-      private:
-       detail::IdType * _find( const sat::Solvable & solv_r ) const
+      public:
+       StepType stepType( Solvable solv_r ) const
        {
-         if ( solv_r && _trans.steps.elements )
+         if ( ! solv_r )
          {
-           for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
-           {
-             if ( *it == detail::IdType(solv_r.id()) )
-               return it;
-           }
+           // post mortem @System solvable
+           return isIn( _systemErase, solv_r.id() ) ? TRANSACTION_ERASE : TRANSACTION_IGNORE;
          }
-         return 0;
-       }
 
-      public:
-       StepType stepType( Solvable solv_r ) const
-       {
          switch( ::transaction_type( &_trans, solv_r.id(), SOLVER_TRANSACTION_RPM_ONLY ) )
          {
            case SOLVER_TRANSACTION_ERASE: return TRANSACTION_ERASE; break;
@@ -177,8 +201,14 @@ namespace zypp
        void stepStage( Solvable solv_r, StepStage newval_r )
        { stepStage( resolve( solv_r ), newval_r ); }
 
-      private:
+       const PostMortem & pmdata( Solvable solv_r ) const
+       {
+         static PostMortem _none;
+         pmmap_type::const_iterator it( _pmMap.find( solv_r.id() ) );
+         return( it == _pmMap.end() ? _none : it->second );
+       }
 
+      private:
        detail::IdType resolve( const Solvable & solv_r ) const
        {
          map_type::const_iterator res( _linkMap.find( solv_r.id() ) );
@@ -213,14 +243,31 @@ namespace zypp
            }
          }
        }
+
+      private:
+       detail::IdType * _find( const sat::Solvable & solv_r ) const
+       {
+         if ( solv_r && _trans.steps.elements )
+         {
+           for_( it, _trans.steps.elements, _trans.steps.elements + _trans.steps.count )
+           {
+             if ( *it == detail::IdType(solv_r.id()) )
+               return it;
+           }
+         }
+         return 0;
+       }
+
      private:
        SerialNumberWatcher _watcher;
        mutable ::Transaction _trans;
        DefaultIntegral<bool,false> _ordered;
        //
-       set_type _doneSet;
-       set_type _errSet;
-       map_type _linkMap;
+       set_type        _doneSet;
+       set_type        _errSet;
+       map_type        _linkMap;       // buddy map to adopt buddies StepResult
+       set_type        _systemErase;   // @System packages to be eased (otherse are TRANSACTION_IGNORE)
+       pmmap_type      _pmMap;         // Post mortem data of deleted @System solvables
 
       public:
         /** Offer default Impl. */
@@ -317,8 +364,24 @@ namespace zypp
     void Transaction::Step::stepStage( StepStage val_r )
     { _pimpl->stepStage( _solv, val_r ); }
 
+    IdString Transaction::Step::ident() const
+    { return _solv ? _solv.ident() : _pimpl->pmdata(_solv )._ident; }
+
+    Edition Transaction::Step::edition() const
+    { return _solv ? _solv.edition() : _pimpl->pmdata(_solv )._edition; }
+
+    Arch Transaction::Step::arch() const
+    { return _solv ? _solv.arch() : _pimpl->pmdata(_solv )._arch; }
+
     std::ostream & operator<<( std::ostream & str, const Transaction::Step & obj )
-    { return str << obj.stepType() << obj.stepStage() << " " << PoolItem( obj.satSolvable() ); }
+    {
+      str << obj.stepType() << obj.stepStage() << " ";
+      if ( obj.satSolvable() )
+       str << PoolItem( obj.satSolvable() );
+      else
+       str << '[' << obj.ident() << '-' << obj.edition() << '.' << obj.arch() << ']';
+      return str;
+    }
 
     std::ostream & operator<<( std::ostream & str, Transaction::StepType obj )
     {
@@ -331,6 +394,7 @@ namespace zypp
        OUTS( TRANSACTION_MULTIINSTALL, [M] );
        #undef OUTS
       }
+      return str << "[?]";
     }
 
     std::ostream & operator<<( std::ostream & str, Transaction::StepStage obj )
@@ -343,6 +407,7 @@ namespace zypp
        OUTS( STEP_ERROR,       [**] );
        #undef OUTS
       }
+      return str << "[??]";
     }
     ///////////////////////////////////////////////////////////////////
     namespace detail
index e622023..31f1d22 100644 (file)
@@ -168,6 +168,13 @@ namespace zypp
 
 
     /** A single step within a \ref Transaction.
+     *
+     * \note After commit, when the @System repo (rpm database) is reread, all
+     * @System solvables within the transaction are invalidated (they got deleted).
+     * Thats why we internally store the NVRA, so you can access \ref ident
+     * (\see \ref sat::Solvable::ident), \ref edition, \ref arch of a deleted package,
+     * even if the \ref satSolvable itself is meanwhile invalid.
+     *
      * \see \ref Transaction.
      */
     class Transaction::Step
@@ -191,10 +198,32 @@ namespace zypp
        /** Set step action result. */
        void stepStage( StepStage val_r );
 
-       /** Return the corresponding \ref Solvable. */
+       /** Return the corresponding \ref Solvable (or.
+        *
+        */
        Solvable satSolvable() const
        { return _solv; }
 
+       /** \name Post mortem acccess to @System solvables
+        * \code
+        *   Transaction::Step step;
+        *   if ( step.satSolvable() )
+        *     std::cout << step.satSolvable() << endl;
+        *   else
+        *     std::cout << step.ident() << endl; // deleted @System solvable
+        * \endcode
+        */
+       //@{
+       /** \see \ref sat::Solvable::ident. */
+       IdString ident() const;
+
+       /** \see \ref sat::Solvable::edition. */
+       Edition edition() const;
+
+       /** \see \ref sat::Solvable::arch. */
+       Arch arch() const;
+       //@}
+
        /** Implicit conversion to \ref Solvable */
        operator const Solvable &() const { return _solv; }
        /** \overload nonconst */
index c05353d..b6a5a91 100644 (file)
@@ -9,6 +9,14 @@
 /** \file      zypp/target/TargetImpl.cc
  *
 */
+#ifdef _RPM_4_4
+#warning _RPM_4_4
+#else
+#ifdef _RPM_4_X
+#warning _RPM_4_X
+#endif
+#endif
+
 #include <iostream>
 #include <fstream>
 #include <sstream>
 #include "zypp/repo/SrcPackageProvider.h"
 
 #include "zypp/sat/Pool.h"
+#include "zypp/sat/Transaction.h"
 
 #include "zypp/PluginScript.h"
 
 using namespace std;
 
-
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
@@ -449,7 +457,7 @@ namespace zypp
 
             MIL << "Found update message " << *sit << endl;
             Pathname localPath( messagesPath_r/(*sit) ); // without root prefix
-            result_r.setUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
+            result_r.rUpdateMessages().push_back( UpdateNotificationFile( *it, localPath ) );
             historylog.comment( str::Str() << _("New update message") << " " << localPath, /*timestamp*/true );
           }
         }
@@ -1001,65 +1009,29 @@ namespace zypp
       ///////////////////////////////////////////////////////////////////
       // Compute transaction:
       ///////////////////////////////////////////////////////////////////
-
       ZYppCommitResult result( root() );
-      TargetImpl::PoolItemList to_uninstall;
-      TargetImpl::PoolItemList to_install;
-      TargetImpl::PoolItemList to_srcinstall;
-
-      {
-        pool::GetResolvablesToInsDel
-        collect( pool_r, policy_r.restrictToMedia() ? pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR
-                 : pool::GetResolvablesToInsDel::ORDER_BY_SOURCE );
-        MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
-        to_uninstall.swap ( collect._toDelete );
-        to_install.swap   ( collect._toInstall );
-        to_srcinstall.swap( collect._toSrcinstall );
-      }
-
+      result.rTransaction() = pool_r.resolver().getTransaction();
+      result.rTransaction().order();
+      // steps: this is our todo-list
+      ZYppCommitResult::TransactionStepList & steps( result.rTransactionStepList() );
       if ( policy_r.restrictToMedia() )
       {
-        MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
-
-        TargetImpl::PoolItemList current_install;
-        TargetImpl::PoolItemList current_srcinstall;
-
-        // Collect until the 1st package from an unwanted media occurs.
+       // Collect until the 1st package from an unwanted media occurs.
         // Further collection could violate install order.
-        bool hitUnwantedMedia = false;
-        for ( TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it )
-        {
-          ResObject::constPtr res( it->resolvable() );
-
-          if ( hitUnwantedMedia
-               || ( res->mediaNr() && res->mediaNr() != policy_r.restrictToMedia() ) )
-          {
-            hitUnwantedMedia = true;
-            result._remaining.push_back( *it );
-          }
-          else
-          {
-            current_install.push_back( *it );
-          }
-        }
-
-        for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
-        {
-          Resolvable::constPtr res( it->resolvable() );
-          Package::constPtr pkg( asKind<Package>(res) );
-          if ( pkg && policy_r.restrictToMedia() != pkg->mediaNr() ) // check medianr for packages only
-          {
-            result._srcremaining.push_back( *it );
-          }
-          else
-          {
-            current_srcinstall.push_back( *it );
-          }
-        }
-
-        to_install.swap   ( current_install );
-        to_srcinstall.swap( current_srcinstall );
+       MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
+#warning Also need to be able to compute ORDER_BY_MEDIANR
+       for_( it, result.transaction().begin(), result.transaction().end() )
+       {
+         if ( makeResObject( *it )->mediaNr() > 1 )
+           break;
+         steps.push_back( *it );
+       }
       }
+      else
+      {
+       result.rTransactionStepList().insert( steps.end(), result.transaction().begin(), result.transaction().end() );
+      }
+      MIL << "Todo: " << result << endl;
 
       ///////////////////////////////////////////////////////////////////
       // First collect and display all messages
@@ -1067,23 +1039,25 @@ namespace zypp
       ///////////////////////////////////////////////////////////////////
       if ( ! policy_r.dryRun() )
       {
-        for_( it, to_install.begin(), to_install.end() )
+        for_( it, steps.begin(), steps.end() )
         {
-          if ( ! isKind<Patch>(it->resolvable()) )
-            continue;
-          if ( ! it->status().isToBeInstalled() )
+         if ( ! it->satSolvable().isKind<Patch>() )
+           continue;
+
+         PoolItem pi( *it );
+          if ( ! pi.status().isToBeInstalled() )
             continue;
 
-          Patch::constPtr patch( asKind<Patch>(it->resolvable()) );
-          if ( ! patch->message().empty() )
-          {
-            MIL << "Show message for " << patch << endl;
-            callback::SendReport<target::PatchMessageReport> report;
-            if ( ! report->show( patch ) )
-            {
-              WAR << "commit aborted by the user" << endl;
-              ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
-            }
+          Patch::constPtr patch( asKind<Patch>(pi.resolvable()) );
+         if ( ! patch ||patch->message().empty()  )
+           continue;
+
+         MIL << "Show message for " << patch << endl;
+         callback::SendReport<target::PatchMessageReport> report;
+         if ( ! report->show( patch ) )
+         {
+           WAR << "commit aborted by the user" << endl;
+           ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
           }
         }
       }
@@ -1095,24 +1069,14 @@ namespace zypp
       ///////////////////////////////////////////////////////////////////
       // Remove/install packages.
       ///////////////////////////////////////////////////////////////////
-
       DBG << "commit log file is set to: " << HistoryLog::fname() << endl;
       if ( ! policy_r.dryRun() || policy_r.downloadMode() == DownloadOnly )
       {
-        // somewhat uggly constraint: The iterator passed to the CommitPackageCache
-        // must match begin and end of the install PoolItemList passed to commit.
-        // For the download policies it's the easiest, if we have just a single
-        // toInstall list. So we unify to_install and to_srcinstall. In case
-        // of errors we have to split it up again. This will be cleaned up when
-        // we introduce the new install order.
-        TargetImpl::PoolItemList items( to_install );
-        items.insert( items.end(), to_srcinstall.begin(), to_srcinstall.end() );
-
-        // prepare the package cache according to the download options:
+       // Prepare the package cache. Pass all items requiring download.
         repo::RepoMediaAccess access;
         RepoProvidePackage repoProvidePackage( access, pool_r );
-        CommitPackageCache packageCache( items.begin(), items.end(),
-                                         root() / "tmp", repoProvidePackage );
+        CommitPackageCache packageCache( root() / "tmp", repoProvidePackage );
+       packageCache.setCommitList( steps.begin(), steps.end() );
 
         bool miss = false;
         if ( policy_r.downloadMode() != DownloadAsNeeded )
@@ -1120,26 +1084,28 @@ namespace zypp
           // Preload the cache. Until now this means pre-loading all packages.
           // Once DownloadInHeaps is fully implemented, this will change and
           // we may actually have more than one heap.
-          for_( it, items.begin(), items.end() )
+          for_( it, steps.begin(), steps.end() )
           {
-            if ( (*it)->isKind<Package>() || (*it)->isKind<SrcPackage>() )
+           PoolItem pi( *it );
+            if ( pi->isKind<Package>() || pi->isKind<SrcPackage>() )
             {
               ManagedFile localfile;
               try
               {
-               if ( (*it)->isKind<Package>() )
+               // TODO: unify packageCache.get for Package and SrcPackage
+               if ( pi->isKind<Package>() )
                {
-                 localfile = packageCache.get( it );
+                 localfile = packageCache.get( pi );
                }
-               else if ( (*it)->isKind<SrcPackage>() )
+               else if ( pi->isKind<SrcPackage>() )
                {
                  repo::RepoMediaAccess access;
                  repo::SrcPackageProvider prov( access );
-                 localfile = prov.provideSrcPackage( (*it)->asKind<SrcPackage>() );
+                 localfile = prov.provideSrcPackage( pi->asKind<SrcPackage>() );
                }
                else
                {
-                 INT << "Don't know howto cache: Neither Package nor SrcPackage: " << *it << endl;
+                 INT << "Don't know howto cache: Neither Package nor SrcPackage: " << pi << endl;
                  continue;
                }
                 localfile.resetDispose(); // keep the package file in the cache
@@ -1147,7 +1113,6 @@ namespace zypp
               catch ( const AbortRequestException & exp )
               {
                 miss = true;
-               result._errors.push_back( *it );
                 WAR << "commit cache preload aborted by the user" << endl;
                 ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
                 break;
@@ -1156,8 +1121,7 @@ namespace zypp
               {
                 ZYPP_CAUGHT( exp );
                 miss = true;
-               result._errors.push_back( *it );
-                WAR << "Skipping cache preload package " << (*it)->asKind<Package>() << " in commit" << endl;
+                WAR << "Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
                 continue;
               }
               catch ( const Exception & exp )
@@ -1166,8 +1130,7 @@ namespace zypp
                 // TODO see if packageCache fails to handle errors correctly.
                 ZYPP_CAUGHT( exp );
                 miss = true;
-               result._errors.push_back( *it );
-                INT << "Unexpected Error: Skipping cache preload package " << (*it)->asKind<Package>() << " in commit" << endl;
+                INT << "Unexpected Error: Skipping cache preload package " << pi->asKind<Package>() << " in commit" << endl;
                 continue;
               }
             }
@@ -1177,23 +1140,10 @@ namespace zypp
         if ( miss )
         {
           ERR << "Some packages could not be provided. Aborting commit."<< endl;
-          result._remaining.insert( result._remaining.end(), to_install.begin(), to_install.end() );
-          result._srcremaining.insert( result._srcremaining.end(), to_srcinstall.begin(), to_srcinstall.end() );
         }
         else if ( ! policy_r.dryRun() )
         {
-          commit ( to_uninstall, policy_r, result, packageCache );
-          TargetImpl::PoolItemList bad = commit( items, policy_r, result, packageCache );
-          if ( ! bad.empty() )
-          {
-            for_( it, bad.begin(), bad.end() )
-            {
-              if ( isKind<SrcPackage>(it->resolvable()) )
-                result._srcremaining.push_back( *it );
-              else
-                result._remaining.push_back( *it );
-            }
-          }
+          commit( policy_r, packageCache, result );
         }
         else
         {
@@ -1213,55 +1163,105 @@ namespace zypp
         buildCache();
       }
 
-      result._result = (to_install.size() - result._remaining.size());
+      // for DEPRECATED old ZyppCommitResult results:
+      ///////////////////////////////////////////////////////////////////
+      // build return statistics
+      ///////////////////////////////////////////////////////////////////
+      result._errors.clear();
+      result._remaining.clear();
+      result._srcremaining.clear();
+      unsigned toInstall = 0;
+      for_( step, steps.begin(), steps.end() )
+      {
+       if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
+       {
+         // For non-packages only products might have beed installed.
+         // All the rest is ignored.
+         if ( step->satSolvable().isSystem() || ! step->satSolvable().isKind<Product>() )
+           continue;
+       }
+       else if ( step->stepType() == sat::Transaction::TRANSACTION_ERASE )
+       {
+         continue;
+       }
+       // to be installed:
+       ++toInstall;
+       switch ( step->stepStage() )
+       {
+         case sat::Transaction::STEP_TODO:
+           if ( step->satSolvable().isKind<Package>() )
+             result._remaining.push_back( PoolItem( *step ) );
+           else if ( step->satSolvable().isKind<SrcPackage>() )
+             result._srcremaining.push_back( PoolItem( *step ) );
+           break;
+         case sat::Transaction::STEP_DONE:
+           // NOOP
+           break;
+         case sat::Transaction::STEP_ERROR:
+           result._errors.push_back( PoolItem( *step ) );
+           break;
+       }
+      }
+      result._result = (toInstall - result._remaining.size());
+      ///////////////////////////////////////////////////////////////////
+
       MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
       return result;
     }
 
-
     ///////////////////////////////////////////////////////////////////
     //
     // COMMIT internal
     //
     ///////////////////////////////////////////////////////////////////
-    TargetImpl::PoolItemList
-    TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
-                        const ZYppCommitPolicy & policy_r,
-                        ZYppCommitResult & result_r,
-                        CommitPackageCache & packageCache_r )
+    void TargetImpl::commit( const ZYppCommitPolicy & policy_r,
+                            CommitPackageCache & packageCache_r,
+                            ZYppCommitResult & result_r )
     {
-      MIL << "TargetImpl::commit(<list>" << policy_r << ")" << items_r.size() << endl;
+      // steps: this is our todo-list
+      ZYppCommitResult::TransactionStepList & steps( result_r.rTransactionStepList() );
+      MIL << "TargetImpl::commit(<list>" << policy_r << ")" << steps.size() << endl;
 
       bool abort = false;
       std::vector<sat::Solvable> successfullyInstalledPackages;
       TargetImpl::PoolItemList remaining;
 
-      for ( TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++ )
+      for_( step, steps.begin(), steps.end() )
       {
-        if ( (*it)->isKind<Package>() )
+       PoolItem citem( *step );
+       if ( step->stepType() == sat::Transaction::TRANSACTION_IGNORE )
+       {
+         if ( citem->isKind<Package>() )
+         {
+           // for packages this means being obsoleted (by rpm)
+           // thius no additional action is needed.
+           step->stepStage( sat::Transaction::STEP_DONE );
+           continue;
+         }
+       }
+
+        if ( citem->isKind<Package>() )
         {
-          Package::constPtr p = (*it)->asKind<Package>();
-          if (it->status().isToBeInstalled())
+          Package::constPtr p = citem->asKind<Package>();
+          if ( citem.status().isToBeInstalled() )
           {
             ManagedFile localfile;
             try
             {
-              localfile = packageCache_r.get( it );
+             localfile = packageCache_r.get( citem );
             }
             catch ( const AbortRequestException &e )
             {
               WAR << "commit aborted by the user" << endl;
               abort = true;
-             result_r._errors.push_back( *it );
-             remaining.insert( remaining.end(), it, items_r.end() );
+             step->stepStage( sat::Transaction::STEP_ERROR );
              break;
             }
             catch ( const SkipRequestException &e )
             {
               ZYPP_CAUGHT( e );
               WAR << "Skipping package " << p << " in commit" << endl;
-             result_r._errors.push_back( *it );
-             remaining.push_back( *it );
+             step->stepStage( sat::Transaction::STEP_ERROR );
               continue;
             }
             catch ( const Exception &e )
@@ -1270,14 +1270,13 @@ namespace zypp
               // TODO see if packageCache fails to handle errors correctly.
               ZYPP_CAUGHT( e );
               INT << "Unexpected Error: Skipping package " << p << " in commit" << endl;
-             result_r._errors.push_back( *it );
-             remaining.push_back( *it );
+             step->stepStage( sat::Transaction::STEP_ERROR );
               continue;
             }
 
 #warning Exception handling
             // create a installation progress report proxy
-            RpmInstallPackageReceiver progress( it->resolvable() );
+            RpmInstallPackageReceiver progress( citem.resolvable() );
             progress.connect(); // disconnected on destruction.
 
             bool success = false;
@@ -1300,21 +1299,21 @@ namespace zypp
             try
             {
               progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
-              rpm().installPackage( localfile, flags );
-              HistoryLog().install(*it);
+             rpm().installPackage( localfile, flags );
+              HistoryLog().install(citem);
 
               if ( progress.aborted() )
               {
                 WAR << "commit aborted by the user" << endl;
                 localfile.resetDispose(); // keep the package file in the cache
                 abort = true;
-               result_r._errors.push_back( *it );
-               remaining.insert( remaining.end(), it, items_r.end() );
+               step->stepStage( sat::Transaction::STEP_ERROR );
                 break;
               }
               else
               {
                 success = true;
+               step->stepStage( sat::Transaction::STEP_DONE );
               }
             }
             catch ( Exception & excpt_r )
@@ -1325,8 +1324,7 @@ namespace zypp
               if ( policy_r.dryRun() )
               {
                 WAR << "dry run failed" << endl;
-               result_r._errors.push_back( *it );
-               remaining.insert( remaining.end(), it, items_r.end() );
+               step->stepStage( sat::Transaction::STEP_ERROR );
                 break;
               }
               // else
@@ -1339,21 +1337,20 @@ namespace zypp
               {
                 WAR << "Install failed" << endl;
               }
-             result_r._errors.push_back( *it );
-             remaining.insert( remaining.end(), it, items_r.end() );
+              step->stepStage( sat::Transaction::STEP_ERROR );
               break; // stop
             }
 
             if ( success && !policy_r.dryRun() )
             {
-              it->status().resetTransact( ResStatus::USER );
-              // Remember to check this package for presence of patch scripts.
-              successfullyInstalledPackages.push_back( it->satSolvable() );
+              citem.status().resetTransact( ResStatus::USER );
+              successfullyInstalledPackages.push_back( citem.satSolvable() );
+             step->stepStage( sat::Transaction::STEP_DONE );
             }
           }
           else
           {
-            RpmRemovePackageReceiver progress( it->resolvable() );
+            RpmRemovePackageReceiver progress( citem.resolvable() );
             progress.connect(); // disconnected on destruction.
 
             bool success = false;
@@ -1362,19 +1359,20 @@ namespace zypp
             if (policy_r.dryRun()) flags |= rpm::RPMINST_TEST;
             try
             {
-              rpm().removePackage( p, flags );
-              HistoryLog().remove(*it);
+             rpm().removePackage( p, flags );
+              HistoryLog().remove(citem);
 
               if ( progress.aborted() )
               {
                 WAR << "commit aborted by the user" << endl;
                 abort = true;
-               result_r._errors.push_back( *it );
+               step->stepStage( sat::Transaction::STEP_ERROR );
                 break;
               }
               else
               {
                 success = true;
+               step->stepStage( sat::Transaction::STEP_DONE );
               }
             }
             catch (Exception & excpt_r)
@@ -1384,16 +1382,17 @@ namespace zypp
               {
                 WAR << "commit aborted by the user" << endl;
                 abort = true;
-               result_r._errors.push_back( *it );
+               step->stepStage( sat::Transaction::STEP_ERROR );
                 break;
               }
               // else
               WAR << "removal of " << p << " failed";
-             result_r._errors.push_back( *it );
+             step->stepStage( sat::Transaction::STEP_ERROR );
             }
             if ( success && !policy_r.dryRun() )
             {
-              it->status().resetTransact( ResStatus::USER );
+              citem.status().resetTransact( ResStatus::USER );
+             step->stepStage( sat::Transaction::STEP_DONE );
             }
           }
         }
@@ -1401,14 +1400,14 @@ namespace zypp
         {
           // Status is changed as the buddy package buddy
           // gets installed/deleted. Handle non-buddies only.
-          if ( ! it->buddy() )
+          if ( ! citem.buddy() )
           {
-            if ( (*it)->isKind<Product>() )
+            if ( citem->isKind<Product>() )
             {
-              Product::constPtr p = (*it)->asKind<Product>();
-              if ( it->status().isToBeInstalled() )
+              Product::constPtr p = citem->asKind<Product>();
+              if ( citem.status().isToBeInstalled() )
               {
-                ERR << "Can't install orphan product without release-package! " << (*it) << endl;
+                ERR << "Can't install orphan product without release-package! " << citem << endl;
               }
               else
               {
@@ -1417,7 +1416,7 @@ namespace zypp
                 std::string referenceFilename( p->referenceFilename() );
                 if ( referenceFilename.empty() )
                 {
-                  ERR << "Can't remove orphan product without 'referenceFilename'! " << (*it) << endl;
+                  ERR << "Can't remove orphan product without 'referenceFilename'! " << citem << endl;
                 }
                 else
                 {
@@ -1429,15 +1428,17 @@ namespace zypp
                 }
               }
             }
-            else if ( (*it)->isKind<SrcPackage>() && it->status().isToBeInstalled() )
+            else if ( citem->isKind<SrcPackage>() && citem.status().isToBeInstalled() )
             {
               // SrcPackage is install-only
-              SrcPackage::constPtr p = (*it)->asKind<SrcPackage>();
+              SrcPackage::constPtr p = citem->asKind<SrcPackage>();
               installSrcPackage( p );
             }
 
-            it->status().resetTransact( ResStatus::USER );
+            citem.status().resetTransact( ResStatus::USER );
+           step->stepStage( sat::Transaction::STEP_DONE );
           }
+
         }  // other resolvables
 
       } // for
@@ -1455,18 +1456,18 @@ namespace zypp
         // send messages after scripts in case some script generates output,
         // that should be kept in t %ghost message file.
         RunUpdateMessages( _root, ZConfig::instance().update_messagesPath(),
-                           successfullyInstalledPackages,
-                           result_r );
+                          successfullyInstalledPackages,
+                          result_r );
       }
 
       if ( abort )
       {
         ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
       }
-
-     return remaining;
     }
 
+    ///////////////////////////////////////////////////////////////////
+
     rpm::RpmDb & TargetImpl::rpm()
     {
       return _rpm;
index 3de2af9..189b9fc 100644 (file)
@@ -13,7 +13,6 @@
 #define ZYPP_TARGET_TARGETIMPL_H
 
 #include <iosfwd>
-#include <list>
 #include <set>
 
 #include "zypp/base/ReferenceCounted.h"
@@ -184,10 +183,9 @@ namespace zypp
 
     private:
       /** Commit ordered changes (internal helper) */
-      PoolItemList commit( const PoolItemList & items_r,
-                           const ZYppCommitPolicy & policy_r,
-                           ZYppCommitResult & result_r,
-                           CommitPackageCache & packageCache_r );
+      void commit( const ZYppCommitPolicy & policy_r,
+                  CommitPackageCache & packageCache_r,
+                  ZYppCommitResult & result_r );
 
     protected:
       /** Path to the target */