libzypp  17.32.4
RepoManager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <cstdlib>
14 #include <iostream>
15 #include <fstream>
16 #include <list>
17 #include <map>
18 #include <algorithm>
19 #include <chrono>
20 
21 #include <zypp-core/base/InputStream>
22 #include <zypp-core/Digest.h>
23 #include <zypp/base/LogTools.h>
24 #include <zypp/base/Gettext.h>
25 #include <zypp-core/base/DefaultIntegral>
26 #include <zypp/base/Function.h>
27 #include <zypp/base/Regex.h>
28 #include <zypp/PathInfo.h>
29 #include <zypp/TmpPath.h>
30 
31 #include <zypp/ServiceInfo.h>
33 #include <zypp/RepoManager.h>
36 
38 #include <zypp-media/auth/CredentialManager>
39 #include <zypp-media/MediaException>
40 #include <zypp/MediaSetAccess.h>
41 #include <zypp/ExternalProgram.h>
42 #include <zypp/ManagedFile.h>
43 
44 #include <zypp/parser/xml/Reader.h>
45 #include <zypp/repo/ServiceRepos.h>
48 
49 #include <zypp/Target.h> // for Target::targetDistribution() for repo index services
50 #include <zypp/ZYppFactory.h> // to get the Target from ZYpp instance
51 #include <zypp/HistoryLog.h> // to write history :O)
52 
53 #include <zypp/ZYppCallbacks.h>
54 
55 #include "sat/Pool.h"
57 #include <zypp/base/Algorithm.h>
58 
59 
60 // zyppng related includes
61 #include <zypp-core/zyppng/pipelines/Lift>
63 #include <zypp/ng/repo/refresh.h>
65 
66 
67 using std::endl;
68 using std::string;
69 using namespace zypp::repo;
70 
71 #define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc()
72 
74 namespace zypp
75 {
77  namespace env
78  {
81  {
82  const char * env = getenv("ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
83  return( env && str::strToBool( env, true ) );
84  }
85  } // namespace env
87 
88  namespace
89  {
93  class MediaMounter
94  {
95  public:
97  MediaMounter( const Url & url_r )
98  {
99  media::MediaManager mediamanager;
100  _mid = mediamanager.open( url_r );
101  mediamanager.attach( _mid );
102  }
103 
104  MediaMounter(const MediaMounter &) = delete;
105  MediaMounter(MediaMounter &&) = delete;
106  MediaMounter &operator=(const MediaMounter &) = delete;
107  MediaMounter &operator=(MediaMounter &&) = delete;
108 
110  ~MediaMounter()
111  {
112  media::MediaManager mediamanager;
113  mediamanager.release( _mid );
114  mediamanager.close( _mid );
115  }
116 
121  Pathname getPathName( const Pathname & path_r = Pathname() ) const
122  {
123  media::MediaManager mediamanager;
124  return mediamanager.localPath( _mid, path_r );
125  }
126 
127  private:
129  };
131  } // namespace
133 
134  std::list<RepoInfo> readRepoFile( const Url & repo_file )
135  {
136  repo::RepoVariablesUrlReplacer replaceVars;
137  Url repoFileUrl { replaceVars(repo_file) };
138 
139  ManagedFile local = MediaSetAccess::provideFileFromUrl( repoFileUrl );
140  DBG << "reading repo file " << repoFileUrl << ", local path: " << local << endl;
141 
142  return repositories_in_file(local);
143  }
144 
151  {
152  public:
154  : RepoManagerBaseImpl(std::move(opt)),
155  _pluginRepoverification(_options.pluginsPath / "repoverification",
156  _options.rootDir) {
157  init_knownServices();
158  init_knownRepositories();
159  }
160 
161  Impl(const Impl &) = default;
162  Impl(Impl &&) = delete;
163  Impl &operator=(const Impl &) = delete;
164  Impl &operator=(Impl &&) = delete;
165 
166  ~Impl() override
167  {
168  // trigger appdata refresh if some repos change
169  if ( ( _reposDirty || env::ZYPP_PLUGIN_APPDATA_FORCE_COLLECT() )
170  && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
171  {
172  try {
173  std::list<Pathname> entries;
174  filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
175  if ( ! entries.empty() )
176  {
178  cmd.push_back( "<" ); // discard stdin
179  cmd.push_back( ">" ); // discard stdout
180  cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
181  for ( const auto & rinfo : repos() )
182  {
183  if ( ! rinfo.enabled() )
184  continue;
185  cmd.push_back( "-R" );
186  cmd.push_back( rinfo.alias() );
187  cmd.push_back( "-t" );
188  cmd.push_back( rinfo.type().asString() );
189  cmd.push_back( "-p" );
190  cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache
191  }
192 
193  for_( it, entries.begin(), entries.end() )
194  {
195  PathInfo pi( *it );
196  //DBG << "/tmp/xx ->" << pi << endl;
197  if ( pi.isFile() && pi.userMayRX() )
198  {
199  // trigger plugin
200  cmd[2] = pi.asString(); // [2] - PROGRAM
202  }
203  }
204  }
205  }
206  catch (...) {} // no throw in dtor
207  }
208  }
209 
210  public:
212 
213  void refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, OPT_PROGRESS );
214 
215  void buildCache( const RepoInfo & info, CacheBuildPolicy policy, OPT_PROGRESS );
216 
217  repo::RepoType probe( const Url & url, const Pathname & path = Pathname() ) const;
218 
219  void loadFromCache( const RepoInfo & info, OPT_PROGRESS );
220 
221  void addRepository( const RepoInfo & info, OPT_PROGRESS );
222 
223  void addRepositories( const Url & url, OPT_PROGRESS );
224 
225  void removeRepository ( const RepoInfo & info, OPT_PROGRESS ) override;
226 
227  public:
228  void refreshServices( const RefreshServiceOptions & options_r );
229 
230  void refreshService( const std::string & alias, const RefreshServiceOptions & options_r );
231  void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
232  { refreshService( service.alias(), options_r ); }
233 
234  repo::ServiceType probeService( const Url & url ) const;
235 
236  void refreshGeoIPData ( const RepoInfo::url_set &urls );
237 
238  private:
240 
241  private:
242  friend Impl * rwcowClone<Impl>( const Impl * rhs );
244  Impl * clone() const
245  { return new Impl( *this ); }
246  };
248 
250  inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj )
251  { return str << "RepoManager::Impl"; }
252 
254  {
255  using namespace zyppng::operators;
256  using zyppng::operators::operator|;
257 
258  refreshGeoIPData( { url } );
259 
260  auto ctx = zyppng::SyncContext::create();
261  auto res = zyppng::repo::SyncRefreshContext::create( ctx, info, _options )
262  | and_then( [&]( zyppng::repo::SyncRefreshContextRef &&refCtx ) {
263  refCtx->setPolicy ( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
264  return ctx->provider()->attachMedia( url, zyppng::ProvideMediaSpec() )
265  | and_then( [ r = std::move(refCtx) ]( auto &&mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), mediaHandle, nullptr ); } );
266  } );
267 
268  if ( !res ) {
269  ZYPP_RETHROW ( res.error() );
270  }
271  return static_cast<RepoManager::RefreshCheckStatus>(res.get());
272  }
273 
274 
275  void RepoManager::Impl::refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, const ProgressData::ReceiverFnc & progress )
276  {
277  using namespace zyppng;
278  using namespace zyppng::operators;
279  using zyppng::operators::operator|;
280 
281  // make sure geoIP data is up 2 date
282  refreshGeoIPData( info.baseUrls() );
283 
284  // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
285  media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 );
286 
287  // we will throw this later if no URL checks out fine
288  RepoException rexception( info, PL_("Valid metadata not found at specified URL",
289  "Valid metadata not found at specified URLs",
290  info.baseUrlsSize() ) );
291 
292 
293  auto ctx = SyncContext::create();
294 
295  // helper callback in case the repo type changes on the remote
296  const auto &updateProbedType = [&]( repo::RepoType repokind ) {
297  // update probed type only for repos in system
298  for_( it, repoBegin(), repoEnd() )
299  {
300  if ( info.alias() == (*it).alias() )
301  {
302  RepoInfo modifiedrepo = *it;
303  modifiedrepo.setType( repokind );
304  // don't modify .repo in refresh.
305  // modifyRepository( info.alias(), modifiedrepo );
306  break;
307  }
308  }
309  };
310 
311  // try urls one by one
312  for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
313  {
314  try {
315  auto res = zyppng::repo::SyncRefreshContext::create( ctx, info, _options )
316  | and_then( [&]( zyppng::repo::SyncRefreshContextRef refCtx ) {
317  refCtx->setPolicy( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
318  // in case probe detects a different repokind, update our internal repos
319  refCtx->connectFunc( &zyppng::repo::SyncRefreshContext::sigProbedTypeChanged, updateProbedType );
320  return ctx->provider()->attachMedia( *it, zyppng::ProvideMediaSpec() )
321  | and_then( [ refCtx ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), std::move(mediaHandle), nullptr); } );
322  });
323 
324  if ( !res ) {
325  ZYPP_RETHROW( res.error() );
326  }
327  if ( ! isTmpRepo( info ) )
328  reposManip(); // remember to trigger appdata refresh
329 
330  // we are done.
331  return;
332 
333  } catch ( const zypp::Exception &e ) {
334  ERR << "Trying another url..." << endl;
335 
336  // remember the exception caught for the *first URL*
337  // if all other URLs fail, the rexception will be thrown with the
338  // cause of the problem of the first URL remembered
339  if (it == info.baseUrlsBegin())
340  rexception.remember( e );
341  else
342  rexception.addHistory( e.asUserString() );
343  }
344  } // for every url
345  ERR << "No more urls..." << endl;
346  ZYPP_THROW(rexception);
347 
348  }
349 
350  void RepoManager::Impl::buildCache( const RepoInfo & info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
351  {
352  assert_alias(info);
353  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
354  Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
355 
356  if( filesystem::assert_dir(_options.repoCachePath) )
357  {
358  Exception ex(str::form( _("Can't create %s"), _options.repoCachePath.c_str()) );
359  ZYPP_THROW(ex);
360  }
361  RepoStatus raw_metadata_status = metadataStatus(info);
362  if ( raw_metadata_status.empty() )
363  {
364  /* if there is no cache at this point, we refresh the raw
365  in case this is the first time - if it's !autorefresh,
366  we may still refresh */
367  refreshMetadata(info, RefreshIfNeeded, progressrcv );
368  raw_metadata_status = metadataStatus(info);
369  }
370 
371  bool needs_cleaning = false;
372  if ( isCached( info ) )
373  {
374  MIL << info.alias() << " is already cached." << endl;
375  RepoStatus cache_status = cacheStatus(info);
376 
377  if ( cache_status == raw_metadata_status )
378  {
379  MIL << info.alias() << " cache is up to date with metadata." << endl;
380  if ( policy == BuildIfNeeded )
381  {
382  // On the fly add missing solv.idx files for bash completion.
383  const Pathname & base = solv_path_for_repoinfo( _options, info);
384  if ( ! PathInfo(base/"solv.idx").isExist() )
385  sat::updateSolvFileIndex( base/"solv" );
386 
387  return;
388  }
389  else {
390  MIL << info.alias() << " cache rebuild is forced" << endl;
391  }
392  }
393 
394  needs_cleaning = true;
395  }
396 
397  ProgressData progress(100);
398  callback::SendReport<ProgressReport> report;
399  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
400  progress.name(str::form(_("Building repository '%s' cache"), info.label().c_str()));
401  progress.toMin();
402 
403  if (needs_cleaning)
404  {
405  cleanCache(info);
406  }
407 
408  MIL << info.alias() << " building cache..." << info.type() << endl;
409 
410  Pathname base = solv_path_for_repoinfo( _options, info);
411 
412  if( filesystem::assert_dir(base) )
413  {
414  Exception ex(str::form( _("Can't create %s"), base.c_str()) );
415  ZYPP_THROW(ex);
416  }
417 
418  if( ! PathInfo(base).userMayW() )
419  {
420  Exception ex(str::form( _("Can't create cache at %s - no writing permissions."), base.c_str()) );
421  ZYPP_THROW(ex);
422  }
423  Pathname solvfile = base / "solv";
424 
425  // do we have type?
426  repo::RepoType repokind = info.type();
427 
428  // if the type is unknown, try probing.
429  switch ( repokind.toEnum() )
430  {
431  case RepoType::NONE_e:
432  // unknown, probe the local metadata
433  repokind = probeCache( productdatapath );
434  break;
435  default:
436  break;
437  }
438 
439  MIL << "repo type is " << repokind << endl;
440 
441  switch ( repokind.toEnum() )
442  {
443  case RepoType::RPMMD_e :
444  case RepoType::YAST2_e :
446  {
447  // Take care we unlink the solvfile on exception
448  ManagedFile guard( solvfile, filesystem::unlink );
449  scoped_ptr<MediaMounter> forPlainDirs;
450 
452  cmd.push_back( PathInfo( "/usr/bin/repo2solv" ).isFile() ? "repo2solv" : "repo2solv.sh" );
453  // repo2solv expects -o as 1st arg!
454  cmd.push_back( "-o" );
455  cmd.push_back( solvfile.asString() );
456  cmd.push_back( "-X" ); // autogenerate pattern from pattern-package
457  // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
458 
459  if ( repokind == RepoType::RPMPLAINDIR )
460  {
461  forPlainDirs.reset( new MediaMounter( info.url() ) );
462  // recusive for plaindir as 2nd arg!
463  cmd.push_back( "-R" );
464  // FIXME this does only work form dir: URLs
465  cmd.push_back( forPlainDirs->getPathName( info.path() ).c_str() );
466  }
467  else
468  cmd.push_back( productdatapath.asString() );
469 
470  ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
471  std::string errdetail;
472 
473  for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
474  WAR << " " << output;
475  errdetail += output;
476  }
477 
478  int ret = prog.close();
479  if ( ret != 0 )
480  {
481  RepoException ex(info, str::form( _("Failed to cache repo (%d)."), ret ));
482  ex.addHistory( str::Str() << prog.command() << endl << errdetail << prog.execError() ); // errdetail lines are NL-terminaled!
483  ZYPP_THROW(ex);
484  }
485 
486  // We keep it.
487  guard.resetDispose();
488  sat::updateSolvFileIndex( solvfile ); // content digest for zypper bash completion
489  }
490  break;
491  default:
492  ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") ));
493  break;
494  }
495  // update timestamp and checksum
496  setCacheStatus(info, raw_metadata_status);
497  MIL << "Commit cache.." << endl;
498  progress.toMax();
499  }
500 
502 
503 
510  repo::RepoType RepoManager::Impl::probe( const Url & url, const Pathname & path ) const
511  {
512  using namespace zyppng;
513  using namespace zyppng::operators;
514  using zyppng::operators::operator|;
515 
516  auto ctx = zyppng::SyncContext::create();
517  auto res = ctx->provider()->attachMedia( url, zyppng::ProvideMediaSpec() )
518  | and_then( [&]( auto mediaHandle ) {
519  return zyppng::RepoManagerWorkflow::probeRepoType( ctx, mediaHandle, path );
520  });
521 
522  if ( !res ) {
523  ZYPP_RETHROW ( res.error() );
524  }
525  return res.get();
526  }
527 
529 
530  void RepoManager::Impl::loadFromCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
531  {
532  try
533  {
534  RepoManagerBaseImpl::loadFromCache( info, progressrcv );
535  }
536  catch ( const Exception & exp )
537  {
538  ZYPP_CAUGHT( exp );
539  MIL << "Try to handle exception by rebuilding the solv-file" << endl;
540  cleanCache( info, progressrcv );
541  buildCache( info, BuildIfNeeded, progressrcv );
542 
543  sat::Pool::instance().addRepoSolv( solv_path_for_repoinfo(_options, info) / "solv", info );
544  }
545  }
546 
548 
549  void RepoManager::Impl::addRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
550  {
551  assert_alias(info);
552 
553  ProgressData progress(100);
554  callback::SendReport<ProgressReport> report;
555  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
556  progress.name(str::form(_("Adding repository '%s'"), info.label().c_str()));
557  progress.toMin();
558 
559  MIL << "Try adding repo " << info << endl;
560 
561  RepoInfo tosave = info;
562  if ( repos().find(tosave) != repos().end() )
564 
565  // check the first url for now
566  if ( _options.probe )
567  {
568  DBG << "unknown repository type, probing" << endl;
569  assert_urls(tosave);
570 
571  RepoType probedtype( probe( tosave.url(), info.path() ) );
572  if ( probedtype == RepoType::NONE )
574  else
575  tosave.setType(probedtype);
576  }
577 
578  progress.set(50);
579 
580  RepoManagerBaseImpl::addProbedRepository ( info, info.type() );
581 
582  progress.toMax();
583  MIL << "done" << endl;
584  }
585 
586 
587  void RepoManager::Impl::addRepositories( const Url & url, const ProgressData::ReceiverFnc & progressrcv )
588  {
589  std::list<RepoInfo> repos = readRepoFile(url);
590  for ( std::list<RepoInfo>::const_iterator it = repos.begin();
591  it != repos.end();
592  ++it )
593  {
594  // look if the alias is in the known repos.
595  for_ ( kit, repoBegin(), repoEnd() )
596  {
597  if ( (*it).alias() == (*kit).alias() )
598  {
599  ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << endl;
601  }
602  }
603  }
604 
605  std::string filename = Pathname(url.getPathName()).basename();
606 
607  if ( filename == Pathname() )
608  {
609  // TranslatorExplanation '%s' is an URL
610  ZYPP_THROW(RepoException(str::form( _("Invalid repo file name at '%s'"), url.asString().c_str() )));
611  }
612 
613  // assert the directory exists
614  filesystem::assert_dir(_options.knownReposPath);
615 
616  Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
617  // now we have a filename that does not exists
618  MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
619 
620  std::ofstream file(repofile.c_str());
621  if (!file)
622  {
623  // TranslatorExplanation '%s' is a filename
624  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
625  }
626 
627  for ( std::list<RepoInfo>::iterator it = repos.begin();
628  it != repos.end();
629  ++it )
630  {
631  MIL << "Saving " << (*it).alias() << endl;
632  it->dumpAsIniOn(file);
633  it->setFilepath(repofile);
634  it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
635  it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
636  reposManip().insert(*it);
637 
638  HistoryLog(_options.rootDir).addRepository(*it);
639  }
640 
641  MIL << "done" << endl;
642  }
643 
644  void RepoManager::Impl::removeRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv )
645  {
646  callback::SendReport<ProgressReport> report;
647  ProgressReportAdaptor adapt( progressrcv, report );
648  removeRepositoryImpl( info, std::ref(adapt) );
649  }
650 
652  //
653  // Services
654  //
656 
657  void RepoManager::Impl::refreshServices( const RefreshServiceOptions & options_r )
658  {
659  // copy the set of services since refreshService
660  // can eventually invalidate the iterator
661  ServiceSet services( serviceBegin(), serviceEnd() );
662  for_( it, services.begin(), services.end() )
663  {
664  if ( !it->enabled() )
665  continue;
666 
667  try {
668  refreshService(*it, options_r);
669  }
670  catch ( const repo::ServicePluginInformalException & e )
671  { ;/* ignore ServicePluginInformalException */ }
672  }
673  }
674 
675  void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
676  {
677  ServiceInfo service( getService( alias ) );
678  assert_alias( service );
679  assert_url( service );
680  MIL << "Going to refresh service '" << service.alias() << "', url: " << service.url() << ", opts: " << options_r << endl;
681 
682  if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
683  {
684  // Service defines a TTL; maybe we can re-use existing data without refresh.
685  Date lrf = service.lrf();
686  if ( lrf )
687  {
688  Date now( Date::now() );
689  if ( lrf <= now )
690  {
691  if ( (lrf+=service.ttl()) > now ) // lrf+= !
692  {
693  MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
694  return;
695  }
696  }
697  else
698  WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
699  }
700  }
701 
702  // NOTE: It might be necessary to modify and rewrite the service info.
703  // Either when probing the type, or when adjusting the repositories
704  // enable/disable state.:
705  bool serviceModified = false;
706 
708 
709  // if the type is unknown, try probing.
710  if ( service.type() == repo::ServiceType::NONE )
711  {
712  repo::ServiceType type = probeService( service.url() );
713  if ( type != ServiceType::NONE )
714  {
715  service.setProbedType( type ); // lazy init!
716  serviceModified = true;
717  }
718  }
719 
720  // get target distro identifier
721  std::string servicesTargetDistro = _options.servicesTargetDistro;
722  if ( servicesTargetDistro.empty() )
723  {
724  servicesTargetDistro = Target::targetDistribution( Pathname() );
725  }
726  DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
727 
728  // parse it
729  Date::Duration origTtl = service.ttl(); // FIXME Ugly hack: const service.ttl modified when parsing
730  RepoCollector collector(servicesTargetDistro);
731  // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
732  // which is actually a notification. Using an exception for this
733  // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
734  // and in zypper.
735  std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
736  try {
737  // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they
738  // are not aware of the RepoManagers rootDir. The service url, as created in known_services,
739  // contains the full path to the script. The script however has to be executed chrooted.
740  // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace
741  // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it
742  // to ServiceRepos.
743  ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
744  }
745  catch ( const repo::ServicePluginInformalException & e )
746  {
747  /* ignore ServicePluginInformalException and throw later */
748  uglyHack.first = true;
749  uglyHack.second = e;
750  }
751  if ( service.ttl() != origTtl ) // repoindex.xml changed ttl
752  {
753  if ( !service.ttl() )
754  service.setLrf( Date() ); // don't need lrf when zero ttl
755  serviceModified = true;
756  }
758  // On the fly remember the new repo states as defined the reopoindex.xml.
759  // Move into ServiceInfo later.
760  ServiceInfo::RepoStates newRepoStates;
761 
762  // set service alias and base url for all collected repositories
763  for_( it, collector.repos.begin(), collector.repos.end() )
764  {
765  // First of all: Prepend service alias:
766  it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
767  // set reference to the parent service
768  it->setService( service.alias() );
769 
770  // remember the new parsed repo state
771  newRepoStates[it->alias()] = *it;
772 
773  // - If the repo url was not set by the repoindex parser, set service's url.
774  // - Libzypp currently has problem with separate url + path handling so just
775  // append a path, if set, to the baseurls
776  // - Credentials in the url authority will be extracted later, either if the
777  // repository is added or if we check for changed urls.
778  Pathname path;
779  if ( !it->path().empty() )
780  {
781  if ( it->path() != "/" )
782  path = it->path();
783  it->setPath("");
784  }
785 
786  if ( it->baseUrlsEmpty() )
787  {
788  Url url( service.rawUrl() );
789  if ( !path.empty() )
790  url.setPathName( url.getPathName() / path );
791  it->setBaseUrl( std::move(url) );
792  }
793  else if ( !path.empty() )
794  {
795  RepoInfo::url_set urls( it->rawBaseUrls() );
796  for ( Url & url : urls )
797  {
798  url.setPathName( url.getPathName() / path );
799  }
800  it->setBaseUrls( std::move(urls) );
801  }
802  }
803 
805  // Now compare collected repos with the ones in the system...
806  //
807  RepoInfoList oldRepos;
808  getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
809 
811  // find old repositories to remove...
812  for_( oldRepo, oldRepos.begin(), oldRepos.end() )
813  {
814  if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
815  {
816  if ( oldRepo->enabled() )
817  {
818  // Currently enabled. If this was a user modification remember the state.
819  const auto & last = service.repoStates().find( oldRepo->alias() );
820  if ( last != service.repoStates().end() && ! last->second.enabled )
821  {
822  DBG << "Service removes user enabled repo " << oldRepo->alias() << endl;
823  service.addRepoToEnable( oldRepo->alias() );
824  serviceModified = true;
825  }
826  else
827  DBG << "Service removes enabled repo " << oldRepo->alias() << endl;
828  }
829  else
830  DBG << "Service removes disabled repo " << oldRepo->alias() << endl;
831 
832  removeRepository( *oldRepo );
833  }
834  }
835 
837  // create missing repositories and modify existing ones if needed...
838  UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
839  for_( it, collector.repos.begin(), collector.repos.end() )
840  {
841  // User explicitly requested the repo being enabled?
842  // User explicitly requested the repo being disabled?
843  // And hopefully not both ;) If so, enable wins.
844 
845  TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request
846  DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl;
847 
848  if ( options_r.testFlag( RefreshService_restoreStatus ) )
849  {
850  DBG << "Opt RefreshService_restoreStatus " << it->alias() << endl;
851  // this overrides any pending request!
852  // Remove from enable request list.
853  // NOTE: repoToDisable is handled differently.
854  // It gets cleared on each refresh.
855  service.delRepoToEnable( it->alias() );
856  // toBeEnabled stays indeterminate!
857  }
858  else
859  {
860  if ( service.repoToEnableFind( it->alias() ) )
861  {
862  DBG << "User request to enable service repo " << it->alias() << endl;
863  toBeEnabled = true;
864  // Remove from enable request list.
865  // NOTE: repoToDisable is handled differently.
866  // It gets cleared on each refresh.
867  service.delRepoToEnable( it->alias() );
868  serviceModified = true;
869  }
870  else if ( service.repoToDisableFind( it->alias() ) )
871  {
872  DBG << "User request to disable service repo " << it->alias() << endl;
873  toBeEnabled = false;
874  }
875  }
876 
877  RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
878  if ( oldRepo == oldRepos.end() )
879  {
880  // Not found in oldRepos ==> a new repo to add
881 
882  // Make sure the service repo is created with the appropriate enablement
883  if ( ! indeterminate(toBeEnabled) )
884  it->setEnabled( ( bool ) toBeEnabled );
885 
886  DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl;
887  addRepository( *it );
888  }
889  else
890  {
891  // ==> an exising repo to check
892  bool oldRepoModified = false;
893 
894  if ( indeterminate(toBeEnabled) )
895  {
896  // No user request: check for an old user modificaton otherwise follow service request.
897  // NOTE: Assert toBeEnabled is boolean afterwards!
898  if ( oldRepo->enabled() == it->enabled() )
899  toBeEnabled = it->enabled(); // service requests no change to the system
900  else if (options_r.testFlag( RefreshService_restoreStatus ) )
901  {
902  toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
903  DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl;
904  }
905  else
906  {
907  const auto & last = service.repoStates().find( oldRepo->alias() );
908  if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
909  toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
910  else
911  {
912  toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
913  DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << endl;
914  }
915  }
916  }
917 
918  // changed enable?
919  if ( toBeEnabled == oldRepo->enabled() )
920  {
921  DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl;
922  }
923  else if ( toBeEnabled )
924  {
925  DBG << "Service repo " << it->alias() << " gets enabled" << endl;
926  oldRepo->setEnabled( true );
927  oldRepoModified = true;
928  }
929  else
930  {
931  DBG << "Service repo " << it->alias() << " gets disabled" << endl;
932  oldRepo->setEnabled( false );
933  oldRepoModified = true;
934  }
935 
936  // all other attributes follow the service request:
937 
938  // changed name (raw!)
939  if ( oldRepo->rawName() != it->rawName() )
940  {
941  DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
942  oldRepo->setName( it->rawName() );
943  oldRepoModified = true;
944  }
945 
946  // changed autorefresh
947  if ( oldRepo->autorefresh() != it->autorefresh() )
948  {
949  DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl;
950  oldRepo->setAutorefresh( it->autorefresh() );
951  oldRepoModified = true;
952  }
953 
954  // changed priority?
955  if ( oldRepo->priority() != it->priority() )
956  {
957  DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl;
958  oldRepo->setPriority( it->priority() );
959  oldRepoModified = true;
960  }
961 
962  // changed url?
963  {
964  RepoInfo::url_set newUrls( it->rawBaseUrls() );
965  urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
966  if ( oldRepo->rawBaseUrls() != newUrls )
967  {
968  DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
969  oldRepo->setBaseUrls( std::move(newUrls) );
970  oldRepoModified = true;
971  }
972  }
973 
974  // changed gpg check settings?
975  // ATM only plugin services can set GPG values.
976  if ( service.type() == ServiceType::PLUGIN )
977  {
978  TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
979  TriBool ngpg[3];
980  oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
981  it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
982 #define Z_CHKGPG(I,N) \
983  if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
984  { \
985  DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
986  oldRepo->set##N##Check( ngpg[I] ); \
987  oldRepoModified = true; \
988  }
989  Z_CHKGPG( 0, Gpg );
990  Z_CHKGPG( 1, RepoGpg );
991  Z_CHKGPG( 2, PkgGpg );
992 #undef Z_CHKGPG
993  }
994 
995  // save if modified:
996  if ( oldRepoModified )
997  {
998  modifyRepository( oldRepo->alias(), *oldRepo );
999  }
1000  }
1001  }
1002 
1003  // Unlike reposToEnable, reposToDisable is always cleared after refresh.
1004  if ( ! service.reposToDisableEmpty() )
1005  {
1006  service.clearReposToDisable();
1007  serviceModified = true;
1008  }
1009 
1010  // Remember original service request for next refresh
1011  if ( service.repoStates() != newRepoStates )
1012  {
1013  service.setRepoStates( std::move(newRepoStates) );
1014  serviceModified = true;
1015  }
1016 
1018  // save service if modified: (unless a plugin service)
1019  if ( service.type() != ServiceType::PLUGIN )
1020  {
1021  if ( service.ttl() )
1022  {
1023  service.setLrf( Date::now() ); // remember last refresh
1024  serviceModified = true; // or use a cookie file
1025  }
1026 
1027  if ( serviceModified )
1028  {
1029  // write out modified service file.
1030  modifyService( service.alias(), service );
1031  }
1032  }
1033 
1034  if ( uglyHack.first )
1035  {
1036  throw( uglyHack.second ); // intentionally not ZYPP_THROW
1037  }
1038  }
1039 
1041 
1042  repo::ServiceType RepoManager::Impl::probeService( const Url & url ) const
1043  {
1044  try
1045  {
1046  MediaSetAccess access(url);
1047  if ( access.doesFileExist("/repo/repoindex.xml") )
1048  return repo::ServiceType::RIS;
1049  }
1050  catch ( const media::MediaException &e )
1051  {
1052  ZYPP_CAUGHT(e);
1053  // TranslatorExplanation '%s' is an URL
1054  RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
1055  enew.remember(e);
1056  ZYPP_THROW(enew);
1057  }
1058  catch ( const Exception &e )
1059  {
1060  ZYPP_CAUGHT(e);
1061  // TranslatorExplanation '%s' is an URL
1062  Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
1063  enew.remember(e);
1064  ZYPP_THROW(enew);
1065  }
1066 
1067  return repo::ServiceType::NONE;
1068  }
1069 
1070  void RepoManager::Impl::refreshGeoIPData ( const RepoInfo::url_set &urls )
1071  {
1072  try {
1073 
1074  if ( !ZConfig::instance().geoipEnabled() ) {
1075  MIL << "GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
1076  return;
1077  }
1078 
1079  std::vector<std::string> hosts;
1080  for ( const auto &baseUrl : urls ) {
1081  const auto &host = baseUrl.getHost();
1082  if ( zypp::any_of( ZConfig::instance().geoipHostnames(), [&host]( const auto &elem ){ return ( zypp::str::compareCI( host, elem ) == 0 ); } ) ) {
1083  hosts.push_back( host );
1084  break;
1085  }
1086  }
1087 
1088  if ( hosts.empty() ) {
1089  MIL << "No configured geoip URL found, not updating geoip data" << std::endl;
1090  return;
1091  }
1092 
1093  const auto &geoIPCache = ZConfig::instance().geoipCachePath();
1094 
1095  if ( filesystem::assert_dir( geoIPCache ) != 0 ) {
1096  MIL << "Unable to create cache directory for GeoIP." << std::endl;
1097  return;
1098  }
1099 
1100  if ( !PathInfo(geoIPCache).userMayRWX() ) {
1101  MIL << "No access rights for the GeoIP cache directory." << std::endl;
1102  return;
1103  }
1104 
1105  // remove all older cache entries
1106  filesystem::dirForEachExt( geoIPCache, []( const Pathname &dir, const filesystem::DirEntry &entry ){
1107  if ( entry.type != filesystem::FT_FILE )
1108  return true;
1109 
1110  PathInfo pi( dir/entry.name );
1111  auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
1112  if ( age < std::chrono::hours(24) )
1113  return true;
1114 
1115  MIL << "Removing GeoIP file for " << entry.name << " since it's older than 24hrs." << std::endl;
1116  filesystem::unlink( dir/entry.name );
1117  return true;
1118  });
1119 
1120  // go over all found hostnames
1121  std::for_each( hosts.begin(), hosts.end(), [ & ]( const std::string &hostname ) {
1122 
1123  // do not query files that are still there
1124  if ( zypp::PathInfo( geoIPCache / hostname ).isExist() ) {
1125  MIL << "Skipping GeoIP request for " << hostname << " since a valid cache entry exists." << std::endl;
1126  return;
1127  }
1128 
1129  MIL << "Query GeoIP for " << hostname << std::endl;
1130 
1131  zypp::Url url;
1132  try
1133  {
1134  url.setHost(hostname);
1135  url.setScheme("https");
1136  }
1137  catch(const zypp::Exception &e )
1138  {
1139  ZYPP_CAUGHT(e);
1140  MIL << "Ignoring invalid GeoIP hostname: " << hostname << std::endl;
1141  return;
1142  }
1143 
1144  MediaSetAccess acc( url );
1145  zypp::ManagedFile file;
1146  try {
1147  // query the file from the server
1148  file = zypp::ManagedFile (acc.provideOptionalFile("/geoip"), filesystem::unlink );
1149 
1150  } catch ( const zypp::Exception &e ) {
1151  ZYPP_CAUGHT(e);
1152  MIL << "Failed to query GeoIP from hostname: " << hostname << std::endl;
1153  return;
1154  }
1155  if ( !file->empty() ) {
1156 
1157  constexpr auto writeHostToFile = []( const Pathname &fName, const std::string &host ){
1158  std::ofstream out;
1159  out.open( fName.asString(), std::ios_base::trunc );
1160  if ( out.is_open() ) {
1161  out << host << std::endl;
1162  } else {
1163  MIL << "Failed to create/open GeoIP cache file " << fName << std::endl;
1164  }
1165  };
1166 
1167  std::string geoipMirror;
1168  try {
1169  xml::Reader reader( *file );
1170  if ( reader.seekToNode( 1, "host" ) ) {
1171  const auto &str = reader.nodeText().asString();
1172 
1173  // make a dummy URL to ensure the hostname is valid
1174  zypp::Url testUrl;
1175  testUrl.setHost(str);
1176  testUrl.setScheme("https");
1177 
1178  if ( testUrl.isValid() ) {
1179  MIL << "Storing geoIP redirection: " << hostname << " -> " << str << std::endl;
1180  geoipMirror = str;
1181  }
1182 
1183  } else {
1184  MIL << "No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
1185  }
1186  } catch ( const zypp::Exception &e ) {
1187  ZYPP_CAUGHT(e);
1188  MIL << "Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
1189  }
1190 
1191  writeHostToFile( geoIPCache / hostname, geoipMirror );
1192  }
1193  });
1194 
1195  } catch ( const zypp::Exception &e ) {
1196  ZYPP_CAUGHT(e);
1197  MIL << "Failed to query GeoIP data." << std::endl;
1198  }
1199  }
1200 
1202  //
1203  // CLASS NAME : RepoManager
1204  //
1206 
1208  : _pimpl( new Impl(std::move(opt)) )
1209  {}
1210 
1212  {}
1213 
1215  { return _pimpl->repoEmpty(); }
1216 
1218  { return _pimpl->repoSize(); }
1219 
1221  { return _pimpl->repoBegin(); }
1222 
1224  { return _pimpl->repoEnd(); }
1225 
1226  RepoInfo RepoManager::getRepo( const std::string & alias ) const
1227  { return _pimpl->getRepo( alias ); }
1228 
1229  bool RepoManager::hasRepo( const std::string & alias ) const
1230  { return _pimpl->hasRepo( alias ); }
1231 
1232  std::string RepoManager::makeStupidAlias( const Url & url_r )
1233  {
1234  std::string ret( url_r.getScheme() );
1235  if ( ret.empty() )
1236  ret = "repo-";
1237  else
1238  ret += "-";
1239 
1240  std::string host( url_r.getHost() );
1241  if ( ! host.empty() )
1242  {
1243  ret += host;
1244  ret += "-";
1245  }
1246 
1247  static Date::ValueType serial = Date::now();
1248  ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8);
1249  return ret;
1250  }
1251 
1253  { return _pimpl->metadataStatus( info ); }
1254 
1256  { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
1257 
1259  { return _pimpl->metadataPath( info ); }
1260 
1262  { return _pimpl->packagesPath( info ); }
1263 
1265  { return _pimpl->refreshMetadata( info, policy, progressrcv ); }
1266 
1267  void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1268  { return _pimpl->cleanMetadata( info, progressrcv ); }
1269 
1270  void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1271  { return _pimpl->cleanPackages( info, progressrcv ); }
1272 
1274  { return _pimpl->cacheStatus( info ); }
1275 
1276  void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
1277  { return _pimpl->buildCache( info, policy, progressrcv ); }
1278 
1279  void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1280  { return _pimpl->cleanCache( info, progressrcv ); }
1281 
1282  bool RepoManager::isCached( const RepoInfo &info ) const
1283  { return _pimpl->isCached( info ); }
1284 
1285  void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1286  { return _pimpl->loadFromCache( info, progressrcv ); }
1287 
1289  { return _pimpl->cleanCacheDirGarbage( progressrcv ); }
1290 
1291  repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const
1292  { return _pimpl->probe( url, path ); }
1293 
1295  { return _pimpl->probe( url ); }
1296 
1297  void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1298  { return _pimpl->addRepository( info, progressrcv ); }
1299 
1300  void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv )
1301  { return _pimpl->addRepositories( url, progressrcv ); }
1302 
1303  void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1304  { return _pimpl->removeRepository( info, progressrcv ); }
1305 
1306  void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv )
1307  { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
1308 
1309  RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv )
1310  { return _pimpl->getRepositoryInfo( alias ); }
1311 
1312  RepoInfo RepoManager::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
1313  { return _pimpl->getRepositoryInfo( url, urlview ); }
1314 
1316  { return _pimpl->serviceEmpty(); }
1317 
1319  { return _pimpl->serviceSize(); }
1320 
1322  { return _pimpl->serviceBegin(); }
1323 
1325  { return _pimpl->serviceEnd(); }
1326 
1327  ServiceInfo RepoManager::getService( const std::string & alias ) const
1328  { return _pimpl->getService( alias ); }
1329 
1330  bool RepoManager::hasService( const std::string & alias ) const
1331  { return _pimpl->hasService( alias ); }
1332 
1334  { return _pimpl->probeService( url ); }
1335 
1336  void RepoManager::addService( const std::string & alias, const Url& url )
1337  { return _pimpl->addService( alias, url ); }
1338 
1339  void RepoManager::addService( const ServiceInfo & service )
1340  { return _pimpl->addService( service ); }
1341 
1342  void RepoManager::removeService( const std::string & alias )
1343  { return _pimpl->removeService( alias ); }
1344 
1345  void RepoManager::removeService( const ServiceInfo & service )
1346  { return _pimpl->removeService( service ); }
1347 
1349  { return _pimpl->refreshServices( options_r ); }
1350 
1351  void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
1352  { return _pimpl->refreshService( alias, options_r ); }
1353 
1354  void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
1355  { return _pimpl->refreshService( service, options_r ); }
1356 
1357  void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service )
1358  { return _pimpl->modifyService( oldAlias, service ); }
1359 
1361  { return _pimpl->refreshGeoIPData( urls ); }
1362 
1364 
1365  std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
1366  { return str << *obj._pimpl; }
1367 
1369 } // namespace zypp
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy)
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:537
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
RefreshCheckStatus
Possibly return state of checkIfRefreshMEtadata function.
Definition: RepoManager.h:148
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:320
Service data.
Definition: ServiceInfo.h:36
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: Target.cc:102
Interface to gettext.
RepoSet::size_type RepoSizeType
Definition: RepoManager.h:73
#define MIL
Definition: Logger.h:96
constexpr std::string_view Url("url")
static const std::string & sha1()
sha1
Definition: Digest.cc:44
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:30
bool hasRepo(const std::string &alias) const
Return whether there is a known repository for alias.
Pathname solv_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the solv cache path for a repository.
thrown when it was impossible to determine this repo type.
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:238
Retrieval of repository list for a service.
Definition: ServiceRepos.h:25
#define _(MSG)
Definition: Gettext.h:37
Repository metadata verification beyond GPG.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:429
static ManagedFile provideFileFromUrl(const Url &file_url, ProvideFileOptions options=PROVIDE_DEFAULT)
Provides file from url.
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:925
#define OPT_PROGRESS
Definition: RepoManager.cc:71
std::list< RepoInfo > repositories_in_file(const Pathname &file)
Reads RepoInfo&#39;s from a repo file.
Impl * clone() const
clone for RWCOW_pointer
Definition: RepoManager.cc:244
bool collect(const RepoInfo &repo)
void removeService(const std::string &alias)
Removes service specified by its name.
RefreshCheckStatus
Possibly return state of checkIfRefreshMEtadata function.
Definition: refresh.h:40
zypp_private::repo::PluginRepoverification _pluginRepoverification
Definition: RepoManager.cc:239
void cleanCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
clean local cache
ServiceInfo getService(const std::string &alias) const
Finds ServiceInfo by alias or return ServiceInfo::noService.
RepoSizeType repoSize() const
void refreshServices(const RefreshServiceOptions &options_r)
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
Definition: progressdata.h:140
Pathname metadataPath(const RepoInfo &info) const
Path where the metadata is downloaded and kept.
void loadFromCache(const RepoInfo &info, OPT_PROGRESS)
SignalProxy< void(zypp::repo::RepoType)> sigProbedTypeChanged()
Definition: refresh.cc:147
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
String related utilities and Regular expression matching.
Impl(RepoManagerOptions &&opt)
Definition: RepoManager.cc:153
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
Definition: SerialNumber.cc:52
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
Pathname packagescache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the packages cache path for a repository.
static expected< repo::RefreshContextRef< ZyppContextRefType > > create(ZyppContextRefType zyppContext, zypp::RepoInfo info, zypp::RepoManagerOptions opts)
Definition: refresh.cc:28
void setHost(const std::string &host)
Set the hostname or IP in the URL authority.
Definition: Url.cc:752
void addRepositories(const Url &url, OPT_PROGRESS)
RepoInfo getRepo(const std::string &alias) const
Find RepoInfo by alias or return RepoInfo::noRepo.
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
repo::ServiceType probeService(const Url &url) const
void buildCache(const RepoInfo &info, CacheBuildPolicy policy, OPT_PROGRESS)
Url::asString() view options.
Definition: UrlBase.h:39
Pathname rawcache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw cache path for a repository, this is usually /var/cache/zypp/alias.
#define ERR
Definition: Logger.h:98
repo::RepoType probe(const Url &url, const Pathname &path=Pathname()) const
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
Repo manager settings.
void loadFromCache(const RepoInfo &info, OPT_PROGRESS)
void cleanCacheDirGarbage(const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove any subdirectories of cache directories which no longer belong to any of known repositories...
time_t ValueType
Definition: Date.h:38
static const ServiceType RIS
Repository Index Service (RIS) (formerly known as &#39;Novell Update&#39; (NU) service)
Definition: ServiceType.h:32
~Impl() override
Definition: RepoManager.cc:166
void modifyRepository(const std::string &alias, const RepoInfo &newinfo, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Modify repository attributes.
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:30
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:441
void addRepository(const RepoInfo &info, OPT_PROGRESS)
static Pool instance()
Singleton ctor.
Definition: Pool.h:55
void cleanPackages(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local package cache.
RepoInfo getRepositoryInfo(const std::string &alias, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Find a matching repository info.
void addProbedRepository(const RepoInfo &info, repo::RepoType probedType)
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition: Url.cc:672
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:701
void removeRepository(const RepoInfo &info, OPT_PROGRESS) override
void assert_alias(const RepoInfo &info)
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
std::string alias() const
unique identifier for this source.
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:282
void addService(const std::string &alias, const Url &url)
Adds a new service by its alias and URL.
bool serviceEmpty() const
Gets true if no service is in RepoManager (so no one in specified location)
static const ServiceType NONE
No service set.
Definition: ServiceType.h:34
Service type enumeration.
Definition: ServiceType.h:26
std::string asUserString() const
Translated error message as string suitable for the user.
Definition: Exception.cc:101
Pathname rawproductdata_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw product metadata path for a repository, this is inside the raw cache dir...
RawMetadataRefreshPolicy
Definition: refresh.h:30
#define WAR
Definition: Logger.h:97
bool repoEmpty() const
std::string asCompleteString() const
Returns a complete string representation of the Url object.
Definition: Url.cc:509
AsyncOpRef< expected< repo::RefreshCheckStatus > > checkIfToRefreshMetadata(repo::AsyncRefreshContextRef refCtx, ProvideMediaHandle medium, ProgressObserverRef progressObserver=nullptr)
ServiceSet::size_type ServiceSizeType
Definition: RepoManager.h:68
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition: Pool.cc:286
time_t Duration
Definition: Date.h:39
void modifyService(const std::string &oldAlias, const ServiceInfo &service)
Modifies service file (rewrites it with new values) and underlying repositories if needed...
static const ServiceType PLUGIN
Plugin services are scripts installed on your system that provide the package manager with repositori...
Definition: ServiceType.h:43
bool isCached(const RepoInfo &info) const
Whether a repository exists in cache.
bool isValid() const
Verifies the Url.
Definition: Url.cc:493
std::list< Url > url_set
Definition: RepoInfo.h:108
Pathname geoipCachePath() const
Path where the geoip caches are kept (/var/cache/zypp/geoip)
Definition: ZConfig.cc:1135
ServiceConstIterator serviceBegin() const
Iterator to first service in internal storage.
std::vector< std::string > Arguments
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:249
transform_iterator< repo::RepoVariablesUrlReplacer, url_set::const_iterator > urls_const_iterator
Definition: RepoInfo.h:110
static const RepoType NONE
Definition: RepoType.h:32
int compareCI(const C_Str &lhs, const C_Str &rhs)
Definition: String.h:984
bool isTmpRepo(const RepoInfo &info_r)
Whether repo is not under RM control and provides its own methadata paths.
ServiceConstIterator serviceEnd() const
Iterator to place behind last service in internal storage.
bool userMayRX() const
Definition: PathInfo.h:351
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:437
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:606
RWCOW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: RepoManager.h:656
std::list< RepoInfo > readRepoFile(const Url &repo_file)
Parses repo_file and returns a list of RepoInfo objects corresponding to repositories found within th...
Definition: RepoManager.cc:134
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
Definition: RepoManager.h:102
void refreshService(const ServiceInfo &service, const RefreshServiceOptions &options_r)
Definition: RepoManager.cc:231
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy, OPT_PROGRESS)
Base class for Exception.
Definition: Exception.h:146
void assert_urls(const RepoInfo &info)
Exception for repository handling.
Definition: RepoException.h:37
RepoConstIterator repoBegin() const
bool any_of(const Container &c, Fnc &&cb)
Definition: Algorithm.h:76
static std::string makeStupidAlias(const Url &url_r=Url())
Some stupid string but suitable as alias for your url if nothing better is available.
media::MediaAccessId _mid
Definition: RepoManager.cc:128
static Date now()
Return the current time.
Definition: Date.h:78
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
Definition: RepoManager.cc:80
#define PL_(MSG1, MSG2, N)
Definition: Gettext.h:40
AsyncOpRef< expected< zypp::repo::RepoType > > probeRepoType(ContextRef ctx, ProvideMediaHandle medium, zypp::Pathname path, std::optional< zypp::Pathname > targetPath={})
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:592
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:429
void assert_url(const ServiceInfo &info)
RepoSet::const_iterator RepoConstIterator
Definition: RepoManager.h:72
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition: PathInfo.cc:594
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
std::map< std::string, RepoState > RepoStates
Definition: ServiceInfo.h:185
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > refreshMetadata(repo::AsyncRefreshContextRef refCtx, ProvideMediaHandle medium, ProgressObserverRef progressObserver)
static const RepoType RPMPLAINDIR
Definition: RepoType.h:31
RepoStatus metadataStatus(const RepoInfo &info) const
Status of local metadata.
Track changing files or directories.
Definition: RepoStatus.h:40
Repository already exists and some unique attribute can&#39;t be duplicated.
ServiceSizeType serviceSize() const
Gets count of service in RepoManager (in specified location)
bool foundAliasIn(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Check if alias_r is present in repo/service container.
Functor replacing repository variables.
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r)
Repository addRepoSolv(const Pathname &file_r, const std::string &name_r)
Load Solvables from a solv-file into a Repository named name_r.
Definition: Pool.cc:185
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
RepoConstIterator repoEnd() const
void refreshGeoIp(const RepoInfo::url_set &urls)
std::string hexstring(char n, int w=4)
Definition: String.h:324
RepoManager implementation.
std::ostream & operator<<(std::ostream &str, const RepoManager::Impl &obj)
Definition: RepoManager.cc:250
void cleanMetadata(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local metadata.
Url manipulation class.
Definition: Url.h:91
RepoStatus cacheStatus(const RepoInfo &info) const
Status of metadata cache.
bool hasService(const std::string &alias) const
Return whether there is a known service for alias.
#define ZYPP_LOCAL
Definition: Globals.h:59
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > buildCache(repo::AsyncRefreshContextRef refCtx, ProgressObserverRef progressObserver=nullptr)
#define Z_CHKGPG(I, N)
RepoManager(RepoManagerOptions options=RepoManagerOptions())
#define DBG
Definition: Logger.h:95
Repository type enumeration.
Definition: RepoType.h:27
ServiceSet::const_iterator ServiceConstIterator
Definition: RepoManager.h:67
Pathname packagesPath(const RepoInfo &info) const
Path where the rpm packages are downloaded and kept.