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