libzypp  12.16.5
PackageProvider.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <sstream>
14 #include "zypp/repo/PackageDelta.h"
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/Gettext.h"
18 #include "zypp/base/NonCopyable.h"
21 #include "zypp/repo/PackageDelta.h"
22 
23 #include "zypp/TmpPath.h"
24 #include "zypp/ZConfig.h"
25 #include "zypp/RepoInfo.h"
26 
27 using std::endl;
28 
30 namespace zypp
31 {
33  namespace repo
34  {
36  // class PackageProviderPolicy
38 
39  bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
40  const Edition & ed_r,
41  const Arch & arch_r ) const
42  {
43  if ( _queryInstalledCB )
44  return _queryInstalledCB( name_r, ed_r, arch_r );
45  return false;
46  }
47 
48 
54  {
55  public:
57  Impl( RepoMediaAccess & access_r,
58  const Package::constPtr & package_r,
59  const DeltaCandidates & deltas_r,
60  const PackageProviderPolicy & policy_r )
61  : _policy( policy_r )
62  , _package( package_r )
63  , _deltas( deltas_r )
64  , _access( access_r )
65  , _retry(false)
66  {}
67 
68  virtual ~Impl() {}
69 
74  static Impl * factoryMake( RepoMediaAccess & access_r,
75  const Package::constPtr & package_r,
76  const DeltaCandidates & deltas_r,
77  const PackageProviderPolicy & policy_r );
78 
79  public:
85 
86  protected:
89 
98  virtual ManagedFile providePackageFromCache() const = 0;
99 
117  virtual ManagedFile doProvidePackage() const = 0;
118 
119  protected:
121  Report & report() const
122  { return *_report; }
123 
125  bool progressPackageDownload( int value ) const
126  { return report()->progress( value, _package ); }
127 
129  bool failOnChecksumError() const
130  {
131  std::string package_str = _package->name() + "-" + _package->edition().asString();
132 
133  // TranslatorExplanation %s = package being checked for integrity
134  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() ) ) )
135  {
137  _retry = true;
138  break;
140  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
141  break;
143  ZYPP_THROW(AbortRequestException("User requested to abort"));
144  break;
145  default:
146  break;
147  }
148  return true; // anyway a failure
149  }
150 
151  protected:
156 
157  private:
158  typedef shared_ptr<void> ScopedGuard;
159 
161  {
162  _report.reset( new Report );
163  // Use a custom deleter calling _report.reset() when guard goes out of
164  // scope (cast required as reset is overloaded). We want report to end
165  // when leaving providePackage and not wait for *this going out of scope.
166  return shared_ptr<void>( static_cast<void*>(0),
167  bind( mem_fun_ref( static_cast<void (shared_ptr<Report>::*)()>(&shared_ptr<Report>::reset) ),
168  ref(_report) ) );
169  }
170 
171  mutable bool _retry;
172  mutable shared_ptr<Report> _report;
173  };
175 
178  { return ManagedFile(); }
179 
182  {
183  ManagedFile ret;
184  OnMediaLocation loc = _package->location();
185 
186  ProvideFilePolicy policy;
187  policy.progressCB( bind( &Base::progressPackageDownload, this, _1 ) );
188  policy.failOnChecksumErrorCB( bind( &Base::failOnChecksumError, this ) );
189  return _access.provideFile( _package->repoInfo(), loc, policy );
190  }
191 
193 
195  {
196  Url url;
197  RepoInfo info = _package->repoInfo();
198  // FIXME we only support the first url for now.
199  if ( info.baseUrlsEmpty() )
200  ZYPP_THROW(Exception("No url in repository."));
201  else
202  url = * info.baseUrlsBegin();
203 
204  // check for cache hit:
205  ManagedFile ret( providePackageFromCache() );
206  if ( ! ret.value().empty() )
207  {
208  if ( ! info.keepPackages() )
209  {
211  }
212  MIL << "provided Package from cache " << _package << " at " << ret << endl;
213  return ret; // <-- cache hit
214  }
215 
216  // HERE: cache misss, do download:
217  MIL << "provide Package " << _package << endl;
218  ScopedGuard guardReport( newReport() );
219  do {
220  _retry = false;
221  report()->start( _package, url );
222  try // ELIMINATE try/catch by providing a log-guard
223  {
224  ret = doProvidePackage();
225  }
226  catch ( const UserRequestException & excpt )
227  {
228  // UserRequestException e.g. from failOnChecksumError was already reported.
229  ERR << "Failed to provide Package " << _package << endl;
230  if ( ! _retry )
231  {
232  ZYPP_RETHROW( excpt );
233  }
234  }
235  catch ( const Exception & excpt )
236  {
237  ERR << "Failed to provide Package " << _package << endl;
238  if ( ! _retry )
239  {
240  // Aything else gets reported
241  std::string package_str = _package->name() + "-" + _package->edition().asString();
242 
243  // TranslatorExplanation %s = name of the package being processed.
244  std::string detail_str( str::form(_("Failed to provide Package %s. Do you want to retry retrieval?"), package_str.c_str() ) );
245  detail_str += str::form( "\n\n%s", excpt.asUserHistory().c_str() );
246 
247  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
248  {
250  _retry = true;
251  break;
253  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
254  break;
256  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
257  break;
258  default:
259  ZYPP_RETHROW( excpt );
260  break;
261  }
262  }
263  }
264  } while ( _retry );
265 
266  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
267  MIL << "provided Package " << _package << " at " << ret << endl;
268  return ret;
269  }
270 
271 
277  {
278  public:
280  const Package::constPtr & package_r,
281  const DeltaCandidates & deltas_r,
282  const PackageProviderPolicy & policy_r )
283  : PackageProvider::Impl( access_r, package_r, deltas_r, policy_r )
284  {}
285 
286  protected:
287  virtual ManagedFile providePackageFromCache() const;
288 
289  virtual ManagedFile doProvidePackage() const;
290 
291  private:
293 
294  ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
295 
296  bool progressDeltaDownload( int value ) const
297  { return report()->progressDeltaDownload( value ); }
298 
299  void progressDeltaApply( int value ) const
300  { return report()->progressDeltaApply( value ); }
301 
302  bool queryInstalled( const Edition & ed_r = Edition() ) const
303  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
304  };
306 
308  {
309  RepoInfo info = _package->repoInfo();
310  OnMediaLocation loc( _package->location() );
311  PathInfo cachepath( info.packagesPath() / loc.filename() );
312 
313  if ( cachepath.isFile() && ! loc.checksum().empty() ) // accept cache hit with matching checksum only!
314  // Tempting to do a quick check for matching .rpm-filesize before computing checksum,
315  // but real life shows that loc.downloadSize() and the .rpm-filesize frequently do not
316  // match, even if loc.checksum() and the .rpm-files checksum do. Blame the metadata generator(s).
317  {
318  CheckSum cachechecksum( loc.checksum().type(), filesystem::checksum( cachepath.path(), loc.checksum().type() ) );
319  if ( cachechecksum == loc.checksum() )
320  {
321  return ManagedFile( cachepath.path() ); // <-- cache hit
322  }
323  }
324  return ManagedFile(); // <-- cache miss
325  }
326 
328  {
329  Url url;
330  RepoInfo info = _package->repoInfo();
331  // FIXME we only support the first url for now.
332  if ( info.baseUrlsEmpty() )
333  ZYPP_THROW(Exception("No url in repository."));
334  else
335  url = * info.baseUrlsBegin();
336 
337  // check whether to process patch/delta rpms
338  if ( ZConfig::instance().download_use_deltarpm()
340  {
341  std::list<DeltaRpm> deltaRpms;
342  _deltas.deltaRpms( _package ).swap( deltaRpms );
343 
344  if ( ! deltaRpms.empty() && queryInstalled() && applydeltarpm::haveApplydeltarpm() )
345  {
346  for_( it, deltaRpms.begin(), deltaRpms.end())
347  {
348  DBG << "tryDelta " << *it << endl;
349  ManagedFile ret( tryDelta( *it ) );
350  if ( ! ret->empty() )
351  return ret;
352  }
353  }
354  }
355 
356  // no patch/delta -> provide full package
357  return Base::doProvidePackage();
358  }
359 
361  {
362  if ( delta_r.baseversion().edition() != Edition::noedition
363  && ! queryInstalled( delta_r.baseversion().edition() ) )
364  return ManagedFile();
365 
366  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
367  return ManagedFile();
368 
369  report()->startDeltaDownload( delta_r.location().filename(),
370  delta_r.location().downloadSize() );
371  ManagedFile delta;
372  try
373  {
374  ProvideFilePolicy policy;
375  policy.progressCB( bind( &RpmPackageProvider::progressDeltaDownload, this, _1 ) );
376  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
377  }
378  catch ( const Exception & excpt )
379  {
380  report()->problemDeltaDownload( excpt.asUserHistory() );
381  return ManagedFile();
382  }
383  report()->finishDeltaDownload();
384 
385  report()->startDeltaApply( delta );
386  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
387  {
388  report()->problemDeltaApply( _("applydeltarpm check failed.") );
389  return ManagedFile();
390  }
391 
392  // build the package and put it into the cache
393  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
394 
395  if ( ! applydeltarpm::provide( delta, destination,
396  bind( &RpmPackageProvider::progressDeltaApply, this, _1 ) ) )
397  {
398  report()->problemDeltaApply( _("applydeltarpm failed.") );
399  return ManagedFile();
400  }
401  report()->finishDeltaApply();
402 
403  return ManagedFile( destination, filesystem::unlink );
404  }
405 
406 
415  {
416  public:
417  PluginPackageProvider( const std::string & stem_r,
418  RepoMediaAccess & access_r,
419  const Package::constPtr & package_r,
420  const DeltaCandidates & deltas_r,
421  const PackageProviderPolicy & policy_r )
422  : Base( access_r, package_r, deltas_r, policy_r )
423  {}
424 
425  protected:
426  virtual ManagedFile providePackageFromCache() const
427  {
428  return Base::providePackageFromCache();
429  }
430 
431  virtual ManagedFile doProvidePackage() const
432  {
433  return Base::doProvidePackage();
434  }
435  };
437 
438 
440  // class PackageProvider
442 
444  const Package::constPtr & package_r,
445  const DeltaCandidates & deltas_r,
446  const PackageProviderPolicy & policy_r )
447  {
448  return new RpmPackageProvider( access_r, package_r, deltas_r, policy_r );
449  }
450 
452  const Package::constPtr & package_r,
453  const DeltaCandidates & deltas_r,
454  const PackageProviderPolicy & policy_r )
455  : _pimpl( Impl::factoryMake( access_r, package_r, deltas_r, policy_r ) )
456  {}
457 
459  {}
460 
462  { return _pimpl->providePackage(); }
463 
464 
465  } // namespace repo
467 } // namespace zypp