PackageProvider.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/base/Gettext.h"
00016 #include "zypp/base/UserRequestException.h"
00017 
00018 #include "zypp/Repository.h"
00019 #include "zypp/repo/PackageProvider.h"
00020 #include "zypp/repo/RepoProvideFile.h"
00021 #include "zypp/repo/Applydeltarpm.h"
00022 #include "zypp/repo/PackageDelta.h"
00023 #include "zypp/detail/ImplConnect.h"
00024 
00025 #include "zypp/ZConfig.h"
00026 #include "zypp/RepoInfo.h"
00027 #include "zypp/Repository.h"
00028 #include "zypp/media/MediaManager.h"
00029 
00030 using std::endl;
00031 using zypp::media::MediaManager;
00032 
00034 namespace zypp
00035 { 
00036 
00037   namespace repo
00038   { 
00039 
00041     //
00042     //  CLASS NAME : PackageProviderPolicy
00043     //
00045 
00046     bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
00047                                                 const Edition &     ed_r,
00048                                                 const Arch &        arch_r ) const
00049     {
00050       if ( _queryInstalledCB )
00051         return _queryInstalledCB( name_r, ed_r, arch_r );
00052       return false;
00053     }
00054 
00056     //
00057     //  CLASS NAME : PackageProvider
00058     //
00060 
00062     namespace
00063     { 
00064 
00065       inline std::string defRpmFileName( const Package::constPtr & package )
00066       {
00067         std::ostringstream ret;
00068         ret << package->name() << '-' << package->edition() << '.' << package->arch() << ".rpm";
00069         return ret.str();
00070       }
00071 
00073     } // namespace source
00075     PackageProvider::PackageProvider(  RepoMediaAccess &access,
00076                                       const Package::constPtr & package,
00077                                       const DeltaCandidates & deltas,
00078                                       const PackageProviderPolicy & policy_r )
00079     : _policy( policy_r )
00080     , _package( package )
00081     , _implPtr( detail::ImplConnect::resimpl( _package ) )
00082     , _deltas(deltas)
00083     , _access(access)
00084     {}
00085 
00086     PackageProvider::~PackageProvider()
00087     {}
00088 
00089     ManagedFile PackageProvider::providePackage() const
00090     {
00091       Url url;
00092       RepoInfo info = _package->repository().info();
00093       // FIXME we only support the first url for now.
00094       if ( info.baseUrlsEmpty() )
00095         ZYPP_THROW(Exception("No url in repository."));
00096       else
00097         url = * info.baseUrlsBegin();
00098 
00099       MIL << "provide Package " << _package << endl;
00100       ScopedGuard guardReport( newReport() );
00101       ManagedFile ret;
00102       do {
00103         _retry = false;
00104         report()->start( _package, url );
00105         try  // ELIMINATE try/catch by providing a log-guard
00106           {
00107             ret = doProvidePackage();
00108           }
00109         catch ( const Exception & excpt )
00110           {
00111             ERR << "Failed to provide Package " << _package << endl;
00112             if ( ! _retry )
00113               {
00114                 ZYPP_RETHROW( excpt );
00115               }
00116           }
00117       } while ( _retry );
00118 
00119       report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
00120       MIL << "provided Package " << _package << " at " << ret << endl;
00121       return ret;
00122     }
00123 
00124     ManagedFile PackageProvider::doProvidePackage() const
00125     {
00126       Url url;
00127       RepoInfo info = _package->repository().info();
00128       // FIXME we only support the first url for now.
00129       if ( info.baseUrlsEmpty() )
00130         ZYPP_THROW(Exception("No url in repository."));
00131       else
00132         url = * info.baseUrlsBegin();
00133 
00134       // check whether to process patch/delta rpms
00135       if ( MediaManager::downloads(url) )
00136         {
00137           std::list<DeltaRpm> deltaRpms;
00138           if ( ZConfig::instance().download_use_deltarpm() )
00139           {
00140             _deltas.deltaRpms( _package ).swap( deltaRpms );
00141           }
00142 
00143           std::list<PatchRpm> patchRpms;
00144           if ( ZConfig::instance().download_use_patchrpm() )
00145           {
00146             _deltas.patchRpms( _package ).swap( patchRpms );
00147           }
00148 
00149           if ( ! ( deltaRpms.empty() && patchRpms.empty() )
00150                && queryInstalled() )
00151             {
00152               if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() )
00153                 {
00154                   for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
00155                        it != deltaRpms.end(); ++it )
00156                     {
00157                       DBG << "tryDelta " << *it << endl;
00158                       ManagedFile ret( tryDelta( *it ) );
00159                       if ( ! ret->empty() )
00160                         return ret;
00161                     }
00162                 }
00163 
00164               if ( ! patchRpms.empty() )
00165                 {
00166                   for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
00167                        it != patchRpms.end(); ++it )
00168                     {
00169                       DBG << "tryPatch " << *it << endl;
00170                       ManagedFile ret( tryPatch( *it ) );
00171                       if ( ! ret->empty() )
00172                         return ret;
00173                     }
00174                 }
00175             }
00176         }
00177       else
00178         {
00179           // allow patch rpm from local source
00180           std::list<PatchRpm> patchRpms;
00181           if ( ZConfig::instance().download_use_patchrpm() )
00182           {
00183             _deltas.patchRpms( _package ).swap( patchRpms );
00184           }
00185 
00186           if ( ! patchRpms.empty() && queryInstalled() )
00187             {
00188               for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
00189                    it != patchRpms.end(); ++it )
00190                 {
00191                   DBG << "tryPatch " << *it << endl;
00192                   ManagedFile ret( tryPatch( *it ) );
00193                   if ( ! ret->empty() )
00194                     return ret;
00195                 }
00196             }
00197         }
00198 
00199       // no patch/delta -> provide full package
00200       ManagedFile ret;
00201       OnMediaLocation loc = _package->location();
00202 
00203       ProvideFilePolicy policy;
00204       policy.progressCB( bind( &PackageProvider::progressPackageDownload, this, _1 ) );
00205       policy.failOnChecksumErrorCB( bind( &PackageProvider::failOnChecksumError, this ) );
00206       return _access.provideFile( _package->repository(), loc, policy );
00207     }
00208 
00209     ManagedFile PackageProvider::tryDelta( const DeltaRpm & delta_r ) const
00210     {
00211       if ( delta_r.baseversion().edition() != Edition::noedition
00212            && ! queryInstalled( delta_r.baseversion().edition() ) )
00213         return ManagedFile();
00214 
00215       if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
00216         return ManagedFile();
00217 
00218       report()->startDeltaDownload( delta_r.location().filename(),
00219                                     delta_r.location().downloadSize() );
00220       ManagedFile delta;
00221       try
00222         {
00223           ProvideFilePolicy policy;
00224           policy.progressCB( bind( &PackageProvider::progressDeltaDownload, this, _1 ) );
00225           delta = _access.provideFile( _package->repository(), delta_r.location(), policy );
00226         }
00227       catch ( const Exception & excpt )
00228         {
00229           report()->problemDeltaDownload( excpt.asUserString() );
00230           return ManagedFile();
00231         }
00232       report()->finishDeltaDownload();
00233 
00234       report()->startDeltaApply( delta );
00235       if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
00236         {
00237           report()->problemDeltaApply( _("applydeltarpm check failed.") );
00238           return ManagedFile();
00239         }
00240 
00241       Pathname destination( Pathname::dirname( delta ) / defRpmFileName( _package ) );
00242       /* just to ease testing with non remote sources */
00243       // FIXME removed API
00244       //if ( ! _package->source().remote() )
00245       //  destination = Pathname("/tmp") / defRpmFileName( _package );
00246       
00247 
00248       if ( ! applydeltarpm::provide( delta, destination,
00249                                      bind( &PackageProvider::progressDeltaApply, this, _1 ) ) )
00250         {
00251           report()->problemDeltaApply( _("applydeltarpm failed.") );
00252           return ManagedFile();
00253         }
00254       report()->finishDeltaApply();
00255 
00256       return ManagedFile( destination, filesystem::unlink );
00257     }
00258 
00259     ManagedFile PackageProvider::tryPatch( const PatchRpm & patch_r ) const
00260     {
00261       // installed edition is in baseversions?
00262       const PatchRpm::BaseVersions & baseversions( patch_r.baseversions() );
00263 
00264       if ( std::find_if( baseversions.begin(), baseversions.end(),
00265                          bind( &PackageProvider::queryInstalled, this, _1 ) )
00266            == baseversions.end() )
00267         return ManagedFile();
00268 
00269       report()->startPatchDownload( patch_r.location().filename(),
00270                                     patch_r.location().downloadSize() );
00271       ManagedFile patch;
00272       try
00273         {
00274           ProvideFilePolicy policy;
00275           policy.progressCB( bind( &PackageProvider::progressPatchDownload, this, _1 ) );
00276           patch = _access.provideFile( _package->repository(), patch_r.location(), policy );
00277         }
00278       catch ( const Exception & excpt )
00279         {
00280           report()->problemPatchDownload( excpt.asUserString() );
00281           return ManagedFile();
00282         }
00283       report()->finishPatchDownload();
00284 
00285       return patch;
00286     }
00287 
00288     PackageProvider::ScopedGuard PackageProvider::newReport() const
00289     {
00290       _report.reset( new Report );
00291       return shared_ptr<void>( static_cast<void*>(0),
00292                                // custom deleter calling _report.reset()
00293                                // (cast required as reset is overloaded)
00294                                bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
00295                                      ref(_report) ) );
00296     }
00297 
00298     PackageProvider::Report & PackageProvider::report() const
00299     { return *_report; }
00300 
00301     bool PackageProvider::progressDeltaDownload( int value ) const
00302     { return report()->progressDeltaDownload( value ); }
00303 
00304     void PackageProvider::progressDeltaApply( int value ) const
00305     { return report()->progressDeltaApply( value ); }
00306 
00307     bool PackageProvider::progressPatchDownload( int value ) const
00308     { return report()->progressPatchDownload( value ); }
00309 
00310     bool PackageProvider::progressPackageDownload( int value ) const
00311     { return report()->progress( value, _package ); }
00312 
00313     bool PackageProvider::failOnChecksumError() const
00314     {
00315       std::string package_str = _package->name() + "-" + _package->edition().asString();
00316 
00317       // TranslatorExplanation %s = package being checked for integrity
00318       switch ( report()->problem( _package, repo::DownloadResolvableReport::INVALID, str::form(_("Package %s fails integrity check. Do you want to retry?"), package_str.c_str() ) ) )
00319         {
00320         case repo::DownloadResolvableReport::RETRY:
00321           _retry = true;
00322           break;
00323           case repo::DownloadResolvableReport::IGNORE:
00324           ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
00325           break;
00326           case repo::DownloadResolvableReport::ABORT:
00327           ZYPP_THROW(AbortRequestException("User requested to abort"));
00328           break;
00329         default:
00330           break;
00331         }
00332       return true; // anyway a failure
00333     }
00334 
00335     bool PackageProvider::queryInstalled( const Edition & ed_r ) const
00336     { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
00337 
00338 
00340   } // namespace repo
00343 } // namespace zypp

Generated on Tue Sep 25 19:23:05 2007 for libzypp by  doxygen 1.5.3