00001
00002
00003
00004
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
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
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 }
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
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
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
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
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
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
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
00256
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
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;
00293 }
00294
00295 bool PackageProvider::queryInstalled( const Edition & ed_r ) const
00296 { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
00297
00298
00300 }
00303 }