libzypp  17.38.7
RepoProvideFile.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16 #include <set>
17 
18 #include <zypp-core/base/Gettext.h>
19 #include <zypp-core/base/Logger.h>
20 #include <zypp-core/base/String.h>
21 #include <utility>
22 #include <zypp-core/base/UserRequestException>
24 #include <zypp/ZYppCallbacks.h>
25 #include <zypp/MediaSetAccess.h>
26 #include <zypp/ZConfig.h>
27 #include <zypp/ZYppFactory.h>
30 
33 #include <zypp/FileChecker.h>
34 #include <zypp/Fetcher.h>
35 
36 using std::endl;
37 using std::set;
38 
40 namespace zypp
41 {
42  namespace repo
44  {
45 
47  //
48  // provideFile
49  //
51 
53  namespace
54  {
55 
61  struct DownloadFileReportHack : public callback::ReceiveReport<media::DownloadProgressReport>
62  {
63  using BaseType = callback::ReceiveReport<ReportType>;
64  using RedirectType = function<bool (int)>;
65 
66  DownloadFileReportHack(RedirectType &&redirect_r)
67  : _oldRec(Distributor::instance().getReceiver()),
68  _redirect(std::move(redirect_r)) {
69  connect();
70  }
71 
72  DownloadFileReportHack(const DownloadFileReportHack &) = delete;
73  DownloadFileReportHack(DownloadFileReportHack &&) = delete;
74  DownloadFileReportHack &operator=(const DownloadFileReportHack &) = delete;
75  DownloadFileReportHack &operator=(DownloadFileReportHack &&) = delete;
76 
77  ~DownloadFileReportHack() override
78  { if ( _oldRec ) Distributor::instance().setReceiver( *_oldRec ); else Distributor::instance().noReceiver(); }
79 
80  void start( const Url & file, Pathname localfile ) override
81  {
82  if ( _oldRec )
83  _oldRec->start( file, localfile );
84  else
85  BaseType::start( file, localfile );
86  }
87 
88  bool progress( int value, const Url & file, double dbps_avg = -1, double dbps_current = -1 ) override
89  {
90  bool ret = true;
91  if ( _oldRec )
92  ret &= _oldRec->progress( value, file, dbps_avg, dbps_current );
93  if ( _redirect )
94  ret &= _redirect( value );
95  return ret;
96  }
97 
98  Action problem( const Url & file, Error error, const std::string & description ) override
99  {
100  if ( _oldRec )
101  return _oldRec->problem( file, error, description );
102  return BaseType::problem( file, error, description );
103  }
104  void finish( const Url & file, Error error, const std::string & reason ) override
105  {
106  if ( _oldRec )
107  _oldRec->finish( file, error, reason );
108  else
109  BaseType::finish( file, error, reason );
110  }
111 
112  private:
113  Receiver * _oldRec;
114  RedirectType _redirect;
115  };
116 
118  } // namespace
120 
122  const OnMediaLocation & loc_r,
123  const ProvideFilePolicy & policy_r )
124  {
125  RepoMediaAccess access;
126  return access.provideFile(std::move(repo_r), loc_r, policy_r );
127  }
128 
129  std::vector<Pathname> repositoryCachePaths( RepoInfo repo_r )
130  {
131  std::vector<Pathname> paths;
132 
133  // Add the writable location first
134  paths.push_back( repo_r.packagesPath() );
135 
136  // Add the configured path if it differs (i.e. is read-only)
137  const Pathname & cfg { repo_r.systemPackagesPath() };
138  if ( cfg != paths[0] )
139  paths.push_back( cfg );
140 
141  return paths;
142  }
143 
146  {
147  public:
148  Impl(ProvideFilePolicy &&defaultPolicy_r)
149  : _defaultPolicy(std::move(defaultPolicy_r)) {}
150 
151  Impl(const Impl &) = delete;
152  Impl(Impl &&) = delete;
153  Impl &operator=(const Impl &) = delete;
154  Impl &operator=(Impl &&) = delete;
155 
157  {
158  std::map<Url, shared_ptr<MediaSetAccess> >::iterator it;
159  for ( it = _medias.begin();
160  it != _medias.end();
161  ++it )
162  {
163  it->second->release();
164  }
165  }
166 
174  shared_ptr<MediaSetAccess> mediaAccessForUrl( const MirroredOrigin &origin, RepoInfo repo )
175  {
176  if ( !origin.isValid() )
177  return nullptr;
178 
179  std::map<Url, shared_ptr<MediaSetAccess> >::const_iterator it;
180  it = _medias.find( origin.authority().url() ); // primary Url is the key
181  shared_ptr<MediaSetAccess> media;
182  if ( it != _medias.end() )
183  {
184  media = it->second;
185  }
186  else
187  {
188  media.reset( new MediaSetAccess( origin ) );
189  _medias[origin.authority().url()] = media;
190  }
191  setVerifierForRepo( repo, media );
192  return media;
193  }
194 
195  private:
196  void setVerifierForRepo( const RepoInfo& repo, const shared_ptr<MediaSetAccess>& media )
197  {
198  // Always set the MediaSetAccess label.
199  media->setLabel( repo.name() );
200 
201  // set a verifier if the repository has it
202 
203  Pathname mediafile = repo.metadataPath() + "/media.1/media";
204  if ( ! repo.metadataPath().empty() )
205  {
206  if ( PathInfo(mediafile).isExist() )
207  {
208  std::map<shared_ptr<MediaSetAccess>, RepoInfo>::const_iterator it;
209  it = _verifier.find(media);
210  if ( it != _verifier.end() )
211  {
212  if ( it->second.alias() == repo.alias() )
213  {
214  // this media is already using this repo verifier
215  return;
216  }
217  }
218 
219  SUSEMediaVerifier lverifier { mediafile };
220  if ( lverifier ) {
221  DBG << "Verifier for repo '" << repo.alias() << "':" << lverifier << endl;
222  for ( media::MediaNr i = 1; i <= lverifier.totalMedia(); ++i ) {
224  media->setVerifier( i, verifier);
225  }
226  _verifier[media] = repo;
227  }
228  else {
229  WAR << "Invalid verifier for repo '" << repo.alias() << "' in '" << repo.metadataPath() << "': " << lverifier << endl;
230  }
231  }
232  else
233  {
234  DBG << "No media verifier for repo '" << repo.alias() << "' media.1/media does not exist in '" << repo.metadataPath() << "'" << endl;
235  }
236  }
237  else
238  {
239  WAR << "'" << repo.alias() << "' metadata path is empty. Can't set verifier. Probably this repository does not come from RepoManager." << endl;
240  }
241  }
242 
243  private:
244  std::map<shared_ptr<MediaSetAccess>, RepoInfo> _verifier;
245  std::map<Url, shared_ptr<MediaSetAccess> > _medias;
246 
247  public:
249  };
251 
252 
254  : _impl( new Impl( std::move(defaultPolicy_r) ) )
255  {}
256 
258  {}
259 
261  { _impl->_defaultPolicy = policy_r; }
262 
264  { return _impl->_defaultPolicy; }
265 
267  const OnMediaLocation & loc_rx,
268  const ProvideFilePolicy & policy_r )
269  {
270  const OnMediaLocation locWithPath( OnMediaLocation(loc_rx).prependPath( repo_r.path() ) );
271 
272  MIL << locWithPath << endl;
273  // Arrange DownloadFileReportHack to receive the source::DownloadFileReport
274  // and redirect download progress triggers to call the ProvideFilePolicy
275  // callback.
276  DownloadFileReportHack dumb( std::bind( std::mem_fn(&ProvideFilePolicy::progress), std::ref(policy_r), _1 ) );
277 
278  RepoException repo_excpt(repo_r,
279  str::form(_("Can't provide file '%s' from repository '%s'"),
280  locWithPath.filename().c_str(),
281  repo_r.alias().c_str() ) );
282 
283  const auto &repoOrigins = repo_r.repoOrigins();
284 
285  if ( repoOrigins.empty() ) {
286  repo_excpt.remember(RepoException(_("No url in repository.")));
287  ZYPP_THROW(repo_excpt);
288  }
289 
290  Fetcher fetcher;
291 
292  bool first = true;
293  for ( const auto& path : repositoryCachePaths(repo_r) ) {
294  // The first element will be the writeable cache.
295  // Add it to the cache.
296  fetcher.addCachePath( path );
297  MIL << "Added cache path " << path << endl;
298  if (first) {
299  // Add the preloaded version of the previous cache and mark it as "clean it later".
300  Pathname preloadPath = path / ".preload";
301  fetcher.addCachePath( preloadPath, Fetcher::CleanFiles );
302  MIL << "Added cache path " << preloadPath << endl;
303 
304  first = false;
305  }
306  }
307 
308  // Test whether download destination is writable, if not
309  // switch into the tmpspace (e.g. bnc#755239, download and
310  // install srpms as user).
311  Pathname destinationDir( repo_r.packagesPath() );
312 
313  PathInfo pi( destinationDir );
314  if ( ! pi.isExist() )
315  {
316  // try to create it...
317  assert_dir( destinationDir );
318  pi();
319  }
320 
321  // Suppress (interactive) media::MediaChangeReport if we have fallback URLs
322  media::ScopedDisableMediaChangeReport guard( repoOrigins.hasFallbackUrls() );
323  for ( const auto &origin : repoOrigins )
324  {
325 
326  if ( !origin.isValid() ) {
327  MIL << "Skipping empty Url group" << std::endl;
328  continue;
329  }
330 
331  try
332  {
333  MIL << "Providing file of repo '" << repo_r.alias() << "' from: ";
334  std::for_each( origin.begin (), origin.end(), [&]( const OriginEndpoint &u ){
335  MIL << u << ", ";
336  });
337  MIL << std::endl;
338 
339  shared_ptr<MediaSetAccess> access = _impl->mediaAccessForUrl( origin, repo_r );
340  if ( !access )
341  continue;
342 
343  fetcher.enqueue( locWithPath, policy_r.fileChecker() );
344  fetcher.start( destinationDir, *access );
345 
346  // reached if no exception has been thrown, so this is the correct file
347  // LEGACY NOTE:
348  // DeltaRpms e.g are in fact optional resources (tagged in OnMediaLocation).
349  // They should actually return a ManagedFile(). But I don't know if there is
350  // already code which requests optional files but relies on provideFile returning
351  // a ManagedFile holding the path even if it does not exist. So I keep it this way.
352 
353  ManagedFile ret { destinationDir / Fetcher::mapToCachePath( locWithPath ) };
354  if ( !repo_r.keepPackages() )
355  {
356  ret.setDispose( filesystem::unlink );
357  }
358 
359  MIL << "provideFile at " << ret << endl;
360  return ret;
361  }
362  catch ( const UserRequestException & excpt )
363  {
364  ZYPP_RETHROW( excpt );
365  }
366  catch ( const FileCheckException & excpt )
367  {
368  ZYPP_RETHROW( excpt );
369  }
370  catch ( const Exception &e )
371  {
372  ZYPP_CAUGHT( e );
373 
374  repo_excpt.remember(e);
375 
376  WAR << "Trying next url" << endl;
377  continue;
378  }
379  } // iteration over urls
380 
381  ZYPP_THROW(repo_excpt);
382  return ManagedFile(); // not reached
383  }
384 
385  Pathname RepoMediaAccess::mapToCachePath( const RepoInfo & repo_r, const OnMediaLocation & resource_r )
386  {
387  // While our implementation is based on the Fetcher:
388  return Fetcher::mapToCachePath( repo_r.path() / resource_r.filename() );
389  }
390 
392  } // namespace repo
395 } // namespace zypp
shared_ptr< MediaSetAccess > mediaAccessForUrl(const MirroredOrigin &origin, RepoInfo repo)
Provide a MediaSetAccess for url with label and verifier adjusted.
Pathname path() const
Repository path.
Definition: RepoInfo.cc:824
#define MIL
Definition: Logger.h:103
Implementation of the traditional SUSE media verifier.
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:338
const ProvideFilePolicy & defaultPolicy() const
Get the current default ProvideFilePolicy.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
Describes a resource file located on a medium.
bool progress(int value) const
Evaluate callback.
Pathname systemPackagesPath() const
Returns a path to the system-defined package cache.
Definition: RepoInfo.cc:782
MirroredOriginSet repoOrigins() const
The repodata origins.
Definition: RepoInfo.cc:735
RedirectType _redirect
void setVerifierForRepo(const RepoInfo &repo, const shared_ptr< MediaSetAccess > &media)
std::map< Url, shared_ptr< MediaSetAccess > > _medias
const char * c_str() const
String representation.
Definition: Pathname.h:113
Definition: ansi.h:854
What is known about a repository.
Definition: RepoInfo.h:71
const zypp::Url & url() const
void addCachePath(const Pathname &cache_dir)
adds a directory to the list of directories where to look for cached files
Definition: Fetcher.cc:958
static Pathname mapToCachePath(Pathname remotePath_r)
Map a resource filename to a local path below a destDir.
Definition: Fetcher.cc:990
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:39
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:154
Policy for provideFile and RepoMediaAccess.
void start(const Pathname &dest_dir, const ProgressData::ReceiverFnc &progress=ProgressData::ReceiverFnc())
start the transfer to a destination directory dest_dir The media has to be provides with setMediaSetA...
Definition: Fetcher.cc:978
bool empty() const
Test for an empty path.
Definition: Pathname.h:117
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:479
RepoMediaAccess(ProvideFilePolicy defaultPolicy_r=ProvideFilePolicy())
Ctor taking the default ProvideFilePolicy.
Impl(ProvideFilePolicy &&defaultPolicy_r)
bool keepPackages() const
Whether packages downloaded from this repository will be kept in local cache.
Definition: RepoInfo.cc:773
std::vector< Pathname > repositoryCachePaths(RepoInfo repo_r)
returns a set of paths.
ManagedFile provideFile(RepoInfo repo_r, const OnMediaLocation &loc_r, const ProvideFilePolicy &policy_r)
Provide a file from a Repository.
std::map< shared_ptr< MediaSetAccess >, RepoInfo > _verifier
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
std::string alias() const
unique identifier for this source.
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:286
#define WAR
Definition: Logger.h:104
ProvideFilePolicy & fileChecker(FileChecker fileChecker_r)
Add a FileCecker passed down to the Fetcher.
#define _(MSG)
Definition: Gettext.h:39
Receiver * _oldRec
Impl & operator=(const Impl &)=delete
const Pathname & filename() const
The path to the resource on the medium.
Pathname metadataPath() const
Path where this repo metadata was read from.
Definition: RepoInfo.cc:779
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:719
Provides files from different repos.
ManagedFile provideFile(const RepoInfo &repo_r, const OnMediaLocation &loc_r, const ProvideFilePolicy &policy_r)
Provide a file from a Repository.
Temporarily disable MediaChangeReport Sometimes helpful to suppress interactive messages connected to...
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:475
static Pathname mapToCachePath(const RepoInfo &repo_r, const OnMediaLocation &resource_r)
Map a resource filename to a local path below a repositories cache.
Base class for Exception.
Definition: Exception.h:152
Exception for repository handling.
Definition: RepoException.h:37
std::string name() const
Repository name.
MediaVerifierRef verifier
unsigned int MediaNr
Definition: MediaManager.h:32
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:292
Pathname packagesPath() const
packagesPath Checks if the effective user is allowed to write into the system package cache...
Definition: RepoInfo.cc:785
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
Base for exceptions caused by explicit user request.
void enqueue(const OnMediaLocation &resource, const FileChecker &checker=FileChecker())
Enqueue a object for transferal, they will not be transferred until start() is called.
Definition: Fetcher.cc:952
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
const OriginEndpoint & authority() const
Represents a single, configurable network endpoint, combining a URL with specific access settings...
void setDefaultPolicy(const ProvideFilePolicy &policy_r)
Set a new default ProvideFilePolicy.
This class allows to retrieve a group of files in a confortable way, providing some smartness that do...
Definition: Fetcher.h:113
#define DBG
Definition: Logger.h:102