TargetImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 
00015 #include <iostream>
00016 #include <string>
00017 #include <list>
00018 #include <set>
00019 
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Exception.h"
00022 #include "zypp/base/Gettext.h"
00023 #include "zypp/PoolItem.h"
00024 #include "zypp/Resolvable.h"
00025 #include "zypp/ResObject.h"
00026 #include "zypp/Package.h"
00027 #include "zypp/Script.h"
00028 #include "zypp/Message.h"
00029 #include "zypp/Source.h"
00030 #include "zypp/Url.h"
00031 
00032 #include "zypp/target/TargetImpl.h"
00033 #include "zypp/target/TargetCallbackReceiver.h"
00034 
00035 #include "zypp/pool/GetResolvablesToInsDel.h"
00036 #include "zypp/solver/detail/Helper.h"
00037 #include "zypp/source/PackageProvider.h"
00038 
00039 using namespace std;
00040 using zypp::solver::detail::Helper;
00041 //using zypp::solver::detail::InstallOrder;
00042 
00044 namespace zypp
00045 { 
00046 
00047   namespace target
00048   { 
00049 
00051     struct QueryInstalledEditionHelper
00052     {
00053       QueryInstalledEditionHelper( rpm::RpmDb & rpmdb_r )
00054       : _rpmdb( rpmdb_r )
00055       {}
00056 
00057       bool operator()( const std::string & name_r, const Edition & ed_r ) const
00058       {
00059         if ( ed_r == Edition::noedition )
00060           return _rpmdb.hasPackage( name_r );
00061         return _rpmdb.hasPackage( name_r, ed_r );
00062       }
00063     private:
00064       rpm::RpmDb & _rpmdb;
00065     };
00066 
00067 
00068     IMPL_PTR_TYPE(TargetImpl);
00069 
00070     TargetImpl_Ptr TargetImpl::_nullimpl;
00071 
00073     TargetImpl_Ptr TargetImpl::nullimpl()
00074     {
00075       if (_nullimpl == 0)
00076         _nullimpl = new TargetImpl;
00077       return _nullimpl;
00078     }
00079 
00080 
00082     //
00083     //  METHOD NAME : TargetImpl::TargetImpl
00084     //  METHOD TYPE : Ctor
00085     //
00086     TargetImpl::TargetImpl(const Pathname & root_r)
00087     : _root(root_r)
00088     {
00089       _rpm.initDatabase(root_r);
00090       _storage_enabled = false;
00091       MIL << "Initialized target on " << _root << endl;
00092     }
00093 
00095     //
00096     //  METHOD NAME : TargetImpl::~TargetImpl
00097     //  METHOD TYPE : Dtor
00098     //
00099     TargetImpl::~TargetImpl()
00100     {
00101       _rpm.closeDatabase();
00102       MIL << "Targets closed" << endl;
00103     }
00104 
00105     bool TargetImpl::isStorageEnabled() const
00106     {
00107       return _storage_enabled;
00108     }
00109 
00110 
00111     void TargetImpl::enableStorage(const Pathname &root_r)
00112     {
00113       _storage.init(root_r);
00114       _storage_enabled = true;
00115     }
00116 
00117     Pathname TargetImpl::root() const
00118     {
00119       return _root;
00120     }
00121 
00122     const ResStore & TargetImpl::resolvables()
00123     {
00124       _store.clear();
00125       // RPM objects
00126       std::list<Package::Ptr> packages = _rpm.getPackages();
00127       for (std::list<Package::Ptr>::const_iterator it = packages.begin();
00128            it != packages.end();
00129            it++)
00130       {
00131         _store.insert(*it);
00132       }
00133 
00134       if ( isStorageEnabled() )
00135       {
00136         // resolvables stored in the zypp storage database
00137         std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
00138         for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
00139             it != resolvables.end();
00140             it++)
00141         {
00142           _store.insert(*it);
00143         }
00144       }
00145       else
00146       {
00147         WAR << "storage target not enabled" << std::endl;
00148       }
00149 
00150       return _store;
00151     }
00152 
00153 
00154 
00155     ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
00156     {
00157       // ----------------------------------------------------------------- //
00158       // Fake outstanding YCP fix: Honour restriction to media 1
00159       // at installation, but install all remaining packages if post-boot.
00160       ZYppCommitPolicy policy_r( policy_rX );
00161       if ( policy_r.restrictToMedia() > 1 )
00162         policy_r.allMedia();
00163       // ----------------------------------------------------------------- //
00164 
00165       MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
00166       ZYppCommitResult result;
00167 #warning Commit does not provide ZYppCommitResult::_errors
00168 
00169       TargetImpl::PoolItemList to_uninstall;
00170       TargetImpl::PoolItemList to_install;
00171       TargetImpl::PoolItemList to_srcinstall;
00172       {
00173 
00174         pool::GetResolvablesToInsDel
00175           collect( pool_r, policy_r.restrictToMedia() ? pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR
00176                                                       : pool::GetResolvablesToInsDel::ORDER_BY_SOURCE );
00177         MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00178         to_uninstall.swap( collect._toDelete );
00179         to_install.swap( collect._toInstall );
00180         to_srcinstall.swap( collect._toSrcinstall );
00181       }
00182 
00183       if ( policy_r.restrictToMedia() ) {
00184         MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
00185       }
00186 
00187       commit (to_uninstall, policy_r, pool_r );
00188 
00189       if (policy_r.restrictToMedia() == 0) {                    // commit all
00190         result._remaining = commit( to_install, policy_r, pool_r );
00191         result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
00192       }
00193       else
00194       {
00195         TargetImpl::PoolItemList current_install;
00196         TargetImpl::PoolItemList current_srcinstall;
00197 
00198         // Collect until the 1st package from an unwanted media occurs.
00199         // Further collection could violate install order.
00200         bool hitUnwantedMedia = false;
00201         for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
00202         {
00203           ResObject::constPtr res( it->resolvable() );
00204 
00205           if ( hitUnwantedMedia
00206                || ( res->sourceMediaNr() && res->sourceMediaNr() != policy_r.restrictToMedia() ) )
00207             {
00208               hitUnwantedMedia = true;
00209               result._remaining.push_back( *it );
00210             }
00211           else
00212             {
00213               current_install.push_back( *it );
00214             }
00215         }
00216 
00217         TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
00218         result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
00219 
00220         for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
00221         {
00222           Resolvable::constPtr res( it->resolvable() );
00223           Package::constPtr pkg( asKind<Package>(res) );
00224           if (pkg && policy_r.restrictToMedia() != pkg->sourceMediaNr()) // check medianr for packages only
00225           {
00226             XXX << "Package " << *pkg << ", wrong media " << pkg->sourceMediaNr() << endl;
00227             result._srcremaining.push_back( *it );
00228           }
00229           else {
00230             current_srcinstall.push_back( *it );
00231           }
00232         }
00233         bad = commit( current_srcinstall, policy_r, pool_r );
00234         result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
00235       }
00236 
00237 
00238       result._result = (to_install.size() - result._remaining.size());
00239       return result;
00240     }
00241 
00242 
00243     TargetImpl::PoolItemList
00244     TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
00245                         const ZYppCommitPolicy & policy_r,
00246                         const ResPool & pool_r )
00247     {
00248       TargetImpl::PoolItemList remaining;
00249 
00250       MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
00251 
00252       bool abort = false;
00253 
00254       // remember the last used source (if any)
00255       Source_Ref lastUsedSource;
00256 
00257       // Redirect PackageProvider queries for installed editions
00258       // (in case of patch/delta rpm processing) to rpmDb.
00259       source::PackageProviderPolicy packageProviderPolicy;
00260       packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper(_rpm) );
00261 
00262 
00263       for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
00264       {
00265         if (isKind<Package>(it->resolvable()))
00266         {
00267           Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
00268           if (it->status().isToBeInstalled())
00269           {
00270             source::ManagedFile localfile;
00271             try {
00272                 source::PackageProvider pkgProvider( p, packageProviderPolicy );
00273                 localfile = pkgProvider.providePackage();
00274             }
00275             catch( const source::SkipRequestedException & e )
00276             {
00277                 ZYPP_CAUGHT( e );
00278                 WAR << "Skipping package " << p << " in commit" << endl;
00279                 continue;
00280             }
00281 
00282             lastUsedSource = p->source();                       // remember the package source
00283 
00284 #warning Exception handling
00285             // create a installation progress report proxy
00286             RpmInstallPackageReceiver progress( it->resolvable() );
00287             progress.connect();
00288             bool success = true;
00289             unsigned flags = 0;
00290             if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
00291             if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00292             if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
00293 
00294             try {
00295               progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
00296               rpm().installPackage( localfile, flags );
00297 
00298               if( progress.aborted() )
00299               {
00300                 WAR << "commit aborted by the user" << endl;
00301                 progress.disconnect();
00302                 abort = true;
00303                 break;
00304               }
00305 
00306             }
00307             catch (Exception & excpt_r) {
00308               ZYPP_CAUGHT(excpt_r);
00309               WAR << "Install failed, retrying with --nodeps" << endl;
00310               if (policy_r.dryRun()) {
00311                   WAR << "dry run failed" << endl;
00312                   progress.disconnect();
00313                   break;
00314               }
00315 
00316               try {
00317                 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
00318                 flags |= rpm::RpmDb::RPMINST_NODEPS;
00319                 rpm().installPackage( localfile, flags );
00320 
00321                 if( progress.aborted() )
00322                 {
00323                   WAR << "commit aborted by the user" << endl;
00324                   abort = true;
00325                   progress.disconnect();
00326                   break;
00327                 }
00328               }
00329               catch (Exception & excpt_r)
00330               {
00331                 ZYPP_CAUGHT(excpt_r);
00332                 WAR << "Install failed again, retrying with --force --nodeps" << endl;
00333 
00334                 try {
00335                   progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
00336                   flags |= rpm::RpmDb::RPMINST_FORCE;
00337                   rpm().installPackage( localfile, flags );
00338                 }
00339                 catch (Exception & excpt_r) {
00340                   remaining.push_back( *it );
00341                   success = false;
00342                   ZYPP_CAUGHT(excpt_r);
00343                 }
00344 
00345                 if( progress.aborted() )
00346                 {
00347                     WAR << "commit aborted by the user" << endl;
00348                     abort = true;
00349                     progress.disconnect();
00350                     break;
00351                 }
00352               }
00353             }
00354             if (success
00355                 && !policy_r.dryRun())
00356             {
00357               it->status().resetTransact( ResStatus::USER );
00358             }
00359             progress.disconnect();
00360             p->source().releaseFile( p->location(), p->sourceMediaNr() );
00361           }
00362           else
00363           {
00364             bool success = true;
00365 
00366             RpmRemovePackageReceiver progress( it->resolvable() );
00367             progress.connect();
00368             unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
00369             if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00370             try {
00371               rpm().removePackage( p, flags );
00372             }
00373             catch (Exception & excpt_r) {
00374               WAR << "removal of " << p << " failed";
00375               success = false;
00376               ZYPP_CAUGHT( excpt_r );
00377             }
00378             if (success
00379                 && !policy_r.dryRun())
00380             {
00381               it->status().resetTransact( ResStatus::USER );
00382             }
00383             progress.disconnect();
00384           }
00385         }
00386         else if (!policy_r.dryRun()) // other resolvables (non-Package)
00387         {
00388           if ( isStorageEnabled() )
00389           {
00390             if (it->status().isToBeInstalled())
00391             {
00392               bool success = false;
00393               try
00394               {
00395                 if (isKind<Message>(it->resolvable()))
00396                 {
00397                   Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
00398                   std::string text = m->text().asString();
00399 
00400                   callback::SendReport<target::MessageResolvableReport> report;
00401 
00402                   report->show( m );
00403 
00404                   MIL << "Displaying the text '" << text << "'" << endl;
00405                 }
00406                 else if (isKind<Script>(it->resolvable()))
00407                 {
00408                   Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00409                   Pathname p = s->do_script();
00410                   if (p != "" && p != "/")
00411                   {
00412                     chmod( p.asString().c_str(), S_IRUSR|S_IXUSR );     // "r-x------"
00413                     ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00414                     if (! prog)
00415                       ZYPP_THROW(Exception("Cannot run the script"));
00416                     int retval = prog->close();
00417                     delete prog;
00418                     if (retval != 0)
00419                       ZYPP_THROW(Exception("Exit code of script is non-zero"));
00420                   }
00421                   else
00422                   {
00423                     ERR << "Do script not defined" << endl;
00424                   }
00425                 }
00426                 else if (!isKind<Atom>(it->resolvable()))       // atoms are re-created from the patch data, no need to save them
00427                 {
00428                   // #160792 do not just add, also remove older versions
00429                   if (true) // !installOnly - only on Package?!
00430                   {
00431                     // this would delete the same item over and over
00432                     //for (PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it); old; )
00433                     PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it);
00434                     if (old)
00435                     {
00436                       _storage.deleteObject(old.resolvable());
00437                     }
00438                   }
00439                   _storage.storeObject(it->resolvable());
00440                 }
00441                 success = true;
00442               }
00443               catch (Exception & excpt_r)
00444               {
00445                 ZYPP_CAUGHT(excpt_r);
00446                 WAR << "Install of Resolvable from storage failed" << endl;
00447               }
00448               if (success)
00449                 it->status().resetTransact( ResStatus::USER );
00450             }
00451             else
00452             {                                   // isToBeUninstalled
00453               bool success = false;
00454               try
00455               {
00456                 if (isKind<Message>(it->resolvable()))
00457                 {
00458                   DBG << "Uninstalling message - no-op" << endl;
00459                 }
00460                 else if (isKind<Script>(it->resolvable()))
00461                 {
00462                   Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00463                   Pathname p = s->undo_script();
00464                   if (! s->undo_available())
00465                   {
00466                     DBG << "Undo script not available" << endl;
00467                   }
00468                   if (p != "" && p != "/")
00469                   {
00470                     ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00471                     if (! prog)
00472                       ZYPP_THROW(Exception("Cannot run the script"));
00473                     int retval = prog->close();
00474                     delete prog;
00475                     if (retval != 0)
00476                       ZYPP_THROW(Exception("Exit code of script is non-zero"));
00477                   }
00478                   else
00479                   {
00480                     ERR << "Undo script not defined" << endl;
00481                   }
00482                 }
00483                 else
00484                 {
00485                   _storage.deleteObject(it->resolvable());
00486                 }
00487                 success = true;
00488               }
00489               catch (Exception & excpt_r)
00490               {
00491                 ZYPP_CAUGHT(excpt_r);
00492                 WAR << "Uninstall of Resolvable from storage failed" << endl;
00493               }
00494               if (success)
00495                 it->status().resetTransact( ResStatus::USER );
00496             }
00497           }
00498           else
00499           {
00500             WAR << "storage target disabled" << std::endl;
00501           }
00502 
00503         }  // other resolvables
00504 
00505       } // for
00506 
00507       // we're done with the commit, release the source media
00508       //   In the case of a single media, end of commit means we don't need _this_
00509       //   media any more.
00510       //   In the case of 'commit any media', end of commit means we're completely
00511       //   done and don't need the source's media anyways.
00512 
00513       if (lastUsedSource) {             // if a source was used
00514         lastUsedSource.release();       //  release their medias
00515       }
00516 
00517       if( abort )
00518         ZYPP_THROW( TargetAbortedException( N_("Target commit aborted by user.") ) );
00519 
00520       return remaining;
00521     }
00522 
00523     rpm::RpmDb & TargetImpl::rpm()
00524     { return _rpm; }
00525 
00526     bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
00527     { return _rpm.hasFile(path_str, name_str); }
00528 
00531     ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
00532     {
00533         string name = _rpm.whoOwnsFile (path_str);
00534         if (name.empty())
00535             return NULL;
00536 
00537         for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
00538             if ((*it)->name() == name) {
00539                 return *it;
00540             }
00541         }
00542         return NULL;
00543     }
00544 
00546     bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
00547     {
00548       return rpm::RpmDb::setInstallationLogfile(path_r);
00549     }
00550 
00551     void
00552     TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
00553                                          TargetImpl::PoolItemList & dellist_r,
00554                                          TargetImpl::PoolItemList & instlist_r,
00555                                          TargetImpl::PoolItemList & srclist_r ) const
00556     {
00557       pool::GetResolvablesToInsDel collect( pool_r );
00558       MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00559       dellist_r.swap( collect._toDelete );
00560       instlist_r.swap( collect._toInstall );
00561       srclist_r.swap( collect._toSrcinstall );
00562     }
00563 
00565   } // namespace target
00568 } // namespace zypp

Generated on Wed Sep 27 01:16:57 2006 for zypp by  doxygen 1.4.6