libzypp  11.13.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"
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 {
32 
33  namespace repo
34  {
35 
37  //
38  // CLASS NAME : PackageProviderPolicy
39  //
41 
42  bool PackageProviderPolicy::queryInstalled( const std::string & name_r,
43  const Edition & ed_r,
44  const Arch & arch_r ) const
45  {
46  if ( _queryInstalledCB )
47  return _queryInstalledCB( name_r, ed_r, arch_r );
48  return false;
49  }
50 
52  //
53  // CLASS NAME : PackageProvider
54  //
56 
58  namespace
59  {
60 
61  inline std::string defRpmFileName( const Package::constPtr & package )
62  {
63  std::ostringstream ret;
64  ret << package->name() << '-' << package->edition() << '.' << package->arch() << ".rpm";
65  return ret.str();
66  }
67 
69  } // namespace source
72  const Package::constPtr & package,
73  const DeltaCandidates & deltas,
74  const PackageProviderPolicy & policy_r )
75  : _policy( policy_r )
76  , _package( package )
77  , _retry(false)
78  , _deltas(deltas)
79  , _access(access)
80  {}
81 
83  {}
84 
86  {
87  Url url;
88  RepoInfo info = _package->repoInfo();
89  // FIXME we only support the first url for now.
90  if ( info.baseUrlsEmpty() )
91  ZYPP_THROW(Exception("No url in repository."));
92  else
93  url = * info.baseUrlsBegin();
94 
95  { // check for cache hit:
96  OnMediaLocation loc( _package->location() );
97  PathInfo cachepath( info.packagesPath() / loc.filename() );
98 
99  if ( cachepath.isFile() && ! loc.checksum().empty() ) // accept cache hit with matching checksum only!
100  // Tempting to do a quick check for matching .rpm-filesize before computing checksum,
101  // but real life shows that loc.downloadSize() and the .rpm-filesize frequently do not
102  // match, even if loc.checksum() and the .rpm-files checksum do. Blame the metadata generator(s).
103  {
104  CheckSum cachechecksum( loc.checksum().type(), filesystem::checksum( cachepath.path(), loc.checksum().type() ) );
105  if ( cachechecksum == loc.checksum() )
106  {
107  ManagedFile ret( cachepath.path() );
108  if ( ! info.keepPackages() )
109  {
111  }
112  MIL << "provided Package from cache " << _package << " at " << ret << endl;
113  return ret; // <-- cache hit
114  }
115  }
116  }
117 
118  // HERE: cache misss, do download:
119  MIL << "provide Package " << _package << endl;
120  ScopedGuard guardReport( newReport() );
121  ManagedFile ret;
122  do {
123  _retry = false;
124  report()->start( _package, url );
125  try // ELIMINATE try/catch by providing a log-guard
126  {
127  ret = doProvidePackage();
128  }
129  catch ( const UserRequestException & excpt )
130  {
131  // UserRequestException e.g. from failOnChecksumError was already reported.
132  ERR << "Failed to provide Package " << _package << endl;
133  if ( ! _retry )
134  {
135  ZYPP_RETHROW( excpt );
136  }
137  }
138  catch ( const Exception & excpt )
139  {
140  ERR << "Failed to provide Package " << _package << endl;
141  if ( ! _retry )
142  {
143  // Aything else gets reported
144  std::string package_str = _package->name() + "-" + _package->edition().asString();
145 
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() );
149 
150  switch ( report()->problem( _package, repo::DownloadResolvableReport::IO, detail_str.c_str() ) )
151  {
153  _retry = true;
154  break;
156  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file", excpt));
157  break;
159  ZYPP_THROW(AbortRequestException("User requested to abort", excpt));
160  break;
161  default:
162  ZYPP_RETHROW( excpt );
163  break;
164  }
165  }
166  }
167  } while ( _retry );
168 
169  report()->finish( _package, repo::DownloadResolvableReport::NO_ERROR, std::string() );
170  MIL << "provided Package " << _package << " at " << ret << endl;
171  return ret;
172  }
173 
175  {
176  Url url;
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."));
181  else
182  url = * info.baseUrlsBegin();
183 
184  // check whether to process patch/delta rpms
186  {
187  std::list<DeltaRpm> deltaRpms;
189  {
190  _deltas.deltaRpms( _package ).swap( deltaRpms );
191  }
192 
193  if ( ! ( deltaRpms.empty() )
194  && queryInstalled() )
195  {
196  if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() )
197  {
198  for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
199  it != deltaRpms.end(); ++it )
200  {
201  DBG << "tryDelta " << *it << endl;
202  ManagedFile ret( tryDelta( *it ) );
203  if ( ! ret->empty() )
204  return ret;
205  }
206  }
207  }
208  }
209 
210  // no patch/delta -> provide full package
211  ManagedFile ret;
212  OnMediaLocation loc = _package->location();
213 
214  ProvideFilePolicy policy;
215  policy.progressCB( bind( &PackageProvider::progressPackageDownload, this, _1 ) );
217  return _access.provideFile( _package->repoInfo(), loc, policy );
218  }
219 
221  {
222  if ( delta_r.baseversion().edition() != Edition::noedition
223  && ! queryInstalled( delta_r.baseversion().edition() ) )
224  return ManagedFile();
225 
226  if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
227  return ManagedFile();
228 
229  report()->startDeltaDownload( delta_r.location().filename(),
230  delta_r.location().downloadSize() );
231  ManagedFile delta;
232  try
233  {
234  ProvideFilePolicy policy;
235  policy.progressCB( bind( &PackageProvider::progressDeltaDownload, this, _1 ) );
236  delta = _access.provideFile( delta_r.repository().info(), delta_r.location(), policy );
237  }
238  catch ( const Exception & excpt )
239  {
240  report()->problemDeltaDownload( excpt.asUserHistory() );
241  return ManagedFile();
242  }
243  report()->finishDeltaDownload();
244 
245  report()->startDeltaApply( delta );
246  if ( ! applydeltarpm::check( delta_r.baseversion().sequenceinfo() ) )
247  {
248  report()->problemDeltaApply( _("applydeltarpm check failed.") );
249  return ManagedFile();
250  }
251 
252  // build the package and put it into the cache
253  Pathname destination( _package->repoInfo().packagesPath() / _package->location().filename() );
254 
255  if ( ! applydeltarpm::provide( delta, destination,
256  bind( &PackageProvider::progressDeltaApply, this, _1 ) ) )
257  {
258  report()->problemDeltaApply( _("applydeltarpm failed.") );
259  return ManagedFile();
260  }
261  report()->finishDeltaApply();
262 
263  return ManagedFile( destination, filesystem::unlink );
264  }
265 
267  {
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) ),
273  ref(_report) ) );
274  }
275 
277  { return *_report; }
278 
280  { return report()->progressDeltaDownload( value ); }
281 
282  void PackageProvider::progressDeltaApply( int value ) const
283  { return report()->progressDeltaApply( value ); }
284 
286  { return report()->progress( value, _package ); }
287 
289  {
290  std::string package_str = _package->name() + "-" + _package->edition().asString();
291 
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() ) ) )
294  {
296  _retry = true;
297  break;
299  ZYPP_THROW(SkipRequestException("User requested skip of corrupted file"));
300  break;
302  ZYPP_THROW(AbortRequestException("User requested to abort"));
303  break;
304  default:
305  break;
306  }
307  return true; // anyway a failure
308  }
309 
310  bool PackageProvider::queryInstalled( const Edition & ed_r ) const
311  { return _policy.queryInstalled( _package->name(), ed_r, _package->arch() ); }
312 
313 
315  } // namespace repo
318 } // namespace zypp