libzypp
10.5.0
|
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 , _retry(false) 00078 , _deltas(deltas) 00079 , _access(access) 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 if ( cachechecksum == loc.checksum() ) 00106 { 00107 ManagedFile ret( cachepath.path() ); 00108 if ( ! info.keepPackages() ) 00109 { 00110 ret.setDispose( filesystem::unlink ); 00111 } 00112 MIL << "provided Package from cache " << _package << " at " << ret << endl; 00113 return ret; // <-- cache hit 00114 } 00115 } 00116 } 00117 00118 // HERE: cache misss, do download: 00119 MIL << "provide Package " << _package << endl; 00120 ScopedGuard guardReport( newReport() ); 00121 ManagedFile ret; 00122 do { 00123 _retry = false; 00124 report()->start( _package, url ); 00125 try // ELIMINATE try/catch by providing a log-guard 00126 { 00127 ret = doProvidePackage(); 00128 } 00129 catch ( const UserRequestException & excpt ) 00130 { 00131 // UserRequestException e.g. from failOnChecksumError was already reported. 00132 ERR << "Failed to provide Package " << _package << endl; 00133 if ( ! _retry ) 00134 { 00135 ZYPP_RETHROW( excpt ); 00136 } 00137 } 00138 catch ( const Exception & excpt ) 00139 { 00140 ERR << "Failed to provide Package " << _package << endl; 00141 if ( ! _retry ) 00142 { 00143 // Aything else gets reported 00144 std::string package_str = _package->name() + "-" + _package->edition().asString(); 00145 00146 // TranslatorExplanation %s = name of the package being processed. 00147 std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) ); 00148 detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() ); 00149 00150 switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) ) 00151 { 00152 case repo::DownloadResolvableReport::RETRY: 00153 _retry = true; 00154 break; 00155 case repo::DownloadResolvableReport::IGNORE: 00156 ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt)); 00157 break; 00158 case repo::DownloadResolvableReport::ABORT: 00159 ZYPP_THROW(AbortRequestException("User requested to abort", excpt)); 00160 break; 00161 default: 00162 ZYPP_RETHROW( excpt ); 00163 break; 00164 } 00165 } 00166 } 00167 } while ( _retry ); 00168 00169 report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() ); 00170 MIL << "provided Package " << _package << " at " << ret << endl; 00171 return ret; 00172 } 00173 00174 ManagedFile PackageProvider::doProvidePackage() const 00175 { 00176 Url url; 00177 RepoInfo info = _package->repoInfo(); 00178 // FIXME we only support the first url for now. 00179 if ( info.baseUrlsEmpty() ) 00180 ZYPP_THROW(Exception("No url in repository.")); 00181 else 00182 url = * info.baseUrlsBegin(); 00183 00184 // check whether to process patch/delta rpms 00185 if ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) 00186 { 00187 std::list<DeltaRpm> deltaRpms; 00188 if ( ZConfig::instance().download_use_deltarpm() ) 00189 { 00190 _deltas.deltaRpms( _package ).swap( deltaRpms ); 00191 } 00192 00193 if ( ! ( deltaRpms.empty() ) 00194 && queryInstalled() ) 00195 { 00196 if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() ) 00197 { 00198 for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin(); 00199 it != deltaRpms.end(); ++it ) 00200 { 00201 DBG << "tryDelta " << *it << endl; 00202 ManagedFile ret( tryDelta( *it ) ); 00203 if ( ! ret->empty() ) 00204 return ret; 00205 } 00206 } 00207 } 00208 } 00209 00210 // no patch/delta -> provide full package 00211 ManagedFile ret; 00212 OnMediaLocation loc = _package->location(); 00213 00214 ProvideFilePolicy policy; 00215 policy.progressCB( bind( &PackageProvider::progressPackageDownload, this, _1 ) ); 00216 policy.failOnChecksumErrorCB( bind( &PackageProvider::failOnChecksumError, this ) ); 00217 return _access.provideFile( _package->repoInfo(), loc, policy ); 00218 } 00219 00220 ManagedFile PackageProvider::tryDelta( const DeltaRpm & delta_r ) const 00221 { 00222 if ( delta_r.baseversion().edition() != Edition::noedition 00223 && ! queryInstalled( delta_r.baseversion().edition() ) ) 00224 return ManagedFile(); 00225 00226 if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) ) 00227 return ManagedFile(); 00228 00229 report()->startDeltaDownload( delta_r.location().filename(), 00230 delta_r.location().downloadSize() ); 00231 ManagedFile delta; 00232 try 00233 { 00234 ProvideFilePolicy policy; 00235 policy.progressCB( bind( &PackageProvider::progressDeltaDownload, this, _1 ) ); 00236 delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy ); 00237 } 00238 catch ( const Exception & excpt ) 00239 { 00240 report()->problemDeltaDownload( excpt.asUserHistory() ); 00241 return ManagedFile(); 00242 } 00243 report()->finishDeltaDownload(); 00244 00245 report()->startDeltaApply( delta ); 00246 if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) ) 00247 { 00248 report()->problemDeltaApply( _("applydeltarpm check failed.") ); 00249 return ManagedFile(); 00250 } 00251 00252 // build the package and put it into the cache 00253 Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() ); 00254 00255 if ( ! applydeltarpm::provide( delta, destination, 00256 bind( &PackageProvider::progressDeltaApply, this, _1 ) ) ) 00257 { 00258 report()->problemDeltaApply( _("applydeltarpm failed.") ); 00259 return ManagedFile(); 00260 } 00261 report()->finishDeltaApply(); 00262 00263 return ManagedFile( destination, filesystem::unlink ); 00264 } 00265 00266 PackageProvider::ScopedGuard PackageProvider::newReport() const 00267 { 00268 _report.reset( new Report ); 00269 return shared_ptr<void>( static_cast<void*>(0), 00270 // custom deleter calling _report.reset() 00271 // (cast required as reset is overloaded) 00272 bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ), 00273 ref(_report) ) ); 00274 } 00275 00276 PackageProvider::Report & PackageProvider::report() const 00277 { return *_report; } 00278 00279 bool PackageProvider::progressDeltaDownload( int value ) const 00280 { return report()->progressDeltaDownload( value ); } 00281 00282 void PackageProvider::progressDeltaApply( int value ) const 00283 { return report()->progressDeltaApply( value ); } 00284 00285 bool PackageProvider::progressPackageDownload( int value ) const 00286 { return report()->progress( value, _package ); } 00287 00288 bool PackageProvider::failOnChecksumError() const 00289 { 00290 std::string package_str = _package->name() + "-" + _package->edition().asString(); 00291 00292 // TranslatorExplanation %s = package being checked for integrity 00293 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() ) ) ) 00294 { 00295 case repo::DownloadResolvableReport::RETRY: 00296 _retry = true; 00297 break; 00298 case repo::DownloadResolvableReport::IGNORE: 00299 ZYPP_THROW(SkipRequestException("User requested skip of corrupted file")); 00300 break; 00301 case repo::DownloadResolvableReport::ABORT: 00302 ZYPP_THROW(AbortRequestException("User requested to abort")); 00303 break; 00304 default: 00305 break; 00306 } 00307 return true; // anyway a failure 00308 } 00309 00310 bool PackageProvider::queryInstalled( const Edition & ed_r ) const 00311 { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); } 00312 00313 00315 } // namespace repo 00318 } // namespace zypp