1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/repo/PackageProvider.cc
14 #include "zypp/repo/PackageDelta.h"
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/Gettext.h"
17 #include "zypp/base/UserRequestException.h"
18 #include "zypp/repo/PackageProvider.h"
19 #include "zypp/repo/RepoProvideFile.h"
20 #include "zypp/repo/Applydeltarpm.h"
21 #include "zypp/repo/PackageDelta.h"
23 #include "zypp/TmpPath.h"
24 #include "zypp/ZConfig.h"
25 #include "zypp/RepoInfo.h"
29 ///////////////////////////////////////////////////////////////////
31 { /////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////
38 // CLASS NAME : PackageProviderPolicy
40 ///////////////////////////////////////////////////////////////////
42 bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
44 const Arch & arch_r ) const
46 if ( _queryInstalledCB )
47 return _queryInstalledCB( name_r, ed_r, arch_r );
51 ///////////////////////////////////////////////////////////////////
53 // CLASS NAME : PackageProvider
55 ///////////////////////////////////////////////////////////////////
57 ///////////////////////////////////////////////////////////////////
59 { /////////////////////////////////////////////////////////////////
61 inline std::string defRpmFileName( const Package::constPtr & package )
63 std::ostringstream ret;
64 ret << package->name() << '-' << package->edition() << '.' << package->arch() << ".rpm";
68 /////////////////////////////////////////////////////////////////
70 ///////////////////////////////////////////////////////////////////
71 PackageProvider::PackageProvider( RepoMediaAccess &access,
72 const Package::constPtr & package,
73 const DeltaCandidates & deltas,
74 const PackageProviderPolicy & policy_r )
81 PackageProvider::~PackageProvider()
84 ManagedFile PackageProvider::providePackage() const
87 RepoInfo info = _package->repoInfo();
88 // FIXME we only support the first url for now.
89 if ( info.baseUrlsEmpty() )
90 ZYPP_THROW(Exception("No url in repository."));
92 url = * info.baseUrlsBegin();
94 { // check for cache hit:
95 OnMediaLocation loc( _package->location() );
96 PathInfo cachepath( info.packagesPath() / loc.filename() );
98 if ( cachepath.isFile() && ! loc.checksum().empty() ) // accept cache hit with matching checksum only!
99 // Tempting to do a quick check for matching .rpm-filesize before computing checksum,
100 // but real life shows that loc.downloadSize() and the .rpm-filesize frequently do not
101 // match, even if loc.checksum() and the .rpm-files checksum do. Blame the metadata generator(s).
103 CheckSum cachechecksum( loc.checksum().type(), filesystem::checksum( cachepath.path(), loc.checksum().type() ) );
104 USR << cachechecksum << endl;
105 if ( cachechecksum == loc.checksum() )
107 ManagedFile ret( cachepath.path() );
108 if ( ! info.keepPackages() )
110 ret.setDispose( filesystem::unlink );
112 MIL << "provided Package from cache " << _package << " at " << ret << endl;
113 return ret; // <-- cache hit
118 // HERE: cache misss, do download:
119 MIL << "provide Package " << _package << endl;
120 ScopedGuard guardReport( newReport() );
124 report()->start( _package, url );
125 try // ELIMINATE try/catch by providing a log-guard
127 ret = doProvidePackage();
129 catch ( const UserRequestException & excpt )
131 // UserRequestException e.g. from failOnChecksumError was already reported.
132 ERR << "Failed to provide Package " << _package << endl;
135 ZYPP_RETHROW( excpt );
138 catch ( const Exception & excpt )
140 ERR << "Failed to provide Package " << _package << endl;
143 // Aything else gets reported
144 std::string package_str = _package->name() + "-" + _package->edition().asString();
146 // TranslatorExplanation %s = name of the package being processed.
147 std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
148 detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
150 switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
152 case repo::DownloadResolvableReport::RETRY:
155 case repo::DownloadResolvableReport::IGNORE:
156 ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
158 case repo::DownloadResolvableReport::ABORT:
159 ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
162 ZYPP_RETHROW( excpt );
169 report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
170 MIL << "provided Package " << _package << " at " << ret << endl;
174 ManagedFile PackageProvider::doProvidePackage() const
177 RepoInfo info = _package->repoInfo();
178 // FIXME we only support the first url for now.
179 if ( info.baseUrlsEmpty() )
180 ZYPP_THROW(Exception("No url in repository."));
182 url = * info.baseUrlsBegin();
184 // check whether to process patch/delta rpms
185 if ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() )
187 std::list<DeltaRpm> deltaRpms;
188 if ( ZConfig::instance().download_use_deltarpm() )
190 _deltas.deltaRpms( _package ).swap( deltaRpms );
193 if ( ! ( deltaRpms.empty() )
194 && queryInstalled() )
196 if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() )
198 for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
199 it != deltaRpms.end(); ++it )
201 DBG << "tryDelta " << *it << endl;
202 ManagedFile ret( tryDelta( *it ) );
203 if ( ! ret->empty() )
210 // no patch/delta -> provide full package
212 OnMediaLocation loc = _package->location();
214 ProvideFilePolicy policy;
215 policy.progressCB( bind( &PackageProvider::progressPackageDownload, this, _1 ) );
216 policy.failOnChecksumErrorCB( bind( &PackageProvider::failOnChecksumError, this ) );
217 return _access.provideFile( _package->repoInfo(), loc, policy );
220 ManagedFile PackageProvider::tryDelta( const DeltaRpm & delta_r ) const
222 if ( delta_r.baseversion().edition() != Edition::noedition
223 && ! queryInstalled( delta_r.baseversion().edition() ) )
224 return ManagedFile();
226 if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
227 return ManagedFile();
229 report()->startDeltaDownload( delta_r.location().filename(),
230 delta_r.location().downloadSize() );
234 ProvideFilePolicy policy;
235 policy.progressCB( bind( &PackageProvider::progressDeltaDownload, this, _1 ) );
236 delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
238 catch ( const Exception & excpt )
240 report()->problemDeltaDownload( excpt.asUserHistory() );
241 return ManagedFile();
243 report()->finishDeltaDownload();
245 report()->startDeltaApply( delta );
246 if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
248 report()->problemDeltaApply( _("applydeltarpm check failed.") );
249 return ManagedFile();
252 // build the package and put it into the cache
253 Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
255 if ( ! applydeltarpm::provide( delta, destination,
256 bind( &PackageProvider::progressDeltaApply, this, _1 ) ) )
258 report()->problemDeltaApply( _("applydeltarpm failed.") );
259 return ManagedFile();
261 report()->finishDeltaApply();
263 return ManagedFile( destination, filesystem::unlink );
266 PackageProvider::ScopedGuard PackageProvider::newReport() const
268 _report.reset( new Report );
269 return shared_ptr<void>( static_cast<void*>(0),
270 // custom deleter calling _report.reset()
271 // (cast required as reset is overloaded)
272 bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
276 PackageProvider::Report & PackageProvider::report() const
279 bool PackageProvider::progressDeltaDownload( int value ) const
280 { return report()->progressDeltaDownload( value ); }
282 void PackageProvider::progressDeltaApply( int value ) const
283 { return report()->progressDeltaApply( value ); }
285 bool PackageProvider::progressPackageDownload( int value ) const
286 { return report()->progress( value, _package ); }
288 bool PackageProvider::failOnChecksumError() const
290 std::string package_str = _package->name() + "-" + _package->edition().asString();
292 // TranslatorExplanation %s = package being checked for integrity
293 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() ) ) )
295 case repo::DownloadResolvableReport::RETRY:
298 case repo::DownloadResolvableReport::IGNORE:
299 ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
301 case repo::DownloadResolvableReport::ABORT:
302 ZYPP_THROW(AbortRequestException("User requested to abort"));
307 return true; // anyway a failure
310 bool PackageProvider::queryInstalled( const Edition & ed_r ) const
311 { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
314 /////////////////////////////////////////////////////////////////
316 ///////////////////////////////////////////////////////////////////
317 /////////////////////////////////////////////////////////////////
319 ///////////////////////////////////////////////////////////////////