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/base/NonCopyable.h"
19
#include "zypp/repo/PackageProvider.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
///////////////////////////////////////////////////////////////////
32
///////////////////////////////////////////////////////////////////
35
///////////////////////////////////////////////////////////////////
36
// class PackageProviderPolicy
37
///////////////////////////////////////////////////////////////////
39
bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
41
const Arch & arch_r ) const
43
if ( _queryInstalledCB )
44
return _queryInstalledCB( name_r, ed_r, arch_r );
49
///////////////////////////////////////////////////////////////////
50
/// \class PackageProvider::Impl
51
/// \brief PackageProvider implementation.
52
///////////////////////////////////////////////////////////////////
53
class PackageProvider::Impl : private base::NonCopyable
56
/** Ctor taking the Package to provide. */
57
Impl( RepoMediaAccess & access_r,
58
const Package::constPtr & package_r,
59
const DeltaCandidates & deltas_r,
60
const PackageProviderPolicy & policy_r )
62
, _package( package_r )
70
/** Factory method providing the appropriate implementation.
71
* Called by PackageProvider ctor. Returned pointer should be
72
* immediately wrapped into a smartpointer.
74
static Impl * factoryMake( RepoMediaAccess & access_r,
75
const Package::constPtr & package_r,
76
const DeltaCandidates & deltas_r,
77
const PackageProviderPolicy & policy_r );
80
/** Provide the package.
84
ManagedFile providePackage() const;
86
/** Provide the package if it is cached. */
87
ManagedFile providePackageFromCache() const
89
ManagedFile ret( doProvidePackageFromCache() );
90
if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) )
91
ret.setDispose( filesystem::unlink );
95
/** Whether the package is cached. */
97
{ return ! doProvidePackageFromCache()->empty(); }
100
typedef PackageProvider::Impl Base;
101
typedef callback::SendReport<repo::DownloadResolvableReport> Report;
103
/** Lookup the final rpm in cache.
105
* A non empty ManagedFile will be returned to the caller.
107
* \note File disposal depending on the repos keepPackages setting
108
* are not set here, but in \ref providePackage or \ref providePackageFromCache.
110
* \note The provoided default implementation returns an empty ManagedFile
113
virtual ManagedFile doProvidePackageFromCache() const = 0;
115
/** Actually provide the final rpm.
116
* Report start/problem/finish and retry loop are hadled by \ref providePackage.
117
* Here you trigger just progress and delta/plugin callbacks as needed.
119
* Proxy methods for progressPackageDownload and failOnChecksum are provided here.
120
* Create similar proxies for other progress callbacks in derived classes and link
121
* it to ProvideFilePolicy for download:
123
* ProvideFilePolicy policy;
124
* policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
125
* policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
126
* return _access.provideFile( _package->repoInfo(), loc, policy );
129
* \note The provoided default implementation retrieves the packages default
132
virtual ManagedFile doProvidePackage() const = 0;
135
/** Access to the DownloadResolvableReport */
136
Report & report() const
139
/** Redirect ProvideFilePolicy package download progress to this. */
140
bool progressPackageDownload( int value ) const
141
{ return report()->progress( value, _package ); }
143
/** Redirect ProvideFilePolicy failOnChecksumError to this if needed. */
144
bool failOnChecksumError() const
146
std::string package_str = _package->name() + "-" + _package->edition().asString();
148
// TranslatorExplanation %s = package being checked for integrity
149
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() ) ) )
151
case repo::DownloadResolvableReport::RETRY:
154
case repo::DownloadResolvableReport::IGNORE:
155
ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
157
case repo::DownloadResolvableReport::ABORT:
158
ZYPP_THROW(AbortRequestException("User requested to abort"));
163
return true; // anyway a failure
167
PackageProviderPolicy _policy;
168
Package::constPtr _package;
169
DeltaCandidates _deltas;
170
RepoMediaAccess & _access;
173
typedef shared_ptr<void> ScopedGuard;
175
ScopedGuard newReport() const
177
_report.reset( new Report );
178
// Use a custom deleter calling _report.reset() when guard goes out of
179
// scope (cast required as reset is overloaded). We want report to end
180
// when leaving providePackage and not wait for *this going out of scope.
181
return shared_ptr<void>( static_cast<void*>(0),
182
bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
187
mutable shared_ptr<Report> _report;
189
///////////////////////////////////////////////////////////////////
191
/** Default implementation (cache miss). */
192
ManagedFile PackageProvider::Impl::doProvidePackageFromCache() const
193
{ return ManagedFile(); }
195
/** Default implementation (provide full package) */
196
ManagedFile PackageProvider::Impl::doProvidePackage() const
199
OnMediaLocation loc = _package->location();
201
ProvideFilePolicy policy;
202
policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
203
policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
204
return _access.provideFile( _package->repoInfo(), loc, policy );
207
///////////////////////////////////////////////////////////////////
209
ManagedFile PackageProvider::Impl::providePackage() const
211
// check for cache hit:
212
ManagedFile ret( providePackageFromCache() );
213
if ( ! ret->empty() )
215
MIL << "provided Package from cache " << _package << " at " << ret << endl;
216
return ret; // <-- cache hit
219
// HERE: cache misss, do download:
221
RepoInfo info = _package->repoInfo();
222
// FIXME we only support the first url for now.
223
if ( info.baseUrlsEmpty() )
224
ZYPP_THROW(Exception("No url in repository."));
226
url = * info.baseUrlsBegin();
228
MIL << "provide Package " << _package << endl;
229
ScopedGuard guardReport( newReport() );
232
report()->start( _package, url );
233
try // ELIMINATE try/catch by providing a log-guard
235
ret = doProvidePackage();
237
catch ( const UserRequestException & excpt )
239
// UserRequestException e.g. from failOnChecksumError was already reported.
240
ERR << "Failed to provide Package " << _package << endl;
243
ZYPP_RETHROW( excpt );
246
catch ( const Exception & excpt )
248
ERR << "Failed to provide Package " << _package << endl;
251
// Aything else gets reported
252
std::string package_str = _package->name() + "-" + _package->edition().asString();
254
// TranslatorExplanation %s = name of the package being processed.
255
std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
256
detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
258
switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
260
case repo::DownloadResolvableReport::RETRY:
263
case repo::DownloadResolvableReport::IGNORE:
264
ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
266
case repo::DownloadResolvableReport::ABORT:
267
ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
270
ZYPP_RETHROW( excpt );
277
report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
278
MIL << "provided Package " << _package << " at " << ret << endl;
283
///////////////////////////////////////////////////////////////////
284
/// \class RpmPackageProvider
285
/// \brief RPM PackageProvider implementation.
286
///////////////////////////////////////////////////////////////////
287
class RpmPackageProvider : public PackageProvider::Impl
290
RpmPackageProvider( RepoMediaAccess & access_r,
291
const Package::constPtr & package_r,
292
const DeltaCandidates & deltas_r,
293
const PackageProviderPolicy & policy_r )
294
: PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
298
virtual ManagedFile doProvidePackageFromCache() const;
300
virtual ManagedFile doProvidePackage() const;
303
typedef packagedelta::DeltaRpm DeltaRpm;
305
ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
307
bool progressDeltaDownload( int value ) const
308
{ return report()->progressDeltaDownload( value ); }
310
void progressDeltaApply( int value ) const
311
{ return report()->progressDeltaApply( value ); }
313
bool queryInstalled( const Edition & ed_r = Edition() ) const
314
{ return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
316
///////////////////////////////////////////////////////////////////
318
ManagedFile RpmPackageProvider::doProvidePackageFromCache() const
320
return ManagedFile( _package->cachedLocation() );
323
ManagedFile RpmPackageProvider::doProvidePackage() const
326
RepoInfo info = _package->repoInfo();
327
// FIXME we only support the first url for now.
328
if ( info.baseUrlsEmpty() )
329
ZYPP_THROW(Exception("No url in repository."));
331
url = * info.baseUrlsBegin();
333
// check whether to process patch/delta rpms
334
if ( ZConfig::instance().download_use_deltarpm()
335
&& ( url.schemeIsDownloading() || ZConfig::instance().download_use_deltarpm_always() ) )
337
std::list<DeltaRpm> deltaRpms;
338
_deltas.deltaRpms( _package ).swap( deltaRpms );
340
if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
342
for_( it, deltaRpms.begin(), deltaRpms.end())
344
DBG << "tryDelta " << *it << endl;
345
ManagedFile ret( tryDelta( *it ) );
346
if ( ! ret->empty() )
352
// no patch/delta -> provide full package
353
return Base::doProvidePackage();
356
ManagedFile RpmPackageProvider::tryDelta( const DeltaRpm & delta_r ) const
358
if ( delta_r.baseversion().edition() != Edition::noedition
359
&& ! queryInstalled( delta_r.baseversion().edition() ) )
360
return ManagedFile();
362
if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
363
return ManagedFile();
365
report()->startDeltaDownload( delta_r.location().filename(),
366
delta_r.location().downloadSize() );
370
ProvideFilePolicy policy;
371
policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
372
delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
374
catch ( const Exception & excpt )
376
report()->problemDeltaDownload( excpt.asUserHistory() );
377
return ManagedFile();
379
report()->finishDeltaDownload();
381
report()->startDeltaApply( delta );
382
if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
384
report()->problemDeltaApply( _("applydeltarpm check failed.") );
385
return ManagedFile();
388
// build the package and put it into the cache
389
Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
391
if ( ! applydeltarpm::provide( delta, destination,
392
bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
394
report()->problemDeltaApply( _("applydeltarpm failed.") );
395
return ManagedFile();
397
report()->finishDeltaApply();
399
return ManagedFile( destination, filesystem::unlink );
403
///////////////////////////////////////////////////////////////////
404
/// \class PluginPackageProvider
405
/// \brief Plugin PackageProvider implementation.
407
/// Basically downloads the default package and calls a
408
/// 'stem'2rpm plugin to cteate the final .rpm package.
409
///////////////////////////////////////////////////////////////////
410
class PluginPackageProvider : public PackageProvider::Impl
413
PluginPackageProvider( const std::string & stem_r,
414
RepoMediaAccess & access_r,
415
const Package::constPtr & package_r,
416
const DeltaCandidates & deltas_r,
417
const PackageProviderPolicy & policy_r )
418
: Base( access_r, package_r, deltas_r, policy_r )
422
virtual ManagedFile doProvidePackageFromCache() const
424
return Base::doProvidePackageFromCache();
427
virtual ManagedFile doProvidePackage() const
429
return Base::doProvidePackage();
432
///////////////////////////////////////////////////////////////////
435
///////////////////////////////////////////////////////////////////
436
// class PackageProvider
437
///////////////////////////////////////////////////////////////////
439
PackageProvider::Impl * PackageProvider::Impl::factoryMake( RepoMediaAccess & access_r,
440
const Package::constPtr & package_r,
441
const DeltaCandidates & deltas_r,
442
const PackageProviderPolicy & policy_r )
444
return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
447
PackageProvider::PackageProvider( RepoMediaAccess & access_r,
448
const Package::constPtr & package_r,
449
const DeltaCandidates & deltas_r,
450
const PackageProviderPolicy & policy_r )
451
: _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
454
PackageProvider::~PackageProvider()
457
ManagedFile PackageProvider::providePackage() const
458
{ return _pimpl->providePackage(); }
460
ManagedFile PackageProvider::providePackageFromCache() const
461
{ return _pimpl->providePackageFromCache(); }
463
bool PackageProvider::isCached() const
464
{ return _pimpl->isCached(); }
467
///////////////////////////////////////////////////////////////////
469
///////////////////////////////////////////////////////////////////