libzypp  14.29.1
PackageProvider.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include "zypp/repo/PackageDelta.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Gettext.h"
19 #include "zypp/base/NonCopyable.h"
22 #include "zypp/repo/PackageDelta.h"
23 
24 #include "zypp/TmpPath.h"
25 #include "zypp/ZConfig.h"
26 #include "zypp/RepoInfo.h"
27 #include "zypp/RepoManager.h"
28 
29 using std::endl;
30 
32 namespace zypp
33 {
35  namespace repo
36  {
38  // class PackageProviderPolicy
40 
41  bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
42  const Edition & ed_r,
43  const Arch & arch_r ) const
44  {
45  if ( _queryInstalledCB )
46  return _queryInstalledCB( name_r, ed_r, arch_r );
47  return false;
48  }
49 
50 
56  {
57  public:
59  Impl( RepoMediaAccess & access_r,
60  const Package::constPtr & package_r,
61  const DeltaCandidates & deltas_r,
62  const PackageProviderPolicy & policy_r )
63  : _policy( policy_r )
64  , _package( package_r )
65  , _deltas( deltas_r )
66  , _access( access_r )
67  , _retry(false)
68  {}
69 
70  virtual ~Impl() {}
71 
76  static Impl * factoryMake( RepoMediaAccess & access_r,
77  const Package::constPtr & package_r,
78  const DeltaCandidates & deltas_r,
79  const PackageProviderPolicy & policy_r );
80 
81  public:
87 
90  {
92  if ( ! ( ret->empty() || _package->repoInfo().keepPackages() ) )
94  return ret;
95  }
96 
98  bool isCached() const
99  { return ! doProvidePackageFromCache()->empty(); }
100 
101  protected:
104 
115  virtual ManagedFile doProvidePackageFromCache() const = 0;
116 
134  virtual ManagedFile doProvidePackage() const = 0;
135 
136  protected:
138  Report & report() const
139  { return *_report; }
140 
142  bool progressPackageDownload( int value ) const
143  { return report()->progress( value, _package ); }
144 
146  bool failOnChecksumError() const
147  {
148  std::string package_str = _package->name() + "-" + _package->edition().asString();
149 
150  // TranslatorExplanation %s = package being checked for integrity
151  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() ) ) )
152  {
154  _retry = true;
155  break;
157  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
158  break;
160  ZYPP_THROW(AbortRequestException("User requested to abort"));
161  break;
162  default:
163  break;
164  }
165  return true; // anyway a failure
166  }
167 
168  protected:
173 
174  private:
175  typedef shared_ptr<void> ScopedGuard;
176 
177  ScopedGuard newReport() const
178  {
179  _report.reset( new Report );
180  // Use a custom deleter calling _report.reset() when guard goes out of
181  // scope (cast required as reset is overloaded). We want report to end
182  // when leaving providePackage and not wait for *this going out of scope.
183  return shared_ptr<void>( static_cast<void*>(0),
184  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
185  ref(_report) ) );
186  }
187 
188  mutable bool _retry;
189  mutable shared_ptr<Report> _report;
190  };
192 
195  { return ManagedFile(); }
196 
199  {
200  ManagedFile ret;
201  OnMediaLocation loc = _package->location();
202 
203  ProvideFilePolicy policy;
204  policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
205  policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
206  return _access.provideFile( _package->repoInfo(), loc, policy );
207  }
208 
210 
212  {
213  ScopedGuard guardReport( newReport() );
214 
215  // check for cache hit:
217  if ( ! ret->empty() )
218  {
219  MIL << "provided Package from cache " << _package << " at " << ret << endl;
220  report()->infoInCache( _package, ret );
221  return ret; // <-- cache hit
222  }
223 
224  // HERE: cache misss, check toplevel cache or do download:
225  RepoInfo info = _package->repoInfo();
226 
227  // Check toplevel cache
228  {
229  RepoManagerOptions topCache;
230  if ( info.packagesPath().dirname() != topCache.repoPackagesCachePath ) // not using toplevel cache
231  {
232  const OnMediaLocation & loc( _package->location() );
233  if ( ! loc.checksum().empty() ) // no cache hit without checksum
234  {
235  PathInfo pi( topCache.repoPackagesCachePath / info.packagesPath().basename() / loc.filename() );
236  if ( pi.isExist() && loc.checksum() == CheckSum( loc.checksum().type(), std::ifstream( pi.c_str() ) ) )
237  {
238  report()->start( _package, pi.path().asFileUrl() );
239  const Pathname & dest( info.packagesPath() / loc.filename() );
240  if ( filesystem::assert_dir( dest.dirname() ) == 0 && filesystem::hardlinkCopy( pi.path(), dest ) == 0 )
241  {
242  ret = ManagedFile( dest );
243  if ( ! info.keepPackages() )
245 
246  MIL << "provided Package from toplevel cache " << _package << " at " << ret << endl;
247  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
248  return ret; // <-- toplevel cache hit
249  }
250  }
251  }
252  }
253  }
254 
255  // FIXME we only support the first url for now.
256  if ( info.baseUrlsEmpty() )
257  ZYPP_THROW(Exception("No url in repository."));
258 
259  MIL << "provide Package " << _package << endl;
260  Url url = * info.baseUrlsBegin();
261  do {
262  _retry = false;
263  report()->start( _package, url );
264  try // ELIMINATE try/catch by providing a log-guard
265  {
266  ret = doProvidePackage();
267  }
268  catch ( const UserRequestException & excpt )
269  {
270  // UserRequestException e.g. from failOnChecksumError was already reported.
271  ERR << "Failed to provide Package " << _package << endl;
272  if ( ! _retry )
273  {
274  ZYPP_RETHROW( excpt );
275  }
276  }
277  catch ( const Exception & excpt )
278  {
279  ERR << "Failed to provide Package " << _package << endl;
280  if ( ! _retry )
281  {
282  // Aything else gets reported
283  std::string package_str = _package->name() + "-" + _package->edition().asString();
284 
285  // TranslatorExplanation %s = name of the package being processed.
286  std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
287  detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
288 
289  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
290  {
292  _retry = true;
293  break;
295  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
296  break;
298  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
299  break;
300  default:
301  ZYPP_RETHROW( excpt );
302  break;
303  }
304  }
305  }
306  } while ( _retry );
307 
308  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
309  MIL << "provided Package " << _package << " at " << ret << endl;
310  return ret;
311  }
312 
313 
319  {
320  public:
322  const Package::constPtr & package_r,
323  const DeltaCandidates & deltas_r,
324  const PackageProviderPolicy & policy_r )
325  : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
326  {}
327 
328  protected:
329  virtual ManagedFile doProvidePackageFromCache() const;
330 
331  virtual ManagedFile doProvidePackage() const;
332 
333  private:
335 
336  ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
337 
338  bool progressDeltaDownload( int value ) const
339  { return report()->progressDeltaDownload( value ); }
340 
341  void progressDeltaApply( int value ) const
342  { return report()->progressDeltaApply( value ); }
343 
344  bool queryInstalled( const Edition & ed_r = Edition() ) const
345  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
346  };
348 
350  {
351  return ManagedFile( _package->cachedLocation() );
352  }
353 
355  {
356  Url url;
357  RepoInfo info = _package->repoInfo();
358  // FIXME we only support the first url for now.
359  if ( info.baseUrlsEmpty() )
360  ZYPP_THROW(Exception("No url in repository."));
361  else
362  url = * info.baseUrlsBegin();
363 
364  // check whether to process patch/delta rpms
365  if ( ZConfig::instance().download_use_deltarpm()
367  {
368  std::list<DeltaRpm> deltaRpms;
369  _deltas.deltaRpms( _package ).swap( deltaRpms );
370 
371  if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
372  {
373  for_( it, deltaRpms.begin(), deltaRpms.end())
374  {
375  DBG << "tryDelta " << *it << endl;
376  ManagedFile ret( tryDelta( *it ) );
377  if ( ! ret->empty() )
378  return ret;
379  }
380  }
381  }
382 
383  // no patch/delta -> provide full package
384  return Base::doProvidePackage();
385  }
386 
387  ManagedFile RpmPackageProvider::tryDelta( const DeltaRpm & delta_r ) const
388  {
389  if ( delta_r.baseversion().edition() != Edition::noedition
390  && ! queryInstalled( delta_r.baseversion().edition() ) )
391  return ManagedFile();
392 
393  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
394  return ManagedFile();
395 
396  report()->startDeltaDownload( delta_r.location().filename(),
397  delta_r.location().downloadSize() );
398  ManagedFile delta;
399  try
400  {
401  ProvideFilePolicy policy;
402  policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
403  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
404  }
405  catch ( const Exception & excpt )
406  {
407  report()->problemDeltaDownload( excpt.asUserHistory() );
408  return ManagedFile();
409  }
410  report()->finishDeltaDownload();
411 
412  report()->startDeltaApply( delta );
413  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
414  {
415  report()->problemDeltaApply( _("applydeltarpm check failed.") );
416  return ManagedFile();
417  }
418 
419  // build the package and put it into the cache
420  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
421 
422  if ( ! applydeltarpm::provide( delta, destination,
423  bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
424  {
425  report()->problemDeltaApply( _("applydeltarpm failed.") );
426  return ManagedFile();
427  }
428  report()->finishDeltaApply();
429 
430  return ManagedFile( destination, filesystem::unlink );
431  }
432 
433 #if 0
434  class PluginPackageProvider : public PackageProvider::Impl
442  {
443  public:
444  PluginPackageProvider( const std::string & stem_r,
445  RepoMediaAccess & access_r,
446  const Package::constPtr & package_r,
447  const DeltaCandidates & deltas_r,
448  const PackageProviderPolicy & policy_r )
449  : Base( access_r, package_r, deltas_r, policy_r )
450  {}
451 
452  protected:
453  virtual ManagedFile doProvidePackageFromCache() const
454  {
455  return Base::doProvidePackageFromCache();
456  }
457 
458  virtual ManagedFile doProvidePackage() const
459  {
460  return Base::doProvidePackage();
461  }
462  };
464 #endif
465 
467  // class PackageProvider
469 
471  const Package::constPtr & package_r,
472  const DeltaCandidates & deltas_r,
473  const PackageProviderPolicy & policy_r )
474  {
475  return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
476  }
477 
479  const Package::constPtr & package_r,
480  const DeltaCandidates & deltas_r,
481  const PackageProviderPolicy & policy_r )
482  : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
483  {}
484 
486  {}
487 
489  { return _pimpl->providePackage(); }
490 
492  { return _pimpl->providePackageFromCache(); }
493 
495  { return _pimpl->isCached(); }
496 
497  } // namespace repo
499 } // namespace zypp
Candidate delta and patches for a package.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:324
RepoInfo info() const
Return any associated RepoInfo.
Definition: Repository.cc:273
Interface to gettext.
#define MIL
Definition: Logger.h:47
bool failOnChecksumError() const
Redirect ProvideFilePolicy failOnChecksumError to this if needed.
virtual ManagedFile doProvidePackageFromCache() const
Lookup the final rpm in cache.
const Repository & repository() const
Definition: PackageDelta.h:70
PackageProvider implementation.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
Describes a path on a certain media amongs as the information required to download it...
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:655
const BaseVersion & baseversion() const
Definition: PackageDelta.h:69
ManagedFile providePackage() const
Provide the package.
bool isCached() const
Whether the package is cached.
Architecture.
Definition: Arch.h:36
ManagedFile tryDelta(const DeltaRpm &delta_r) const
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:307
callback::SendReport< repo::DownloadResolvableReport > Report
bool isCached() const
Whether the package is cached.
Policies and options for PackageProvider.
bool haveApplydeltarpm()
Test whether an execuatble applydeltarpm program is available.
What is known about a repository.
Definition: RepoInfo.h:66
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Edition represents [epoch:]version[-release]
Definition: Edition.h:60
void progressDeltaApply(int value) const
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:34
Report & report() const
Access to the DownloadResolvableReport.
Pathname packagesPath() const
Path where this repo packages are cached.
Definition: RepoInfo.cc:274
#define ERR
Definition: Logger.h:49
bool queryInstalled(const Edition &ed_r=Edition()) const
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
Repo manager settings.
Definition: RepoManager.h:53
Policy for provideFile.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:328
RW_pointer< Impl > _pimpl
Implementation class.
PackageProvider(RepoMediaAccess &access, const Package::constPtr &package, const DeltaCandidates &deltas, const PackageProviderPolicy &policy_r=PackageProviderPolicy())
Ctor taking the Package to provide.
packagedelta::DeltaRpm DeltaRpm
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
bool keepPackages() const
Whether packages downloaded from this repository will be kept in local cache.
Definition: RepoInfo.cc:268
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:660
ManagedFile providePackageFromCache() const
Provide the package if it is cached.
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:815
zypp::Url url
Definition: MediaCurl.cc:193
bool progressPackageDownload(int value) const
Redirect ProvideFilePolicy package download progress to this.
RpmPackageProvider(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
#define _(MSG)
Return translated text.
Definition: Gettext.h:21
const OnMediaLocation & location() const
Definition: PackageDelta.h:68
virtual ManagedFile doProvidePackage() const
Actually provide the final rpm.
Provides files from different repos.
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Definition: AutoDispose.h:158
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:324
ProvideFilePolicy & failOnChecksumErrorCB(FailOnChecksumErrorCB failOnChecksumErrorCB_r)
Set callback.
const std::string & sequenceinfo() const
Definition: PackageDelta.h:46
virtual ManagedFile doProvidePackageFromCache() const =0
Lookup the final rpm in cache.
Base class for Exception.
Definition: Exception.h:143
ProvideFilePolicy & progressCB(ProgressCB progressCB_r)
Set callback.
Provide a package from a Repo.
Impl(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Ctor taking the Package to provide.
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:178
const Pathname & filename() const
The path to the resource relatve to the url and path.
ManagedFile providePackage() const
Provide the package.
Reference counted access to a _Tp object calling a custom Dispose function when the last AutoDispose ...
Definition: AutoDispose.h:92
RPM PackageProvider implementation.
Pathname repoPackagesCachePath
Definition: RepoManager.h:82
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:75
bool quickcheck(const std::string &sequenceinfo_r)
Quick via check sequence info.
Definition: Applydeltarpm.h:48
bool check(const std::string &sequenceinfo_r, bool quick_r)
Check via sequence info.
virtual ManagedFile doProvidePackage() const =0
Actually provide the final rpm.
bool queryInstalled(const std::string &name_r, const Edition &ed_r, const Arch &arch_r) const
Evaluate callback.
bool progressDeltaDownload(int value) const
Base for exceptions caused by explicit user request.
static bool schemeIsDownloading(const std::string &scheme_r)
http https ftp sftp tftp
Definition: Url.cc:474
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
const ByteCount & downloadSize() const
The size of the resource on the server.
bool provide(const Pathname &delta_r, const Pathname &new_r, const Progress &report_r)
Apply a binary delta to on-disk data to re-create a new rpm.
Url manipulation class.
Definition: Url.h:87
TraitsType::constPtrType constPtr
Definition: Package.h:38
bool download_use_deltarpm_always() const
Whether to consider using a deltarpm even when rpm is local.
Definition: ZConfig.cc:839
#define DBG
Definition: Logger.h:46
static const Edition noedition
Value representing noedition ("") This is in fact a valid Edition.
Definition: Edition.h:73
static Impl * factoryMake(RepoMediaAccess &access_r, const Package::constPtr &package_r, const DeltaCandidates &deltas_r, const PackageProviderPolicy &policy_r)
Factory method providing the appropriate implementation.