libzypp  17.32.5
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 
145  std::ostream & operator<<( std::ostream & str, RepoManager::RawMetadataRefreshPolicy obj )
146  {
147  switch ( obj ) {
148 #define OUTS(V) case RepoManager::V: str << #V; break
150  OUTS( RefreshForced );
152 #undef OUTS
153  }
154  return str;
155  }
156 
157  std::ostream & operator<<( std::ostream & str, RepoManager::RefreshCheckStatus obj )
158  {
159  switch ( obj ) {
160 #define OUTS(V) case RepoManager::V: str << #V; break
161  OUTS( REFRESH_NEEDED );
164 #undef OUTS
165  }
166  return str;
167  }
168 
169  std::ostream & operator<<( std::ostream & str, RepoManager::CacheBuildPolicy obj )
170  {
171  switch ( obj ) {
172 #define OUTS(V) case RepoManager::V: str << #V; break
173  OUTS( BuildIfNeeded );
174  OUTS( BuildForced );
175 #undef OUTS
176  }
177  return str;
178  }
179 
186  {
187  public:
189  : RepoManagerBaseImpl(std::move(opt)),
190  _pluginRepoverification(_options.pluginsPath / "repoverification",
191  _options.rootDir) {
192  init_knownServices();
193  init_knownRepositories();
194  }
195 
196  Impl(const Impl &) = default;
197  Impl(Impl &&) = delete;
198  Impl &operator=(const Impl &) = delete;
199  Impl &operator=(Impl &&) = delete;
200 
201  ~Impl() override
202  {
203  // trigger appdata refresh if some repos change
204  if ( ( _reposDirty || env::ZYPP_PLUGIN_APPDATA_FORCE_COLLECT() )
205  && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
206  {
207  try {
208  std::list<Pathname> entries;
209  filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
210  if ( ! entries.empty() )
211  {
213  cmd.push_back( "<" ); // discard stdin
214  cmd.push_back( ">" ); // discard stdout
215  cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
216  for ( const auto & rinfo : repos() )
217  {
218  if ( ! rinfo.enabled() )
219  continue;
220  cmd.push_back( "-R" );
221  cmd.push_back( rinfo.alias() );
222  cmd.push_back( "-t" );
223  cmd.push_back( rinfo.type().asString() );
224  cmd.push_back( "-p" );
225  cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache
226  }
227 
228  for_( it, entries.begin(), entries.end() )
229  {
230  PathInfo pi( *it );
231  //DBG << "/tmp/xx ->" << pi << endl;
232  if ( pi.isFile() && pi.userMayRX() )
233  {
234  // trigger plugin
235  cmd[2] = pi.asString(); // [2] - PROGRAM
237  }
238  }
239  }
240  }
241  catch (...) {} // no throw in dtor
242  }
243  }
244 
245  public:
247 
248  void refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, OPT_PROGRESS );
249 
250  void buildCache( const RepoInfo & info, CacheBuildPolicy policy, OPT_PROGRESS );
251 
252  repo::RepoType probe( const Url & url, const Pathname & path = Pathname() ) const;
253 
254  void loadFromCache( const RepoInfo & info, OPT_PROGRESS );
255 
256  void addRepository( const RepoInfo & info, OPT_PROGRESS );
257 
258  void addRepositories( const Url & url, OPT_PROGRESS );
259 
260  void removeRepository ( const RepoInfo & info, OPT_PROGRESS ) override;
261 
262  public:
263  void refreshServices( const RefreshServiceOptions & options_r );
264 
265  void refreshService( const std::string & alias, const RefreshServiceOptions & options_r );
266  void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
267  { refreshService( service.alias(), options_r ); }
268 
269  repo::ServiceType probeService( const Url & url ) const;
270 
271  void refreshGeoIPData ( const RepoInfo::url_set &urls );
272 
273  private:
275 
276  private:
277  friend Impl * rwcowClone<Impl>( const Impl * rhs );
279  Impl * clone() const
280  { return new Impl( *this ); }
281  };
283 
285  inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj )
286  { return str << "RepoManager::Impl"; }
287 
289  {
290  // Hotfix for bsc#1223094: No media access for CD/DVD unless rawchache is missing
291  if ( url.schemeIsVolatile() ) {
292  return metadataStatus( info ).empty() ? REFRESH_NEEDED : REPO_UP_TO_DATE;
293  }
294 
295  using namespace zyppng::operators;
296  using zyppng::operators::operator|;
297 
298  refreshGeoIPData( { url } );
299 
300  auto ctx = zyppng::SyncContext::create();
301  auto res = zyppng::repo::SyncRefreshContext::create( ctx, info, _options )
302  | and_then( [&]( zyppng::repo::SyncRefreshContextRef &&refCtx ) {
303  refCtx->setPolicy ( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
304  return ctx->provider()->attachMedia( url, zyppng::ProvideMediaSpec() )
305  | and_then( [ r = std::move(refCtx) ]( auto &&mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), mediaHandle, nullptr ); } );
306  } );
307 
308  if ( !res ) {
309  ZYPP_RETHROW ( res.error() );
310  }
311  return static_cast<RepoManager::RefreshCheckStatus>(res.get());
312  }
313 
314 
315  void RepoManager::Impl::refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, const ProgressData::ReceiverFnc & progress )
316  {
317  using namespace zyppng;
318  using namespace zyppng::operators;
319  using zyppng::operators::operator|;
320 
321  // make sure geoIP data is up 2 date
322  refreshGeoIPData( info.baseUrls() );
323 
324  // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
325  media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 );
326 
327  // we will throw this later if no URL checks out fine
328  RepoException rexception( info, PL_("Valid metadata not found at specified URL",
329  "Valid metadata not found at specified URLs",
330  info.baseUrlsSize() ) );
331 
332 
333  auto ctx = SyncContext::create();
334 
335  // helper callback in case the repo type changes on the remote
336  const auto &updateProbedType = [&]( repo::RepoType repokind ) {
337  // update probed type only for repos in system
338  for_( it, repoBegin(), repoEnd() )
339  {
340  if ( info.alias() == (*it).alias() )
341  {
342  RepoInfo modifiedrepo = *it;
343  modifiedrepo.setType( repokind );
344  // don't modify .repo in refresh.
345  // modifyRepository( info.alias(), modifiedrepo );
346  break;
347  }
348  }
349  };
350 
351  // try urls one by one
352  for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
353  {
354  // Hotfix for bsc#1223094: No media access for CD/DVD unless rawchache is missing
355  if ( it->schemeIsVolatile() && not metadataStatus( info ).empty() ) {
356  // we are done.
357  return;
358  }
359 
360  try {
361  auto res = zyppng::repo::SyncRefreshContext::create( ctx, info, _options )
362  | and_then( [&]( zyppng::repo::SyncRefreshContextRef refCtx ) {
363  refCtx->setPolicy( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
364  // in case probe detects a different repokind, update our internal repos
365  refCtx->connectFunc( &zyppng::repo::SyncRefreshContext::sigProbedTypeChanged, updateProbedType );
366  return ctx->provider()->attachMedia( *it, zyppng::ProvideMediaSpec() )
367  | and_then( [ refCtx ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), std::move(mediaHandle), nullptr); } );
368  });
369 
370  if ( !res ) {
371  ZYPP_RETHROW( res.error() );
372  }
373  if ( ! isTmpRepo( info ) )
374  reposManip(); // remember to trigger appdata refresh
375 
376  // we are done.
377  return;
378 
379  } catch ( const zypp::Exception &e ) {
380  ERR << "Trying another url..." << endl;
381 
382  // remember the exception caught for the *first URL*
383  // if all other URLs fail, the rexception will be thrown with the
384  // cause of the problem of the first URL remembered
385  if (it == info.baseUrlsBegin())
386  rexception.remember( e );
387  else
388  rexception.addHistory( e.asUserString() );
389  }
390  } // for every url
391  ERR << "No more urls..." << endl;
392  ZYPP_THROW(rexception);
393 
394  }
395 
396  void RepoManager::Impl::buildCache( const RepoInfo & info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
397  {
398  assert_alias(info);
399  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
400  Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
401 
402  if( filesystem::assert_dir(_options.repoCachePath) )
403  {
404  Exception ex(str::form( _("Can't create %s"), _options.repoCachePath.c_str()) );
405  ZYPP_THROW(ex);
406  }
407  RepoStatus raw_metadata_status = metadataStatus(info);
408  if ( raw_metadata_status.empty() )
409  {
410  /* if there is no cache at this point, we refresh the raw
411  in case this is the first time - if it's !autorefresh,
412  we may still refresh */
413  refreshMetadata(info, RefreshIfNeeded, progressrcv );
414  raw_metadata_status = metadataStatus(info);
415  }
416 
417  bool needs_cleaning = false;
418  if ( isCached( info ) )
419  {
420  MIL << info.alias() << " is already cached." << endl;
421  RepoStatus cache_status = cacheStatus(info);
422 
423  if ( cache_status == raw_metadata_status )
424  {
425  MIL << info.alias() << " cache is up to date with metadata." << endl;
426  if ( policy == BuildIfNeeded )
427  {
428  // On the fly add missing solv.idx files for bash completion.
429  const Pathname & base = solv_path_for_repoinfo( _options, info);
430  if ( ! PathInfo(base/"solv.idx").isExist() )
431  sat::updateSolvFileIndex( base/"solv" );
432 
433  return;
434  }
435  else {
436  MIL << info.alias() << " cache rebuild is forced" << endl;
437  }
438  }
439 
440  needs_cleaning = true;
441  }
442 
443  ProgressData progress(100);
444  callback::SendReport<ProgressReport> report;
445  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
446  progress.name(str::form(_("Building repository '%s' cache"), info.label().c_str()));
447  progress.toMin();
448 
449  if (needs_cleaning)
450  {
451  cleanCache(info);
452  }
453 
454  MIL << info.alias() << " building cache..." << info.type() << endl;
455 
456  Pathname base = solv_path_for_repoinfo( _options, info);
457 
458  if( filesystem::assert_dir(base) )
459  {
460  Exception ex(str::form( _("Can't create %s"), base.c_str()) );
461  ZYPP_THROW(ex);
462  }
463 
464  if( ! PathInfo(base).userMayW() )
465  {
466  Exception ex(str::form( _("Can't create cache at %s - no writing permissions."), base.c_str()) );
467  ZYPP_THROW(ex);
468  }
469  Pathname solvfile = base / "solv";
470 
471  // do we have type?
472  repo::RepoType repokind = info.type();
473 
474  // if the type is unknown, try probing.
475  switch ( repokind.toEnum() )
476  {
477  case RepoType::NONE_e:
478  // unknown, probe the local metadata
479  repokind = probeCache( productdatapath );
480  break;
481  default:
482  break;
483  }
484 
485  MIL << "repo type is " << repokind << endl;
486 
487  switch ( repokind.toEnum() )
488  {
489  case RepoType::RPMMD_e :
490  case RepoType::YAST2_e :
492  {
493  // Take care we unlink the solvfile on exception
494  ManagedFile guard( solvfile, filesystem::unlink );
495  scoped_ptr<MediaMounter> forPlainDirs;
496 
498  cmd.push_back( PathInfo( "/usr/bin/repo2solv" ).isFile() ? "repo2solv" : "repo2solv.sh" );
499  // repo2solv expects -o as 1st arg!
500  cmd.push_back( "-o" );
501  cmd.push_back( solvfile.asString() );
502  cmd.push_back( "-X" ); // autogenerate pattern from pattern-package
503  // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
504 
505  if ( repokind == RepoType::RPMPLAINDIR )
506  {
507  forPlainDirs.reset( new MediaMounter( info.url() ) );
508  // recusive for plaindir as 2nd arg!
509  cmd.push_back( "-R" );
510  // FIXME this does only work form dir: URLs
511  cmd.push_back( forPlainDirs->getPathName( info.path() ).c_str() );
512  }
513  else
514  cmd.push_back( productdatapath.asString() );
515 
516  ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
517  std::string errdetail;
518 
519  for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
520  WAR << " " << output;
521  errdetail += output;
522  }
523 
524  int ret = prog.close();
525  if ( ret != 0 )
526  {
527  RepoException ex(info, str::form( _("Failed to cache repo (%d)."), ret ));
528  ex.addHistory( str::Str() << prog.command() << endl << errdetail << prog.execError() ); // errdetail lines are NL-terminaled!
529  ZYPP_THROW(ex);
530  }
531 
532  // We keep it.
533  guard.resetDispose();
534  sat::updateSolvFileIndex( solvfile ); // content digest for zypper bash completion
535  }
536  break;
537  default:
538  ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") ));
539  break;
540  }
541  // update timestamp and checksum
542  setCacheStatus(info, raw_metadata_status);
543  MIL << "Commit cache.." << endl;
544  progress.toMax();
545  }
546 
548 
549 
556  repo::RepoType RepoManager::Impl::probe( const Url & url, const Pathname & path ) const
557  {
558  using namespace zyppng;
559  using namespace zyppng::operators;
560  using zyppng::operators::operator|;
561 
562  auto ctx = zyppng::SyncContext::create();
563  auto res = ctx->provider()->attachMedia( url, zyppng::ProvideMediaSpec() )
564  | and_then( [&]( auto mediaHandle ) {
565  return zyppng::RepoManagerWorkflow::probeRepoType( ctx, mediaHandle, path );
566  });
567 
568  if ( !res ) {
569  ZYPP_RETHROW ( res.error() );
570  }
571  return res.get();
572  }
573 
575 
576  void RepoManager::Impl::loadFromCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
577  {
578  try
579  {
580  RepoManagerBaseImpl::loadFromCache( info, progressrcv );
581  }
582  catch ( const Exception & exp )
583  {
584  ZYPP_CAUGHT( exp );
585  MIL << "Try to handle exception by rebuilding the solv-file" << endl;
586  cleanCache( info, progressrcv );
587  buildCache( info, BuildIfNeeded, progressrcv );
588 
589  sat::Pool::instance().addRepoSolv( solv_path_for_repoinfo(_options, info) / "solv", info );
590  }
591  }
592 
594 
595  void RepoManager::Impl::addRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
596  {
597  assert_alias(info);
598 
599  ProgressData progress(100);
600  callback::SendReport<ProgressReport> report;
601  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
602  progress.name(str::form(_("Adding repository '%s'"), info.label().c_str()));
603  progress.toMin();
604 
605  MIL << "Try adding repo " << info << endl;
606 
607  RepoInfo tosave = info;
608  if ( repos().find(tosave) != repos().end() )
610 
611  // check the first url for now
612  if ( _options.probe )
613  {
614  DBG << "unknown repository type, probing" << endl;
615  assert_urls(tosave);
616 
617  RepoType probedtype( probe( tosave.url(), info.path() ) );
618  if ( probedtype == RepoType::NONE )
620  else
621  tosave.setType(probedtype);
622  }
623 
624  progress.set(50);
625 
626  RepoManagerBaseImpl::addProbedRepository ( info, info.type() );
627 
628  progress.toMax();
629  MIL << "done" << endl;
630  }
631 
632 
633  void RepoManager::Impl::addRepositories( const Url & url, const ProgressData::ReceiverFnc & progressrcv )
634  {
635  std::list<RepoInfo> repos = readRepoFile(url);
636  for ( std::list<RepoInfo>::const_iterator it = repos.begin();
637  it != repos.end();
638  ++it )
639  {
640  // look if the alias is in the known repos.
641  for_ ( kit, repoBegin(), repoEnd() )
642  {
643  if ( (*it).alias() == (*kit).alias() )
644  {
645  ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << endl;
647  }
648  }
649  }
650 
651  std::string filename = Pathname(url.getPathName()).basename();
652 
653  if ( filename == Pathname() )
654  {
655  // TranslatorExplanation '%s' is an URL
656  ZYPP_THROW(RepoException(str::form( _("Invalid repo file name at '%s'"), url.asString().c_str() )));
657  }
658 
659  // assert the directory exists
660  filesystem::assert_dir(_options.knownReposPath);
661 
662  Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
663  // now we have a filename that does not exists
664  MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
665 
666  std::ofstream file(repofile.c_str());
667  if (!file)
668  {
669  // TranslatorExplanation '%s' is a filename
670  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
671  }
672 
673  for ( std::list<RepoInfo>::iterator it = repos.begin();
674  it != repos.end();
675  ++it )
676  {
677  MIL << "Saving " << (*it).alias() << endl;
678  it->dumpAsIniOn(file);
679  it->setFilepath(repofile);
680  it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
681  it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
682  reposManip().insert(*it);
683 
684  HistoryLog(_options.rootDir).addRepository(*it);
685  }
686 
687  MIL << "done" << endl;
688  }
689 
690  void RepoManager::Impl::removeRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv )
691  {
692  callback::SendReport<ProgressReport> report;
693  ProgressReportAdaptor adapt( progressrcv, report );
694  removeRepositoryImpl( info, std::ref(adapt) );
695  }
696 
698  //
699  // Services
700  //
702 
703  void RepoManager::Impl::refreshServices( const RefreshServiceOptions & options_r )
704  {
705  // copy the set of services since refreshService
706  // can eventually invalidate the iterator
707  ServiceSet services( serviceBegin(), serviceEnd() );
708  for_( it, services.begin(), services.end() )
709  {
710  if ( !it->enabled() )
711  continue;
712 
713  try {
714  refreshService(*it, options_r);
715  }
716  catch ( const repo::ServicePluginInformalException & e )
717  { ;/* ignore ServicePluginInformalException */ }
718  }
719  }
720 
721  void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
722  {
723  ServiceInfo service( getService( alias ) );
724  assert_alias( service );
725  assert_url( service );
726  MIL << "Going to refresh service '" << service.alias() << "', url: " << service.url() << ", opts: " << options_r << endl;
727 
728  if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
729  {
730  // Service defines a TTL; maybe we can re-use existing data without refresh.
731  Date lrf = service.lrf();
732  if ( lrf )
733  {
734  Date now( Date::now() );
735  if ( lrf <= now )
736  {
737  if ( (lrf+=service.ttl()) > now ) // lrf+= !
738  {
739  MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
740  return;
741  }
742  }
743  else
744  WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
745  }
746  }
747 
748  // NOTE: It might be necessary to modify and rewrite the service info.
749  // Either when probing the type, or when adjusting the repositories
750  // enable/disable state.:
751  bool serviceModified = false;
752 
754 
755  // if the type is unknown, try probing.
756  if ( service.type() == repo::ServiceType::NONE )
757  {
758  repo::ServiceType type = probeService( service.url() );
759  if ( type != ServiceType::NONE )
760  {
761  service.setProbedType( type ); // lazy init!
762  serviceModified = true;
763  }
764  }
765 
766  // get target distro identifier
767  std::string servicesTargetDistro = _options.servicesTargetDistro;
768  if ( servicesTargetDistro.empty() )
769  {
770  servicesTargetDistro = Target::targetDistribution( Pathname() );
771  }
772  DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
773 
774  // parse it
775  Date::Duration origTtl = service.ttl(); // FIXME Ugly hack: const service.ttl modified when parsing
776  RepoCollector collector(servicesTargetDistro);
777  // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
778  // which is actually a notification. Using an exception for this
779  // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
780  // and in zypper.
781  std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
782  try {
783  // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they
784  // are not aware of the RepoManagers rootDir. The service url, as created in known_services,
785  // contains the full path to the script. The script however has to be executed chrooted.
786  // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace
787  // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it
788  // to ServiceRepos.
789  ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
790  }
791  catch ( const repo::ServicePluginInformalException & e )
792  {
793  /* ignore ServicePluginInformalException and throw later */
794  uglyHack.first = true;
795  uglyHack.second = e;
796  }
797  if ( service.ttl() != origTtl ) // repoindex.xml changed ttl
798  {
799  if ( !service.ttl() )
800  service.setLrf( Date() ); // don't need lrf when zero ttl
801  serviceModified = true;
802  }
804  // On the fly remember the new repo states as defined the reopoindex.xml.
805  // Move into ServiceInfo later.
806  ServiceInfo::RepoStates newRepoStates;
807 
808  // set service alias and base url for all collected repositories
809  for_( it, collector.repos.begin(), collector.repos.end() )
810  {
811  // First of all: Prepend service alias:
812  it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
813  // set reference to the parent service
814  it->setService( service.alias() );
815 
816  // remember the new parsed repo state
817  newRepoStates[it->alias()] = *it;
818 
819  // - If the repo url was not set by the repoindex parser, set service's url.
820  // - Libzypp currently has problem with separate url + path handling so just
821  // append a path, if set, to the baseurls
822  // - Credentials in the url authority will be extracted later, either if the
823  // repository is added or if we check for changed urls.
824  Pathname path;
825  if ( !it->path().empty() )
826  {
827  if ( it->path() != "/" )
828  path = it->path();
829  it->setPath("");
830  }
831 
832  if ( it->baseUrlsEmpty() )
833  {
834  Url url( service.rawUrl() );
835  if ( !path.empty() )
836  url.setPathName( url.getPathName() / path );
837  it->setBaseUrl( std::move(url) );
838  }
839  else if ( !path.empty() )
840  {
841  RepoInfo::url_set urls( it->rawBaseUrls() );
842  for ( Url & url : urls )
843  {
844  url.setPathName( url.getPathName() / path );
845  }
846  it->setBaseUrls( std::move(urls) );
847  }
848  }
849 
851  // Now compare collected repos with the ones in the system...
852  //
853  RepoInfoList oldRepos;
854  getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
855 
857  // find old repositories to remove...
858  for_( oldRepo, oldRepos.begin(), oldRepos.end() )
859  {
860  if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
861  {
862  if ( oldRepo->enabled() )
863  {
864  // Currently enabled. If this was a user modification remember the state.
865  const auto & last = service.repoStates().find( oldRepo->alias() );
866  if ( last != service.repoStates().end() && ! last->second.enabled )
867  {
868  DBG << "Service removes user enabled repo " << oldRepo->alias() << endl;
869  service.addRepoToEnable( oldRepo->alias() );
870  serviceModified = true;
871  }
872  else
873  DBG << "Service removes enabled repo " << oldRepo->alias() << endl;
874  }
875  else
876  DBG << "Service removes disabled repo " << oldRepo->alias() << endl;
877 
878  removeRepository( *oldRepo );
879  }
880  }
881 
883  // create missing repositories and modify existing ones if needed...
884  UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
885  for_( it, collector.repos.begin(), collector.repos.end() )
886  {
887  // User explicitly requested the repo being enabled?
888  // User explicitly requested the repo being disabled?
889  // And hopefully not both ;) If so, enable wins.
890 
891  TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request
892  DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl;
893 
894  if ( options_r.testFlag( RefreshService_restoreStatus ) )
895  {
896  DBG << "Opt RefreshService_restoreStatus " << it->alias() << endl;
897  // this overrides any pending request!
898  // Remove from enable request list.
899  // NOTE: repoToDisable is handled differently.
900  // It gets cleared on each refresh.
901  service.delRepoToEnable( it->alias() );
902  // toBeEnabled stays indeterminate!
903  }
904  else
905  {
906  if ( service.repoToEnableFind( it->alias() ) )
907  {
908  DBG << "User request to enable service repo " << it->alias() << endl;
909  toBeEnabled = true;
910  // Remove from enable request list.
911  // NOTE: repoToDisable is handled differently.
912  // It gets cleared on each refresh.
913  service.delRepoToEnable( it->alias() );
914  serviceModified = true;
915  }
916  else if ( service.repoToDisableFind( it->alias() ) )
917  {
918  DBG << "User request to disable service repo " << it->alias() << endl;
919  toBeEnabled = false;
920  }
921  }
922 
923  RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
924  if ( oldRepo == oldRepos.end() )
925  {
926  // Not found in oldRepos ==> a new repo to add
927 
928  // Make sure the service repo is created with the appropriate enablement
929  if ( ! indeterminate(toBeEnabled) )
930  it->setEnabled( ( bool ) toBeEnabled );
931 
932  DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl;
933  addRepository( *it );
934  }
935  else
936  {
937  // ==> an exising repo to check
938  bool oldRepoModified = false;
939 
940  if ( indeterminate(toBeEnabled) )
941  {
942  // No user request: check for an old user modificaton otherwise follow service request.
943  // NOTE: Assert toBeEnabled is boolean afterwards!
944  if ( oldRepo->enabled() == it->enabled() )
945  toBeEnabled = it->enabled(); // service requests no change to the system
946  else if (options_r.testFlag( RefreshService_restoreStatus ) )
947  {
948  toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
949  DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl;
950  }
951  else
952  {
953  const auto & last = service.repoStates().find( oldRepo->alias() );
954  if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
955  toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
956  else
957  {
958  toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
959  DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << endl;
960  }
961  }
962  }
963 
964  // changed enable?
965  if ( toBeEnabled == oldRepo->enabled() )
966  {
967  DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl;
968  }
969  else if ( toBeEnabled )
970  {
971  DBG << "Service repo " << it->alias() << " gets enabled" << endl;
972  oldRepo->setEnabled( true );
973  oldRepoModified = true;
974  }
975  else
976  {
977  DBG << "Service repo " << it->alias() << " gets disabled" << endl;
978  oldRepo->setEnabled( false );
979  oldRepoModified = true;
980  }
981 
982  // all other attributes follow the service request:
983 
984  // changed name (raw!)
985  if ( oldRepo->rawName() != it->rawName() )
986  {
987  DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
988  oldRepo->setName( it->rawName() );
989  oldRepoModified = true;
990  }
991 
992  // changed autorefresh
993  if ( oldRepo->autorefresh() != it->autorefresh() )
994  {
995  DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl;
996  oldRepo->setAutorefresh( it->autorefresh() );
997  oldRepoModified = true;
998  }
999 
1000  // changed priority?
1001  if ( oldRepo->priority() != it->priority() )
1002  {
1003  DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl;
1004  oldRepo->setPriority( it->priority() );
1005  oldRepoModified = true;
1006  }
1007 
1008  // changed url?
1009  {
1010  RepoInfo::url_set newUrls( it->rawBaseUrls() );
1011  urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
1012  if ( oldRepo->rawBaseUrls() != newUrls )
1013  {
1014  DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
1015  oldRepo->setBaseUrls( std::move(newUrls) );
1016  oldRepoModified = true;
1017  }
1018  }
1019 
1020  // changed gpg check settings?
1021  // ATM only plugin services can set GPG values.
1022  if ( service.type() == ServiceType::PLUGIN )
1023  {
1024  TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
1025  TriBool ngpg[3];
1026  oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
1027  it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
1028 #define Z_CHKGPG(I,N) \
1029  if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
1030  { \
1031  DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
1032  oldRepo->set##N##Check( ngpg[I] ); \
1033  oldRepoModified = true; \
1034  }
1035  Z_CHKGPG( 0, Gpg );
1036  Z_CHKGPG( 1, RepoGpg );
1037  Z_CHKGPG( 2, PkgGpg );
1038 #undef Z_CHKGPG
1039  }
1040 
1041  // save if modified:
1042  if ( oldRepoModified )
1043  {
1044  modifyRepository( oldRepo->alias(), *oldRepo );
1045  }
1046  }
1047  }
1048 
1049  // Unlike reposToEnable, reposToDisable is always cleared after refresh.
1050  if ( ! service.reposToDisableEmpty() )
1051  {
1052  service.clearReposToDisable();
1053  serviceModified = true;
1054  }
1055 
1056  // Remember original service request for next refresh
1057  if ( service.repoStates() != newRepoStates )
1058  {
1059  service.setRepoStates( std::move(newRepoStates) );
1060  serviceModified = true;
1061  }
1062 
1064  // save service if modified: (unless a plugin service)
1065  if ( service.type() != ServiceType::PLUGIN )
1066  {
1067  if ( service.ttl() )
1068  {
1069  service.setLrf( Date::now() ); // remember last refresh
1070  serviceModified = true; // or use a cookie file
1071  }
1072 
1073  if ( serviceModified )
1074  {
1075  // write out modified service file.
1076  modifyService( service.alias(), service );
1077  }
1078  }
1079 
1080  if ( uglyHack.first )
1081  {
1082  throw( uglyHack.second ); // intentionally not ZYPP_THROW
1083  }
1084  }
1085 
1087 
1088  repo::ServiceType RepoManager::Impl::probeService( const Url & url ) const
1089  {
1090  try
1091  {
1092  MediaSetAccess access(url);
1093  if ( access.doesFileExist("/repo/repoindex.xml") )
1094  return repo::ServiceType::RIS;
1095  }
1096  catch ( const media::MediaException &e )
1097  {
1098  ZYPP_CAUGHT(e);
1099  // TranslatorExplanation '%s' is an URL
1100  RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
1101  enew.remember(e);
1102  ZYPP_THROW(enew);
1103  }
1104  catch ( const Exception &e )
1105  {
1106  ZYPP_CAUGHT(e);
1107  // TranslatorExplanation '%s' is an URL
1108  Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
1109  enew.remember(e);
1110  ZYPP_THROW(enew);
1111  }
1112 
1113  return repo::ServiceType::NONE;
1114  }
1115 
1116  void RepoManager::Impl::refreshGeoIPData ( const RepoInfo::url_set &urls )
1117  {
1118  try {
1119 
1120  if ( !ZConfig::instance().geoipEnabled() ) {
1121  MIL << "GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
1122  return;
1123  }
1124 
1125  std::vector<std::string> hosts;
1126  for ( const auto &baseUrl : urls ) {
1127  const auto &host = baseUrl.getHost();
1128  if ( zypp::any_of( ZConfig::instance().geoipHostnames(), [&host]( const auto &elem ){ return ( zypp::str::compareCI( host, elem ) == 0 ); } ) ) {
1129  hosts.push_back( host );
1130  break;
1131  }
1132  }
1133 
1134  if ( hosts.empty() ) {
1135  MIL << "No configured geoip URL found, not updating geoip data" << std::endl;
1136  return;
1137  }
1138 
1139  const auto &geoIPCache = ZConfig::instance().geoipCachePath();
1140 
1141  if ( filesystem::assert_dir( geoIPCache ) != 0 ) {
1142  MIL << "Unable to create cache directory for GeoIP." << std::endl;
1143  return;
1144  }
1145 
1146  if ( !PathInfo(geoIPCache).userMayRWX() ) {
1147  MIL << "No access rights for the GeoIP cache directory." << std::endl;
1148  return;
1149  }
1150 
1151  // remove all older cache entries
1152  filesystem::dirForEachExt( geoIPCache, []( const Pathname &dir, const filesystem::DirEntry &entry ){
1153  if ( entry.type != filesystem::FT_FILE )
1154  return true;
1155 
1156  PathInfo pi( dir/entry.name );
1157  auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
1158  if ( age < std::chrono::hours(24) )
1159  return true;
1160 
1161  MIL << "Removing GeoIP file for " << entry.name << " since it's older than 24hrs." << std::endl;
1162  filesystem::unlink( dir/entry.name );
1163  return true;
1164  });
1165 
1166  // go over all found hostnames
1167  std::for_each( hosts.begin(), hosts.end(), [ & ]( const std::string &hostname ) {
1168 
1169  // do not query files that are still there
1170  if ( zypp::PathInfo( geoIPCache / hostname ).isExist() ) {
1171  MIL << "Skipping GeoIP request for " << hostname << " since a valid cache entry exists." << std::endl;
1172  return;
1173  }
1174 
1175  MIL << "Query GeoIP for " << hostname << std::endl;
1176 
1177  zypp::Url url;
1178  try
1179  {
1180  url.setHost(hostname);
1181  url.setScheme("https");
1182  }
1183  catch(const zypp::Exception &e )
1184  {
1185  ZYPP_CAUGHT(e);
1186  MIL << "Ignoring invalid GeoIP hostname: " << hostname << std::endl;
1187  return;
1188  }
1189 
1190  MediaSetAccess acc( url );
1191  zypp::ManagedFile file;
1192  try {
1193  // query the file from the server
1194  file = zypp::ManagedFile (acc.provideOptionalFile("/geoip"), filesystem::unlink );
1195 
1196  } catch ( const zypp::Exception &e ) {
1197  ZYPP_CAUGHT(e);
1198  MIL << "Failed to query GeoIP from hostname: " << hostname << std::endl;
1199  return;
1200  }
1201  if ( !file->empty() ) {
1202 
1203  constexpr auto writeHostToFile = []( const Pathname &fName, const std::string &host ){
1204  std::ofstream out;
1205  out.open( fName.asString(), std::ios_base::trunc );
1206  if ( out.is_open() ) {
1207  out << host << std::endl;
1208  } else {
1209  MIL << "Failed to create/open GeoIP cache file " << fName << std::endl;
1210  }
1211  };
1212 
1213  std::string geoipMirror;
1214  try {
1215  xml::Reader reader( *file );
1216  if ( reader.seekToNode( 1, "host" ) ) {
1217  const auto &str = reader.nodeText().asString();
1218 
1219  // make a dummy URL to ensure the hostname is valid
1220  zypp::Url testUrl;
1221  testUrl.setHost(str);
1222  testUrl.setScheme("https");
1223 
1224  if ( testUrl.isValid() ) {
1225  MIL << "Storing geoIP redirection: " << hostname << " -> " << str << std::endl;
1226  geoipMirror = str;
1227  }
1228 
1229  } else {
1230  MIL << "No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
1231  }
1232  } catch ( const zypp::Exception &e ) {
1233  ZYPP_CAUGHT(e);
1234  MIL << "Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
1235  }
1236 
1237  writeHostToFile( geoIPCache / hostname, geoipMirror );
1238  }
1239  });
1240 
1241  } catch ( const zypp::Exception &e ) {
1242  ZYPP_CAUGHT(e);
1243  MIL << "Failed to query GeoIP data." << std::endl;
1244  }
1245  }
1246 
1248  //
1249  // CLASS NAME : RepoManager
1250  //
1252 
1254  : _pimpl( new Impl(std::move(opt)) )
1255  {}
1256 
1258  {}
1259 
1261  { return _pimpl->repoEmpty(); }
1262 
1264  { return _pimpl->repoSize(); }
1265 
1267  { return _pimpl->repoBegin(); }
1268 
1270  { return _pimpl->repoEnd(); }
1271 
1272  RepoInfo RepoManager::getRepo( const std::string & alias ) const
1273  { return _pimpl->getRepo( alias ); }
1274 
1275  bool RepoManager::hasRepo( const std::string & alias ) const
1276  { return _pimpl->hasRepo( alias ); }
1277 
1278  std::string RepoManager::makeStupidAlias( const Url & url_r )
1279  {
1280  std::string ret( url_r.getScheme() );
1281  if ( ret.empty() )
1282  ret = "repo-";
1283  else
1284  ret += "-";
1285 
1286  std::string host( url_r.getHost() );
1287  if ( ! host.empty() )
1288  {
1289  ret += host;
1290  ret += "-";
1291  }
1292 
1293  static Date::ValueType serial = Date::now();
1294  ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8);
1295  return ret;
1296  }
1297 
1299  { return _pimpl->metadataStatus( info ); }
1300 
1302  { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
1303 
1305  { return _pimpl->metadataPath( info ); }
1306 
1308  { return _pimpl->packagesPath( info ); }
1309 
1311  { return _pimpl->refreshMetadata( info, policy, progressrcv ); }
1312 
1313  void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1314  { return _pimpl->cleanMetadata( info, progressrcv ); }
1315 
1316  void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1317  { return _pimpl->cleanPackages( info, progressrcv ); }
1318 
1320  { return _pimpl->cacheStatus( info ); }
1321 
1322  void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
1323  { return _pimpl->buildCache( info, policy, progressrcv ); }
1324 
1325  void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1326  { return _pimpl->cleanCache( info, progressrcv ); }
1327 
1328  bool RepoManager::isCached( const RepoInfo &info ) const
1329  { return _pimpl->isCached( info ); }
1330 
1331  void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1332  { return _pimpl->loadFromCache( info, progressrcv ); }
1333 
1335  { return _pimpl->cleanCacheDirGarbage( progressrcv ); }
1336 
1337  repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const
1338  { return _pimpl->probe( url, path ); }
1339 
1341  { return _pimpl->probe( url ); }
1342 
1343  void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
1344  { return _pimpl->addRepository( info, progressrcv ); }
1345 
1346  void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv )
1347  { return _pimpl->addRepositories( url, progressrcv ); }
1348 
1349  void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1350  { return _pimpl->removeRepository( info, progressrcv ); }
1351 
1352  void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv )
1353  { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
1354 
1355  RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv )
1356  { return _pimpl->getRepositoryInfo( alias ); }
1357 
1358  RepoInfo RepoManager::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
1359  { return _pimpl->getRepositoryInfo( url, urlview ); }
1360 
1362  { return _pimpl->serviceEmpty(); }
1363 
1365  { return _pimpl->serviceSize(); }
1366 
1368  { return _pimpl->serviceBegin(); }
1369 
1371  { return _pimpl->serviceEnd(); }
1372 
1373  ServiceInfo RepoManager::getService( const std::string & alias ) const
1374  { return _pimpl->getService( alias ); }
1375 
1376  bool RepoManager::hasService( const std::string & alias ) const
1377  { return _pimpl->hasService( alias ); }
1378 
1380  { return _pimpl->probeService( url ); }
1381 
1382  void RepoManager::addService( const std::string & alias, const Url& url )
1383  { return _pimpl->addService( alias, url ); }
1384 
1385  void RepoManager::addService( const ServiceInfo & service )
1386  { return _pimpl->addService( service ); }
1387 
1388  void RepoManager::removeService( const std::string & alias )
1389  { return _pimpl->removeService( alias ); }
1390 
1391  void RepoManager::removeService( const ServiceInfo & service )
1392  { return _pimpl->removeService( service ); }
1393 
1395  { return _pimpl->refreshServices( options_r ); }
1396 
1397  void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
1398  { return _pimpl->refreshService( alias, options_r ); }
1399 
1400  void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
1401  { return _pimpl->refreshService( service, options_r ); }
1402 
1403  void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service )
1404  { return _pimpl->modifyService( oldAlias, service ); }
1405 
1407  { return _pimpl->refreshGeoIPData( urls ); }
1408 
1410 
1411  std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
1412  { return str << *obj._pimpl; }
1413 
1415 } // 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
refresh is delayed due to settings
Definition: refresh.h:43
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
Namespace intended to collect all environment variables we use.
Definition: Env.h:22
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:279
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:274
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
repository not changed
Definition: refresh.h:42
String related utilities and Regular expression matching.
Impl(RepoManagerOptions &&opt)
Definition: RepoManager.cc:188
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:201
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
refresh is needed
Definition: refresh.h:41
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 setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:768
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...
std::ostream & operator<<(std::ostream &str, const DeltaCandidates &obj)
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
Temporarily disable MediaChangeReport Sometimes helpful to suppress interactive messages connected to...
zypp::Url Url
Definition: url.h:15
#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:266
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy, OPT_PROGRESS)
#define OUTS(V)
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)
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition: expected.h:367
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:285
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.