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 
00017 #include "zypp/Source.h"
00018 #include "zypp/source/PackageProvider.h"
00019 #include "zypp/source/SourceProvideFile.h"
00020 #include "zypp/source/Applydeltarpm.h"
00021 #include "zypp/source/PackageDelta.h"
00022 #include "zypp/detail/ImplConnect.h"
00023 
00024 using std::endl;
00025 
00027 namespace zypp
00028 { 
00029 
00030   namespace source
00031   { 
00032 
00034     //
00035     //  CLASS NAME : PackageProviderPolicy
00036     //
00038 
00039     bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
00040                                                 const Edition &     ed_r,
00041                                                 const Arch &        arch_r ) const
00042     {
00043       if ( _queryInstalledCB )
00044         return _queryInstalledCB( name_r, ed_r, arch_r );
00045       return false;
00046     }
00047 
00049     //
00050     //  CLASS NAME : PackageProvider
00051     //
00053 
00055     namespace
00056     { 
00057 
00058       inline std::string defRpmFileName( const Package::constPtr & package )
00059       {
00060         std::ostringstream ret;
00061         ret << package->name() << '-' << package->edition() << '.' << package->arch() << ".rpm";
00062         return ret.str();
00063       }
00064 
00066     } // namespace source
00068     PackageProvider::PackageProvider( const Package::constPtr & package,
00069                                       const PackageProviderPolicy & policy_r )
00070     : _policy( policy_r )
00071     , _package( package )
00072     , _implPtr( detail::ImplConnect::resimpl( _package ) )
00073     {}
00074 
00075     PackageProvider::~PackageProvider()
00076     {}
00077 
00078     ManagedFile PackageProvider::providePackage() const
00079     {
00080       MIL << "provide Package " << _package << endl;
00081       ScopedGuard guardReport( newReport() );
00082       ManagedFile ret;
00083       do {
00084         _retry = false;
00085         report()->start( _package, _package->source().url() );
00086         try  // ELIMINATE try/catch by providing a log-guard
00087           {
00088             ret = doProvidePackage();
00089           }
00090         catch ( const Exception & excpt )
00091           {
00092             ERR << "Failed to provide Package " << _package << endl;
00093             if ( ! _retry )
00094               {
00095                 ZYPP_RETHROW( excpt );
00096               }
00097           }
00098       } while ( _retry );
00099 
00100       report()->finish( _package, source::DownloadResolvableReport::NO_ERROR, std::string() );
00101       MIL << "provided Package " << _package << " at " << ret << endl;
00102       return ret;
00103     }
00104 
00105     ManagedFile PackageProvider::doProvidePackage() const
00106     {
00107       // check whether to process patch/delta rpms
00108       if ( _package->source().remote() )
00109         {
00110           std::list<DeltaRpm> deltaRpms( _implPtr->deltaRpms() );
00111           std::list<PatchRpm> patchRpms( _implPtr->patchRpms() );
00112 
00113           if ( ! ( deltaRpms.empty() && patchRpms.empty() )
00114                && queryInstalled() )
00115             {
00116               if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() )
00117                 {
00118                   for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
00119                        it != deltaRpms.end(); ++it )
00120                     {
00121                       DBG << "tryDelta " << *it << endl;
00122                       ManagedFile ret( tryDelta( *it ) );
00123                       if ( ! ret->empty() )
00124                         return ret;
00125                     }
00126                 }
00127 
00128               if ( ! patchRpms.empty() )
00129                 {
00130                   for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
00131                        it != patchRpms.end(); ++it )
00132                     {
00133                       DBG << "tryPatch " << *it << endl;
00134                       ManagedFile ret( tryPatch( *it ) );
00135                       if ( ! ret->empty() )
00136                         return ret;
00137                     }
00138                 }
00139             }
00140         }
00141       else
00142         {
00143           // allow patch rpm from local source
00144           std::list<PatchRpm> patchRpms( _implPtr->patchRpms() );
00145           if ( ! patchRpms.empty() && queryInstalled() )
00146             {
00147               for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
00148                    it != patchRpms.end(); ++it )
00149                 {
00150                   DBG << "tryPatch " << *it << endl;
00151                   ManagedFile ret( tryPatch( *it ) );
00152                   if ( ! ret->empty() )
00153                     return ret;
00154                 }
00155             }
00156         }
00157 
00158       // no patch/delta -> provide full package
00159       ManagedFile ret;
00160       source::OnMediaLocation loc;
00161       loc.medianr( _package->sourceMediaNr() )
00162       .filename( _package->location() )
00163       .checksum( _package->checksum() )
00164       .downloadsize( _package->archivesize() );
00165 
00166       source::ProvideFilePolicy policy;
00167       policy.progressCB( bind( &PackageProvider::progressPackageDownload, this, _1 ) );
00168       policy.failOnChecksumErrorCB( bind( &PackageProvider::failOnChecksumError, this ) );
00169 
00170       return source::provideFile( _package->source(), loc, policy );
00171     }
00172 
00173     ManagedFile PackageProvider::tryDelta( const DeltaRpm & delta_r ) const
00174     {
00175       if ( delta_r.baseversion().edition() != Edition::noedition
00176            && ! queryInstalled( delta_r.baseversion().edition() ) )
00177         return ManagedFile();
00178 
00179       if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
00180         return ManagedFile();
00181 
00182       report()->startDeltaDownload( delta_r.location().filename(),
00183                                     delta_r.location().downloadsize() );
00184       ManagedFile delta;
00185       try
00186         {
00187           source::ProvideFilePolicy policy;
00188           policy.progressCB( bind( &PackageProvider::progressDeltaDownload, this, _1 ) );
00189           delta = source::provideFile( _package->source(), delta_r.location(), policy );
00190         }
00191       catch ( const Exception & excpt )
00192         {
00193           report()->problemDeltaDownload( excpt.asUserString() );
00194           return ManagedFile();
00195         }
00196       report()->finishDeltaDownload();
00197 
00198       report()->startDeltaApply( delta );
00199       if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
00200         {
00201           report()->problemDeltaApply( _("applydeltarpm check failed.") );
00202           return ManagedFile();
00203         }
00204 
00205       Pathname destination( Pathname::dirname( delta ) / defRpmFileName( _package ) );
00206       /* just to ease testing with non remote sources */
00207       if ( ! _package->source().remote() )
00208         destination = Pathname("/tmp") / defRpmFileName( _package );
00209       
00210 
00211       if ( ! applydeltarpm::provide( delta, destination,
00212                                      bind( &PackageProvider::progressDeltaApply, this, _1 ) ) )
00213         {
00214           report()->problemDeltaApply( _("applydeltarpm failed.") );
00215           return ManagedFile();
00216         }
00217       report()->finishDeltaApply();
00218 
00219       return ManagedFile( destination, filesystem::unlink );
00220     }
00221 
00222     ManagedFile PackageProvider::tryPatch( const PatchRpm & patch_r ) const
00223     {
00224       // installed edition is in baseversions?
00225       const PatchRpm::BaseVersions & baseversions( patch_r.baseversions() );
00226 
00227       if ( std::find_if( baseversions.begin(), baseversions.end(),
00228                          bind( &PackageProvider::queryInstalled, this, _1 ) )
00229            == baseversions.end() )
00230         return ManagedFile();
00231 
00232       report()->startPatchDownload( patch_r.location().filename(),
00233                                     patch_r.location().downloadsize() );
00234       ManagedFile patch;
00235       try
00236         {
00237           source::ProvideFilePolicy policy;
00238           policy.progressCB( bind( &PackageProvider::progressPatchDownload, this, _1 ) );
00239           patch = source::provideFile( _package->source(), patch_r.location(), policy );
00240         }
00241       catch ( const Exception & excpt )
00242         {
00243           report()->problemPatchDownload( excpt.asUserString() );
00244           return ManagedFile();
00245         }
00246       report()->finishPatchDownload();
00247 
00248       return patch;
00249     }
00250 
00251     PackageProvider::ScopedGuard PackageProvider::newReport() const
00252     {
00253       _report.reset( new Report );
00254       return shared_ptr<void>( static_cast<void*>(0),
00255                                // custom deleter calling _report.reset()
00256                                // (cast required as reset is overloaded)
00257                                bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
00258                                      ref(_report) ) );
00259     }
00260 
00261     PackageProvider::Report & PackageProvider::report() const
00262     { return *_report; }
00263 
00264     bool PackageProvider::progressDeltaDownload( int value ) const
00265     { return report()->progressDeltaDownload( value ); }
00266 
00267     void PackageProvider::progressDeltaApply( int value ) const
00268     { return report()->progressDeltaApply( value ); }
00269 
00270     bool PackageProvider::progressPatchDownload( int value ) const
00271     { return report()->progressPatchDownload( value ); }
00272 
00273     bool PackageProvider::progressPackageDownload( int value ) const
00274     { return report()->progress( value, _package ); }
00275 
00276     bool PackageProvider::failOnChecksumError() const
00277     {
00278       std::string package_str = _package->name() + "-" + _package->edition().asString();
00279 
00280       // TranslatorExplanation %s = package being checked for integrity
00281       switch ( report()->problem( _package, source::DownloadResolvableReport::INVALID, str::form(_("Package %s fails integrity check. Do you want to retry downloading it?"), package_str.c_str() ) ) )
00282         {
00283         case source::DownloadResolvableReport::RETRY:
00284           _retry = true;
00285           break;
00286           case source::DownloadResolvableReport::IGNORE:
00287           ZYPP_THROW(source::SkipRequestedException("User requested skip of corrupted file"));
00288           break;
00289         default:
00290           break;
00291         }
00292       return true; // anyway a failure
00293     }
00294 
00295     bool PackageProvider::queryInstalled( const Edition & ed_r ) const
00296     { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
00297 
00298 
00300   } // namespace source
00303 } // namespace zypp

Generated on Fri Jul 4 16:57:59 2008 for zypp by  doxygen 1.5.0