libzypp  17.36.1
repomanager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 
10 #include "repomanager.h"
12 
13 #include <solv/solvversion.h>
14 
15 #include <zypp-core/AutoDispose.h>
16 #include <zypp-core/base/Regex.h>
17 #include <zypp-core/fs/PathInfo.h>
18 #include <zypp-core/zyppng/pipelines/MTry>
19 #include <zypp-core/zyppng/pipelines/Transform>
20 #include <zypp-core/zyppng/ui/ProgressObserver>
22 #include <zypp/HistoryLog.h>
23 #include <zypp/ZConfig.h>
24 #include <zypp/ZYppCallbacks.h>
25 #include <zypp/base/LogTools.h>
28 #include <zypp/sat/Pool.h>
30 #include <zypp/repo/ServiceType.h>
32 
33 #include <zypp/ng/reporthelper.h>
34 #include <zypp/ng/repo/refresh.h>
38 
39 #include <fstream>
40 #include <utility>
41 
42 #undef ZYPP_BASE_LOGGER_LOGGROUP
43 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
44 
46  bool IGotIt(); // in readonly-mode
47 }
48 
49 
50 namespace zyppng
51 {
52  namespace env
53  {
56  {
57  const char * env = getenv("ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
58  return( env && zypp::str::strToBool( env, true ) );
59  }
60  } // namespace env
61 
62  namespace {
68  inline void cleanupNonRepoMetadataFolders( const zypp::Pathname & cachePath_r,
69  const zypp::Pathname & defaultCachePath_r,
70  const std::list<std::string> & repoEscAliases_r )
71  {
72  if ( cachePath_r != defaultCachePath_r )
73  return;
74 
75  std::list<std::string> entries;
76  if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
77  {
78  entries.sort();
79  std::set<std::string> oldfiles;
80  set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
81  std::inserter( oldfiles, oldfiles.end() ) );
82 
83  // bsc#1178966: Files or symlinks here have been created by the user
84  // for whatever purpose. It's our cache, so we purge them now before
85  // they may later conflict with directories we need.
86  zypp::PathInfo pi;
87  for ( const std::string & old : oldfiles )
88  {
89  if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
90  continue;
91  pi( cachePath_r/old );
92  if ( pi.isDir() )
94  else
96  }
97  }
98  }
99  } // namespace
100 
102  {
103  switch ( obj ) {
104 #define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
106  OUTS( RefreshForced );
108 #undef OUTS
109  }
110  return str;
111  }
112 
113  std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::RefreshCheckStatus obj )
114  {
115  switch ( obj ) {
116 #define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
117  OUTS( REFRESH_NEEDED );
120 #undef OUTS
121  }
122  return str;
123  }
124 
125  std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::CacheBuildPolicy obj )
126  {
127  switch ( obj ) {
128 #define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
129  OUTS( BuildIfNeeded );
130  OUTS( BuildForced );
131 #undef OUTS
132  }
133  return str;
134  }
135 
136 
137  std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
138  {
139  std::string filename( alias_r );
140  // replace slashes with underscores
141  zypp::str::replaceAll( filename, "/", "_" );
142 
143  filename = zypp::Pathname(filename).extend("."+stem_r).asString();
144  MIL << "generating filename for " << stem_r << " [" << alias_r << "] : '" << filename << "'" << std::endl;
145  return filename;
146  }
147 
149  {
150  // skip repositories meant for other distros than specified
151  if (!targetDistro.empty()
152  && !repo.targetDistribution().empty()
153  && repo.targetDistribution() != targetDistro)
154  {
155  MIL
156  << "Skipping repository meant for '" << repo.targetDistribution()
157  << "' distribution (current distro is '"
158  << targetDistro << "')." << std::endl;
159 
160  return true;
161  }
162 
163  repos.push_back(repo);
164  return true;
165  }
166 
168  {
169  try {
170  MIL << "repo file: " << file << std::endl;
171  RepoCollector collector;
172  zypp::parser::RepoFileReader parser( file, std::bind( &RepoCollector::collect, &collector, std::placeholders::_1 ) );
173  return expected<std::list<RepoInfo>>::success( std::move(collector.repos) );
174  } catch ( ... ) {
176  }
177  }
178 
188  template <typename ZContextRef>
189  std::list<RepoInfo> repositories_in_dir( ZContextRef zyppContext, const zypp::Pathname &dir )
190  {
191  MIL << "directory " << dir << std::endl;
192  std::list<RepoInfo> repos;
193  bool nonroot( geteuid() != 0 );
194  if ( nonroot && ! zypp::PathInfo(dir).userMayRX() )
195  {
196  JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo directory '%1%': Permission denied")) % dir );
197  }
198  else
199  {
200  std::list<zypp::Pathname> entries;
201  if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
202  {
203  // TranslatorExplanation '%s' is a pathname
204  ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
205  }
206 
207  zypp::str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
208  for ( std::list<zypp::Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
209  {
210  if ( zypp::str::regex_match(it->extension(), allowedRepoExt) )
211  {
212  if ( nonroot && ! zypp::PathInfo(*it).userMayR() )
213  {
214  JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo file '%1%': Permission denied")) % *it );
215  }
216  else
217  {
218  const std::list<RepoInfo> tmp( repositories_in_file( *it ).unwrap() );
219  repos.insert( repos.end(), tmp.begin(), tmp.end() );
220  }
221  }
222  }
223  }
224  return repos;
225  }
226 
228  {
229  if ( info.baseUrlsEmpty() )
231  return expected<void>::success();
232  }
233 
234  bool autoPruneInDir(const zypp::Pathname &path_r)
235  { return not zypp::PathInfo(path_r/".no_auto_prune").isExist(); }
236 
237 
238  template <typename ZyppContextRefType>
240  : _zyppContext( std::move(zyppCtx) )
241  , _options( std::move(opt) )
242  , _pluginRepoverification( _options.pluginsPath / "repoverification",
243  _options.rootDir)
244  {
245 
246  }
247 
248  template <typename ZyppContextRefType>
250  {
251  // trigger appdata refresh if some repos change
252  if ( ( _reposDirty || env::ZYPP_PLUGIN_APPDATA_FORCE_COLLECT() )
253  && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
254  {
255  try {
256  std::list<zypp::Pathname> entries;
257  zypp::filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
258  if ( ! entries.empty() )
259  {
261  cmd.push_back( "<" ); // discard stdin
262  cmd.push_back( ">" ); // discard stdout
263  cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
264  for ( const auto & rinfo : repos() )
265  {
266  if ( ! rinfo.enabled() )
267  continue;
268  cmd.push_back( "-R" );
269  cmd.push_back( rinfo.alias() );
270  cmd.push_back( "-t" );
271  cmd.push_back( rinfo.type().asString() );
272  cmd.push_back( "-p" );
273  cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache
274  }
275 
276  for_( it, entries.begin(), entries.end() )
277  {
278  zypp::PathInfo pi( *it );
279  //DBG << "/tmp/xx ->" << pi << endl;
280  if ( pi.isFile() && pi.userMayRX() )
281  {
282  // trigger plugin
283  cmd[2] = pi.asString(); // [2] - PROGRAM
285  }
286  }
287  }
288  }
289  catch (...) {} // no throw in dtor
290  }
291  }
292 
293  template<typename ZyppContextRefType>
295  {
296  using namespace zyppng::operators;
297  return
298  init_knownServices()
299  | and_then( [this](){ return init_knownRepositories(); } );
300  }
301 
302  template<typename ZyppContextRefType>
304  {
305  return _options;
306  }
307 
308  template <typename ZyppContextRefType>
310  {
311  try {
312  using namespace zyppng::operators;
313 
314  // ATTENTION when making this pipeline async
315  // consider moving it into a workflow object
316  // this var is caputured by ref to modify it from
317  // inside the pipeline, which would break.
318  zypp::Pathname mediarootpath;
319 
320  return rawcache_path_for_repoinfo( options, info )
321  | and_then( [&]( zypp::Pathname mrPath ) {
322  mediarootpath = std::move(mrPath);
323  return rawproductdata_path_for_repoinfo( options, info );
324  })
325  | and_then( [&]( zypp::Pathname productdatapath ) {
326  zypp::repo::RepoType repokind = info.type();
327  // If unknown, probe the local metadata
328  if ( repokind == zypp::repo::RepoType::NONE )
329  repokind = probeCache( productdatapath );
330 
331  // NOTE: The calling code expects an empty RepoStatus being returned
332  // if the metadata cache is empty. So additional components like the
333  // RepoInfos status are joined after the switch IFF the status is not
334  // empty.huhu
335  RepoStatus status;
336  switch ( repokind.toEnum() )
337  {
339  status = RepoStatus( productdatapath/"repodata/repomd.xml");
340  if ( info.requireStatusWithMediaFile() )
341  status = status && RepoStatus( mediarootpath/"media.1/media" );
342  break;
343 
345  status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" );
346  break;
347 
349  // Dir status at last refresh. Plaindir uses the cookiefile as pseudo metadata index file.
350  // It gets touched if the refresh check finds the data being up-to-date. That's why we use
351  // the files mtime as timestamp (like the RepoStatus ctor in the other cases above).
352  status = RepoStatus::fromCookieFileUseMtime( productdatapath/"cookie" );
353  break;
354 
356  // Return default RepoStatus in case of RepoType::NONE
357  // indicating it should be created?
358  // ZYPP_THROW(RepoUnknownTypeException());
359  break;
360  }
361 
362  if ( ! status.empty() )
363  status = status && RepoStatus( info );
364 
365  return expected<RepoStatus>::success(status);
366  });
367  } catch (...) {
369  }
370  }
371 
372  template <typename ZyppContextRefType>
374  {
375  return metadataStatus( info, _options );
376  }
377 
378  template <typename ZyppContextRefType>
379  expected<void> RepoManager<ZyppContextRefType>::cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress )
380  {
381  try {
382 
383  ProgressObserver::setup( myProgress, _("Cleaning metadata"), 100 );
384  ProgressObserver::start( myProgress );
385  zypp::filesystem::recursive_rmdir( _zyppContext->config().geoipCachePath() );
386  ProgressObserver::setCurrent ( myProgress, 50 );
388  ProgressObserver::finish ( myProgress );
389 
390  } catch ( ... ) {
391  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
393  }
394  return expected<void>::success();
395  }
396 
397  template <typename ZyppContextRefType>
398  expected<void> RepoManager<ZyppContextRefType>::cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress, bool isAutoClean )
399  {
400  try {
401  ProgressObserver::setup( myProgress, _("Cleaning packages"), 100 );
402  ProgressObserver::start( myProgress );
403 
404  // bsc#1204956: Tweak to prevent auto pruning package caches
406  if ( not isAutoClean || autoPruneInDir( rpc.dirname() ) )
408 
409  ProgressObserver::finish ( myProgress );
410 
411  } catch (...) {
412  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
414  }
415 
416  return expected<void>::success();
417  }
418 
424  template <typename ZyppContextRefType>
426  {
427  MIL << "going to probe the cached repo at " << path_r << std::endl;
428 
430 
431  if ( zypp::PathInfo(path_r/"/repodata/repomd.xml").isFile() )
432  { ret = zypp::repo::RepoType::RPMMD; }
433  else if ( zypp::PathInfo(path_r/"/content").isFile() )
434  { ret = zypp::repo::RepoType::YAST2; }
435  else if ( zypp::PathInfo(path_r/"/cookie").isFile() )
437 
438  MIL << "Probed cached type " << ret << " at " << path_r << std::endl;
439  return ret;
440  }
441 
442  template <typename ZyppContextRefType>
444  {
445  try {
446  MIL << "Going to clean up garbage in cache dirs" << std::endl;
447 
448  std::list<zypp::Pathname> cachedirs;
449  cachedirs.push_back(_options.repoRawCachePath);
450  cachedirs.push_back(_options.repoPackagesCachePath);
451  cachedirs.push_back(_options.repoSolvCachePath);
452 
453  ProgressObserver::setup( myProgress, _("Cleaning up cache dirs"), cachedirs.size() );
454  ProgressObserver::start( myProgress );
455 
456  for( const auto &dir : cachedirs )
457  {
458  // increase progress on end of every iteration
459  zypp_defer {
460  ProgressObserver::increase( myProgress );
461  };
462 
463  if ( zypp::PathInfo(dir).isExist() )
464  {
465  std::list<zypp::Pathname> entries;
466  if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
467  // TranslatorExplanation '%s' is a pathname
468  ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
469 
470  if ( !entries.size() )
471  continue;
472 
473  auto dirProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Format( _("Cleaning up directory: %1%") ) % dir, entries.size() );
474  for( const auto &subdir : entries )
475  {
476  // if it does not belong known repo, make it disappear
477  bool found = false;
478  for_( r, repoBegin(), repoEnd() )
479  if ( subdir.basename() == r->escaped_alias() )
480  { found = true; break; }
481 
482  if ( ! found && ( zypp::Date::now()-zypp::PathInfo(subdir).mtime() > zypp::Date::day ) )
484 
485  ProgressObserver::increase( dirProgress );
486  }
487  ProgressObserver::finish( dirProgress );
488  }
489  }
490  } catch (...) {
491  // will finish all subprogress children
492  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
494  }
495  ProgressObserver::finish ( myProgress );
496  return expected<void>::success();
497  }
498 
499  template <typename ZyppContextRefType>
500  expected<void> RepoManager<ZyppContextRefType>::cleanCache(const RepoInfo &info, ProgressObserverRef myProgress )
501  {
502  try {
503  ProgressObserver::setup( myProgress, _("Cleaning cache"), 100 );
504  ProgressObserver::start( myProgress );
505 
506  MIL << "Removing raw metadata cache for " << info.alias() << std::endl;
508 
509  ProgressObserver::finish( myProgress );
510  return expected<void>::success();
511 
512  } catch (...) {
513  // will finish all subprogress children
514  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
516  }
517  }
518 
519  template <typename ZyppContextRefType>
520  expected<void> RepoManager<ZyppContextRefType>::loadFromCache( const RepoInfo & info, ProgressObserverRef myProgress )
521  {
522  using namespace zyppng::operators;
523  return zyppng::mtry( [this, info, myProgress](){
524  ProgressObserver::setup( myProgress, _("Loading from cache"), 3 );
525  ProgressObserver::start( myProgress );
526 
527  assert_alias(info).unwrap();
528  zypp::Pathname solvfile = solv_path_for_repoinfo(_options, info).unwrap() / "solv";
529 
530  if ( ! zypp::PathInfo(solvfile).isExist() )
532 
533  _zyppContext->satPool().reposErase( info.alias() );
534 
535  ProgressObserver::increase ( myProgress );
536 
537  zypp::Repository repo = _zyppContext->satPool().addRepoSolv( solvfile, info );
538 
539  ProgressObserver::increase ( myProgress );
540 
541  // test toolversion in order to rebuild solv file in case
542  // it was written by a different libsolv-tool parser.
543  const std::string & toolversion( zypp::sat::LookupRepoAttr( zypp::sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
544  if ( toolversion != LIBSOLV_TOOLVERSION ) {
545  repo.eraseFromPool();
546  ZYPP_THROW(zypp::Exception(zypp::str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
547  }
548  })
549  | or_else( [this, info, myProgress]( std::exception_ptr exp ) {
550  ZYPP_CAUGHT( exp );
551  MIL << "Try to handle exception by rebuilding the solv-file" << std::endl;
552  return cleanCache( info, ProgressObserver::makeSubTask( myProgress ) )
553  | and_then([this, info, myProgress]{
554  return buildCache ( info, zypp::RepoManagerFlags::BuildIfNeeded, ProgressObserver::makeSubTask( myProgress ) );
555  })
556  | and_then( mtry([this, info = info]{
557  _zyppContext->satPool().addRepoSolv( solv_path_for_repoinfo(_options, info).unwrap() / "solv", info );
558  }));
559  })
560  | and_then([myProgress]{
561  ProgressObserver::finish ( myProgress );
562  return expected<void>::success();
563  })
564  | or_else([myProgress]( auto ex ){
565  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
566  return expected<void>::error(ex);
567  })
568  ;
569  }
570 
571  template <typename ZyppContextRefType>
573  {
574  try {
575  auto tosave = info;
576 
577  // assert the directory exists
578  zypp::filesystem::assert_dir(_options.knownReposPath);
579 
580  zypp::Pathname repofile = generateNonExistingName(
581  _options.knownReposPath, generateFilename(tosave));
582  // now we have a filename that does not exists
583  MIL << "Saving repo in " << repofile << std::endl;
584 
585  std::ofstream file(repofile.c_str());
586  if (!file)
587  {
588  // TranslatorExplanation '%s' is a filename
589  ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
590  }
591 
592  tosave.dumpAsIniOn(file);
593  tosave.setFilepath(repofile);
594  tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ).unwrap() );
595  tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ).unwrap() );
596  reposManip().insert(tosave);
597 
598  // check for credentials in Urls
599  zypp::UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
600 
601  zypp::HistoryLog(_options.rootDir).addRepository(tosave);
602 
603  // return the new repoinfo
604  return expected<RepoInfo>::success( tosave );
605 
606  } catch (...) {
608  }
609  }
610 
611  template <typename ZyppContextRefType>
612  expected<void> RepoManager<ZyppContextRefType>::removeRepository( const RepoInfo & info, ProgressObserverRef myProgress )
613  {
614  try {
615  ProgressObserver::setup( myProgress, zypp::str::form(_("Removing repository '%s'"), info.label().c_str()), 1 );
616  ProgressObserver::start( myProgress );
617 
618  MIL << "Going to delete repo " << info.alias() << std::endl;
619 
620  for( const auto &repo : repos() )
621  {
622  // they can be the same only if the provided is empty, that means
623  // the provided repo has no alias
624  // then skip
625  if ( (!info.alias().empty()) && ( info.alias() != repo.alias() ) )
626  continue;
627 
628  // TODO match by url
629 
630  // we have a matching repository, now we need to know
631  // where it does come from.
632  RepoInfo todelete = repo;
633  if (todelete.filepath().empty())
634  {
635  ZYPP_THROW(zypp::repo::RepoException( todelete, _("Can't figure out where the repo is stored.") ));
636  }
637  else
638  {
639  // figure how many repos are there in the file:
640  std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath()).unwrap();
641  if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
642  ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
643  {
644  // easy: file does not exist, contains no or only the repo to delete: delete the file
645  int ret = zypp::filesystem::unlink( todelete.filepath() );
646  if ( ! ( ret == 0 || ret == ENOENT ) )
647  {
648  // TranslatorExplanation '%s' is a filename
649  ZYPP_THROW(zypp::repo::RepoException( todelete, zypp::str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
650  }
651  MIL << todelete.alias() << " successfully deleted." << std::endl;
652  }
653  else
654  {
655  // there are more repos in the same file
656  // write them back except the deleted one.
657  //TmpFile tmp;
658  //std::ofstream file(tmp.path().c_str());
659 
660  // assert the directory exists
662 
663  std::ofstream file(todelete.filepath().c_str());
664  if (!file)
665  {
666  // TranslatorExplanation '%s' is a filename
667  ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
668  }
669  for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
670  fit != filerepos.end();
671  ++fit )
672  {
673  if ( (*fit).alias() != todelete.alias() )
674  (*fit).dumpAsIniOn(file);
675  }
676  }
677 
678  // now delete it from cache
679  if ( isCached(todelete) )
680  cleanCache( todelete, ProgressObserver::makeSubTask( myProgress, 0.2 )).unwrap();
681  // now delete metadata (#301037)
682  cleanMetadata( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 )).unwrap();
683  cleanPackages( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 ), true/*isAutoClean*/ ).unwrap();
684  reposManip().erase(todelete);
685  MIL << todelete.alias() << " successfully deleted." << std::endl;
686  zypp::HistoryLog(_options.rootDir).removeRepository(todelete);
687 
688  ProgressObserver::finish(myProgress);
689  return expected<void>::success();
690  } // else filepath is empty
691  }
692  // should not be reached on a sucess workflow
694  } catch (...) {
695  ProgressObserver::finish( myProgress, ProgressObserver::Error );
696  return expected<void>::error( std::current_exception () );
697  }
698  }
699 
700  template <typename ZyppContextRefType>
701  expected<RepoInfo> RepoManager<ZyppContextRefType>::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, ProgressObserverRef myProgress )
702  {
703  try {
704 
705  ProgressObserver::setup( myProgress, _("Modifying repository"), 5 );
706  ProgressObserver::start( myProgress );
707 
708  RepoInfo toedit = getRepositoryInfo(alias).unwrap();
709  RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
710 
711  // check if the new alias already exists when renaming the repo
712  if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
713  {
715  }
716 
717  if (toedit.filepath().empty())
718  {
719  ZYPP_THROW(zypp::repo::RepoException( toedit, _("Can't figure out where the repo is stored.") ));
720  }
721  else
722  {
723  ProgressObserver::increase( myProgress );
724  // figure how many repos are there in the file:
725  std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath()).unwrap();
726 
727  // there are more repos in the same file
728  // write them back except the deleted one.
729  //TmpFile tmp;
730  //std::ofstream file(tmp.path().c_str());
731 
732  // assert the directory exists
734 
735  std::ofstream file(toedit.filepath().c_str());
736  if (!file)
737  {
738  // TranslatorExplanation '%s' is a filename
739  ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
740  }
741  for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
742  fit != filerepos.end();
743  ++fit )
744  {
745  // if the alias is different, dump the original
746  // if it is the same, dump the provided one
747  if ( (*fit).alias() != toedit.alias() )
748  (*fit).dumpAsIniOn(file);
749  else
750  newinfo.dumpAsIniOn(file);
751  }
752 
753  ProgressObserver::increase( myProgress );
754 
755  if ( toedit.enabled() && !newinfo.enabled() )
756  {
757  // On the fly remove solv.idx files for bash completion if a repo gets disabled.
758  const zypp::Pathname solvidx = solv_path_for_repoinfo(_options, newinfo).unwrap()/"solv.idx";
759  if ( zypp::PathInfo(solvidx).isExist() )
760  zypp::filesystem::unlink( solvidx );
761  }
762 
763  newinfo.setFilepath(toedit.filepath());
764  newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ).unwrap() );
765  newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ).unwrap() );
766 
767  ProgressObserver::increase( myProgress );
768 
769  reposManip().erase(toedit);
770  reposManip().insert(newinfo);
771 
772  ProgressObserver::increase( myProgress );
773 
774  // check for credentials in Urls
775  zypp::UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
776  zypp::HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
777  MIL << "repo " << alias << " modified" << std::endl;
778 
779  ProgressObserver::finish ( myProgress );
780  return expected<RepoInfo>::success( newinfo );
781  }
782 
783  } catch ( ... ) {
784  ProgressObserver::finish ( myProgress, ProgressObserver::Error );
786  }
787  }
788 
789  template <typename ZyppContextRefType>
791  {
792  try {
793  RepoConstIterator it( findAlias( alias, repos() ) );
794  if ( it != repos().end() )
795  return make_expected_success(*it);
796  RepoInfo info;
797  info.setAlias( alias );
799  } catch ( ... ) {
800  return expected<RepoInfo>::error( std::current_exception () );
801  }
802  }
803 
804 
805  template <typename ZyppContextRefType>
807  {
808  try {
809 
810  for_( it, repoBegin(), repoEnd() )
811  {
812  for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
813  {
814  if ( (*urlit).asString(urlview) == url.asString(urlview) )
815  return make_expected_success(*it);
816  }
817  }
818  RepoInfo info;
819  info.setBaseUrl( url );
821 
822  } catch ( ... ) {
823  return expected<RepoInfo>::error( std::current_exception () );
824  }
825  }
826 
827  template<typename ZyppContextRefType>
829  {
830  using namespace zyppng::operators;
831  return joinPipeline( _zyppContext,
833  | [this, info](auto) { return zyppng::repo::RefreshContext<ZyppContextRefType>::create( _zyppContext, info, shared_this<RepoManager<ZyppContextRefType>>() ); }
834  | and_then( [this, url, policy]( zyppng::repo::RefreshContextRef<ZyppContextRefType> &&refCtx ) {
835  refCtx->setPolicy ( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
836  return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec() )
837  | and_then( [ r = std::move(refCtx) ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), std::move(mediaHandle), nullptr ); } );
838  })
839  );
840  }
841 
842  template<typename ZyppContextRefType>
844  {
845  using namespace zyppng::operators;
846  // helper callback in case the repo type changes on the remote
847  // do NOT capture by reference here, since this is possibly executed async
848  const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
849  // update probed type only for repos in system
850  for( const auto &repo : repos() ) {
851  if ( info.alias() == repo.alias() )
852  {
853  RepoInfo modifiedrepo = repo;
854  modifiedrepo.setType( repokind );
855  // don't modify .repo in refresh.
856  // modifyRepository( info.alias(), modifiedrepo );
857  break;
858  }
859  }
860  };
861 
862  return joinPipeline( _zyppContext,
863  // make sure geoIP data is up 2 date, but ignore errors
865  | [this, info = info](auto) { return zyppng::repo::RefreshContext<ZyppContextRefType>::create( _zyppContext, info, shared_this<RepoManager<ZyppContextRefType>>()); }
866  | and_then( [policy, myProgress, cb = updateProbedType]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
867  refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
868  // in case probe detects a different repokind, update our internal repos
870 
871  return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), myProgress );
872  })
873  | and_then([rMgr = shared_this<RepoManager<ZyppContextRefType>>()]( repo::RefreshContextRef<ZyppContextRefType> ctx ) {
874 
875  if ( ! isTmpRepo( ctx->repoInfo() ) )
876  rMgr->reposManip(); // remember to trigger appdata refresh
877 
878  return expected<void>::success ();
879  }));
880  }
881 
882  template<typename ZyppContextRefType>
883  std::vector<std::pair<RepoInfo, expected<void>>> RepoManager<ZyppContextRefType>::refreshMetadata( std::vector<RepoInfo> infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress )
884  {
885  using namespace zyppng::operators;
886 
887  ProgressObserver::setup( myProgress, "Refreshing repositories" , 1 );
888 
889  auto r = std::move(infos)
890  | transform( [this, policy, myProgress]( const RepoInfo &info ) {
891 
892  auto subProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Str() << _("Refreshing Repository: ") << info.alias(), 3 );
893 
894  // helper callback in case the repo type changes on the remote
895  // do NOT capture by reference here, since this is possibly executed async
896  const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
897  // update probed type only for repos in system
898  for( const auto &repo : repos() ) {
899  if ( info.alias() == repo.alias() )
900  {
901  RepoInfo modifiedrepo = repo;
902  modifiedrepo.setType( repokind );
903  // don't modify .repo in refresh.
904  // modifyRepository( info.alias(), modifiedrepo );
905  break;
906  }
907  }
908  };
909 
910  auto sharedThis = shared_this<RepoManager<ZyppContextRefType>>();
911 
912  return
913  // make sure geoIP data is up 2 date, but ignore errors
915  | [sharedThis, info = info](auto) { return zyppng::repo::RefreshContext<ZyppContextRefType>::create( sharedThis->_zyppContext, info, sharedThis); }
916  | inspect( incProgress( subProgress ) )
917  | and_then( [policy, subProgress, cb = updateProbedType]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
918  refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
919  // in case probe detects a different repokind, update our internal repos
921 
922  return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), ProgressObserver::makeSubTask( subProgress ) );
923  })
924  | inspect( incProgress( subProgress ) )
925  | and_then([subProgress]( repo::RefreshContextRef<ZyppContextRefType> ctx ) {
926 
927  if ( ! isTmpRepo( ctx->repoInfo() ) )
928  ctx->repoManager()->reposManip(); // remember to trigger appdata refresh
929 
930  return zyppng::RepoManagerWorkflow::buildCache ( std::move(ctx), CacheBuildPolicy::BuildIfNeeded, ProgressObserver::makeSubTask( subProgress ) );
931  })
932  | inspect( incProgress( subProgress ) )
933  | [ info = info, subProgress ]( expected<repo::RefreshContextRef<ZyppContextRefType>> result ) {
934  if ( result ) {
935  ProgressObserver::finish( subProgress, ProgressObserver::Success );
936  return std::make_pair(info, expected<void>::success() );
937  } else {
938  ProgressObserver::finish( subProgress, ProgressObserver::Error );
939  return std::make_pair(info, expected<void>::error( result.error() ) );
940  }
941  };
942  }
943  | [myProgress]( auto res ) {
944  ProgressObserver::finish( myProgress, ProgressObserver::Success );
945  return res;
946  }
947  );
948 
949  return joinPipeline( _zyppContext, r );
950  }
951 
958  template<typename ZyppContextRefType>
960  {
961  using namespace zyppng::operators;
962  return joinPipeline( _zyppContext,
964  | [this, url=url](auto) { return _zyppContext->provider()->prepareMedia( url, zyppng::ProvideMediaSpec() ); }
965  | and_then( [this, path = path]( auto mediaHandle ) {
966  return RepoManagerWorkflow::probeRepoType( _zyppContext, std::forward<decltype(mediaHandle)>(mediaHandle), path );
967  }));
968  }
969 
970  template<typename ZyppContextRefType>
971  expected<void> RepoManager<ZyppContextRefType>::buildCache( const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress )
972  {
973  using namespace zyppng::operators;
974  return joinPipeline( _zyppContext,
976  | and_then( [policy, myProgress]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
977  return zyppng::RepoManagerWorkflow::buildCache ( std::move(refCtx), policy, myProgress );
978  })
979  | and_then([]( auto ){ return expected<void>::success(); })
980  );
981  }
982 
983  template<typename ZyppContextRefType>
985  {
986  return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this<RepoManager<ZyppContextRefType>>(), info, std::move(myProgress) ) );
987  }
988 
989  template<typename ZyppContextRefType>
991  {
992  using namespace zyppng::operators;
993  return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepositories( shared_this<RepoManager<ZyppContextRefType>>(), url, std::move(myProgress)));
994  }
995 
996  template <typename ZyppContextRefType>
998  {
1000  }
1001 
1002  template <typename ZyppContextRefType>
1004  {
1005  try {
1006 
1007  assert_alias( service ).unwrap();
1008 
1009  // check if service already exists
1010  if ( hasService( service.alias() ) )
1012 
1013  // Writable ServiceInfo is needed to save the location
1014  // of the .service file. Finaly insert into the service list.
1015  ServiceInfo toSave( service );
1016  saveService( toSave ).unwrap();
1017  _services.insert( toSave );
1018 
1019  // check for credentials in Url
1020  zypp::UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1021 
1022  MIL << "added service " << toSave.alias() << std::endl;
1023 
1024  } catch ( ... ) {
1025  return expected<void>::error( std::current_exception () );
1026  }
1027 
1028  return expected<void>::success();
1029  }
1030 
1031  template<typename ZyppContextRefType>
1033  {
1034  return joinPipeline ( _zyppContext, RepoServicesWorkflow::refreshService( shared_this<RepoManager<ZyppContextRefType>>(), getService( alias ), options_r ) );
1035  }
1036 
1040  template<typename ZyppContextRefType>
1042  {
1043  using namespace zyppng::operators;
1044  // copy the set of services since refreshService
1045  // can eventually invalidate the iterator
1046  ServiceSet servicesCopy( serviceBegin(), serviceEnd() );
1047 
1048  // convert the set into a vector, transform needs a container with push_back support
1049  std::vector<ServiceInfo> servicesVec;
1050  std::copy( std::make_move_iterator(servicesCopy.begin()), std::make_move_iterator(servicesCopy.end()), std::back_inserter(servicesVec));
1051 
1052  return joinPipeline( _zyppContext,
1053  std::move(servicesVec)
1054  | transform( [options_r, this]( ServiceInfo i ){ return RepoServicesWorkflow::refreshService( shared_this<RepoManager<ZyppContextRefType>>(), i, options_r ); } )
1055  | join()
1056  | collect()
1057  );
1058  }
1059 
1061 
1062  template <typename ZyppContextRefType>
1064  {
1065  try {
1066  MIL << "Going to delete service " << alias << std::endl;
1067 
1068  const ServiceInfo & service = getService( alias );
1069 
1070  zypp::Pathname location = service.filepath();
1071  if( location.empty() )
1072  {
1073  ZYPP_THROW(zypp::repo::ServiceException( service, _("Can't figure out where the service is stored.") ));
1074  }
1075 
1076  ServiceSet tmpSet;
1078 
1079  // only one service definition in the file
1080  if ( tmpSet.size() == 1 )
1081  {
1082  if ( zypp::filesystem::unlink(location) != 0 )
1083  {
1084  // TranslatorExplanation '%s' is a filename
1085  ZYPP_THROW(zypp::repo::ServiceException( service, zypp::str::form( _("Can't delete '%s'"), location.c_str() ) ));
1086  }
1087  MIL << alias << " successfully deleted." << std::endl;
1088  }
1089  else
1090  {
1092 
1093  std::ofstream file(location.c_str());
1094  if( !file )
1095  {
1096  // TranslatorExplanation '%s' is a filename
1097  ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), location.c_str() )));
1098  }
1099 
1100  for_(it, tmpSet.begin(), tmpSet.end())
1101  {
1102  if( it->alias() != alias )
1103  it->dumpAsIniOn(file);
1104  }
1105 
1106  MIL << alias << " successfully deleted from file " << location << std::endl;
1107  }
1108 
1109  // now remove all repositories added by this service
1110  RepoCollector rcollector;
1111  getRepositoriesInService( alias,
1112  boost::make_function_output_iterator( std::bind( &RepoCollector::collect, &rcollector, std::placeholders::_1 ) ) );
1113  // cannot do this directly in getRepositoriesInService - would invalidate iterators
1114  for_(rit, rcollector.repos.begin(), rcollector.repos.end())
1115  removeRepository(*rit).unwrap();
1116 
1117  return expected<void>::success();
1118 
1119  } catch ( ... ) {
1120  return expected<void>::error( std::current_exception () );
1121  }
1122  }
1123 
1124  template <typename ZyppContextRefType>
1125  expected<void> RepoManager<ZyppContextRefType>::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
1126  {
1127  try {
1128 
1129  MIL << "Going to modify service " << oldAlias << std::endl;
1130 
1131  // we need a writable copy to link it to the file where
1132  // it is saved if we modify it
1133  ServiceInfo service(newService);
1134 
1135  if ( service.type() == zypp::repo::ServiceType::PLUGIN )
1136  {
1138  }
1139 
1140  const ServiceInfo & oldService = getService(oldAlias);
1141 
1142  zypp::Pathname location = oldService.filepath();
1143  if( location.empty() )
1144  {
1145  ZYPP_THROW(zypp::repo::ServiceException( oldService, _("Can't figure out where the service is stored.") ));
1146  }
1147 
1148  // remember: there may multiple services being defined in one file:
1149  ServiceSet tmpSet;
1151 
1153  std::ofstream file(location.c_str());
1154  for_(it, tmpSet.begin(), tmpSet.end())
1155  {
1156  if( *it != oldAlias )
1157  it->dumpAsIniOn(file);
1158  }
1159  service.dumpAsIniOn(file);
1160  file.close();
1161  service.setFilepath(location);
1162 
1163  _services.erase(oldAlias);
1164  _services.insert(service);
1165  // check for credentials in Urls
1166  zypp::UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
1167 
1168 
1169  // changed properties affecting also repositories
1170  if ( oldAlias != service.alias() // changed alias
1171  || oldService.enabled() != service.enabled() ) // changed enabled status
1172  {
1173  std::vector<RepoInfo> toModify;
1174  getRepositoriesInService(oldAlias, std::back_inserter(toModify));
1175  for_( it, toModify.begin(), toModify.end() )
1176  {
1177  if ( oldService.enabled() != service.enabled() )
1178  {
1179  if ( service.enabled() )
1180  {
1181  // reset to last refreshs state
1182  const auto & last = service.repoStates().find( it->alias() );
1183  if ( last != service.repoStates().end() )
1184  it->setEnabled( last->second.enabled );
1185  }
1186  else
1187  it->setEnabled( false );
1188  }
1189 
1190  if ( oldAlias != service.alias() )
1191  it->setService(service.alias());
1192 
1193  modifyRepository(it->alias(), *it).unwrap();
1194  }
1195  }
1196 
1197  return expected<void>::success();
1198 
1199  } catch ( ... ) {
1200  return expected<void>::error( std::current_exception () );
1201  }
1202 
1204  }
1205 
1206 
1207  template <typename ZyppContextRefType>
1209  {
1210  try {
1211 
1212  zypp::filesystem::assert_dir( _options.knownServicesPath );
1213  zypp::Pathname servfile = generateNonExistingName( _options.knownServicesPath,
1214  generateFilename( service ) );
1215  service.setFilepath( servfile );
1216 
1217  MIL << "saving service in " << servfile << std::endl;
1218 
1219  std::ofstream file( servfile.c_str() );
1220  if ( !file )
1221  {
1222  // TranslatorExplanation '%s' is a filename
1223  ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), servfile.c_str() )));
1224  }
1225  service.dumpAsIniOn( file );
1226  MIL << "done" << std::endl;
1227 
1228  return expected<void>::success();
1229 
1230  } catch ( ... ) {
1231  return expected<void>::error( std::current_exception () );
1232  }
1233  }
1234 
1250  template <typename ZyppContextRefType>
1252  const std::string & basefilename ) const
1253  {
1254  std::string final_filename = basefilename;
1255  int counter = 1;
1256  while ( zypp::PathInfo(dir + final_filename).isExist() )
1257  {
1258  final_filename = basefilename + "_" + zypp::str::numstring(counter);
1259  ++counter;
1260  }
1261  return dir + zypp::Pathname(final_filename);
1262  }
1263 
1264  template <typename ZyppContextRefType>
1266  {
1267  try {
1268  zypp::Pathname productdatapath = rawproductdata_path_for_repoinfo( options, info ).unwrap();
1269 
1270  zypp::repo::RepoType repokind = info.type();
1271  if ( repokind.toEnum() == zypp::repo::RepoType::NONE_e )
1272  // unknown, probe the local metadata
1273  repokind = probeCache( productdatapath );
1274  // if still unknown, just return
1275  if (repokind == zypp::repo::RepoType::NONE_e)
1276  return expected<void>::success();
1277 
1278  zypp::Pathname p;
1279  switch ( repokind.toEnum() )
1280  {
1282  p = zypp::Pathname(productdatapath + "/repodata/repomd.xml");
1283  break;
1284 
1286  p = zypp::Pathname(productdatapath + "/content");
1287  break;
1288 
1290  p = zypp::Pathname(productdatapath + "/cookie");
1291  break;
1292 
1294  default:
1295  break;
1296  }
1297 
1298  // touch the file, ignore error (they are logged anyway)
1300  } catch ( ... ) {
1302  }
1303  return expected<void>::success();
1304  }
1305 
1306  template<typename ZyppContextRefType>
1308  {
1310  }
1311 
1312  template <typename ZyppContextRefType>
1314  {
1315  return touchIndexFile( info, _options );
1316  }
1317 
1318  template <typename ZyppContextRefType>
1320  {
1321  try {
1322  zypp::Pathname dir = _options.knownServicesPath;
1323  std::list<zypp::Pathname> entries;
1324  if (zypp::PathInfo(dir).isExist())
1325  {
1326  if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
1327  {
1328  // TranslatorExplanation '%s' is a pathname
1329  ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
1330  }
1331 
1332  //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
1333  for_(it, entries.begin(), entries.end() )
1334  {
1336  }
1337  }
1338 
1339  zypp::repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services));
1340 
1341  return expected<void>::success();
1342 
1343  } catch ( ... ) {
1344  return expected<void>::error( std::current_exception () );
1345  }
1346 
1347  }
1348 
1349  namespace {
1356  inline void cleanupNonRepoMetadtaFolders( const zypp::Pathname & cachePath_r,
1357  const zypp::Pathname & defaultCachePath_r,
1358  const std::list<std::string> & repoEscAliases_r )
1359  {
1361  return;
1362 
1363  if ( cachePath_r != defaultCachePath_r )
1364  return;
1365 
1366  std::list<std::string> entries;
1367  if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
1368  {
1369  entries.sort();
1370  std::set<std::string> oldfiles;
1371  set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
1372  std::inserter( oldfiles, oldfiles.end() ) );
1373 
1374  // bsc#1178966: Files or symlinks here have been created by the user
1375  // for whatever purpose. It's our cache, so we purge them now before
1376  // they may later conflict with directories we need.
1377  zypp::PathInfo pi;
1378  for ( const std::string & old : oldfiles )
1379  {
1380  if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
1381  continue;
1382  pi( cachePath_r/old );
1383  if ( pi.isDir() )
1385  else
1387  }
1388  }
1389  }
1390  } // namespace
1391 
1392  template <typename ZyppContextRefType>
1394  {
1395  try {
1396 
1397  MIL << "start construct known repos" << std::endl;
1398 
1399  if ( zypp::PathInfo(_options.knownReposPath).isExist() )
1400  {
1401  std::list<std::string> repoEscAliases;
1402  std::list<RepoInfo> orphanedRepos;
1403  for ( RepoInfo & repoInfo : repositories_in_dir( _zyppContext, _options.knownReposPath ) )
1404  {
1405  // set the metadata path for the repo
1406  repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo).unwrap() );
1407  // set the downloaded packages path for the repo
1408  repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo).unwrap() );
1409  // remember it
1410  _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
1411 
1412  // detect orphaned repos belonging to a deleted service
1413  const std::string & serviceAlias( repoInfo.service() );
1414  if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
1415  {
1416  WAR << "Schedule orphaned service repo for deletion: " << repoInfo << std::endl;
1417  orphanedRepos.push_back( repoInfo );
1418  continue; // don't remember it in repoEscAliases
1419  }
1420 
1421  repoEscAliases.push_back(repoInfo.escaped_alias());
1422  }
1423 
1424  // Cleanup orphanded service repos:
1425  if ( ! orphanedRepos.empty() )
1426  {
1427  for ( const auto & repoInfo : orphanedRepos )
1428  {
1429  MIL << "Delete orphaned service repo " << repoInfo.alias() << std::endl;
1430  // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
1431  // %1% = service name
1432  // %2% = repository name
1433  JobReportHelper(_zyppContext).warning( zypp::str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'"))
1434  % repoInfo.service()
1435  % repoInfo.alias() );
1436  try {
1437  removeRepository( repoInfo ).unwrap();
1438  }
1439  catch ( const zypp::Exception & caugth )
1440  {
1442  }
1443  }
1444  }
1445 
1446  // bsc#1210740: Don't cleanup if read-only mode was promised.
1447  if ( not zypp::zypp_readonly_hack::IGotIt() ) {
1448  // delete metadata folders without corresponding repo (e.g. old tmp directories)
1449  //
1450  // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise
1451  // we'd need somemagic file to identify zypp cache directories. Without this
1452  // we may easily remove user data (zypper --pkg-cache-dir . download ...)
1453  repoEscAliases.sort();
1454  cleanupNonRepoMetadtaFolders( _options.repoRawCachePath,
1455  zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoMetadataPath() ),
1456  repoEscAliases );
1457  cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath,
1458  zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoSolvfilesPath() ),
1459  repoEscAliases );
1460  // bsc#1204956: Tweak to prevent auto pruning package caches
1461  if ( autoPruneInDir( _options.repoPackagesCachePath ) )
1462  cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath,
1463  zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoPackagesPath() ),
1464  repoEscAliases );
1465  }
1466  }
1467  MIL << "end construct known repos" << std::endl;
1468 
1469  return expected<void>::success();
1470 
1471  } catch ( ... ) {
1472  return expected<void>::error( std::current_exception () );
1473  }
1474  }
1475 
1476  // explicitely intantiate the template types we want to work with
1477  template class RepoManager<SyncContextRef>;
1478  template class RepoManager<ContextRef>;
1479 } // namespace zyppng
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
Pathname filepath() const
File where this repo was read from.
static const ValueType day
Definition: Date.h:44
void setBaseUrl(Url url)
Clears current base URL list and adds url.
Definition: RepoInfo.cc:556
void loadFromCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Load resolvables into the pool.
Definition: RepoManager.cc:166
Service data.
Definition: ServiceInfo.h:36
std::ostream & dumpAsIniOn(std::ostream &str) const override
Writes ServiceInfo to stream in ".service" format.
Definition: ServiceInfo.cc:176
thrown when it was impossible to match a repository
#define MIL
Definition: Logger.h:100
zypp::RepoStatus RepoStatus
Definition: repomanager.h:37
std::string targetDistro
Definition: repomanager.h:146
bool empty() const
Whether the status is empty (empty checksum)
Definition: RepoStatus.cc:234
Namespace intended to collect all environment variables we use.
Definition: Env.h:22
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:324
#define _(MSG)
Definition: Gettext.h:39
repo::RepoType probe(const Url &url, const Pathname &path) const
Probe repo metadata type.
Definition: RepoManager.cc:172
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:251
Read service data from a .service file.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
Type toEnum() const
Definition: RepoType.h:49
Regular expression.
Definition: Regex.h:94
std::enable_if_t<!std::is_same_v< void, T >, expected< Container< T >, E > > collect(Container< expected< T, E >, CArgs... > &&in)
Definition: expected.h:501
bool warning(std::string msg_r, UserData userData_r=UserData())
send warning text
expected< T, E > inspect(expected< T, E > exp, Function &&f)
Definition: expected.h:531
AsyncOpRef< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
Definition: serviceswf.cc:306
std::string join(TIterator begin, TIterator end, const C_Str &sep_r=" ")
Join strings using separator sep_r (defaults to BLANK).
Definition: String.h:776
void removeService(const std::string &alias)
Removes service specified by its name.
Definition: RepoManager.cc:246
void cleanCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
clean local cache
Definition: RepoManager.cc:160
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > refreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
expected< std::list< RepoInfo > > repositories_in_file(const zypp::Pathname &file)
Reads RepoInfo&#39;s from a repo file.
Definition: repomanager.cc:167
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:175
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy=RefreshIfNeeded)
Checks whether to refresh metadata for specified repository and url.
Definition: RepoManager.cc:128
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
const char * c_str() const
String representation.
Definition: Pathname.h:112
void setAlias(const std::string &alias)
set the repository alias
Definition: RepoInfoBase.cc:94
std::list< RepoInfo > repositories_in_dir(ZContextRef zyppContext, const zypp::Pathname &dir)
List of RepoInfo&#39;s from a directory.
Definition: repomanager.cc:189
String related utilities and Regular expression matching.
void setFilepath(const Pathname &filename)
set the path to the .repo file
bool isTmpRepo(const RepoInfo &info_r)
Whether repo is not under RM control and provides its own methadata paths.
Definition: repomanager.h:55
Definition: Arch.h:363
What is known about a repository.
Definition: RepoInfo.h:71
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition: expected.h:397
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > buildCache(repo::AsyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
Service already exists and some unique attribute can&#39;t be duplicated.
Convenient building of std::string with boost::format.
Definition: String.h:252
void buildCache(const RepoInfo &info, CacheBuildPolicy policy=BuildIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local cache.
Definition: RepoManager.cc:153
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
bool enabled() const
If enabled is false, then this repository must be ignored as if does not exists, except when checking...
repo::ServiceType probeService(const Url &url) const
Probe the type or the service.
Definition: RepoManager.cc:237
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:428
ZyppContextRefType _zyppContext
#define zypp_defer
Definition: AutoDispose.h:293
Url::asString() view options.
Definition: UrlBase.h:40
zypp::RepoManager::RefreshServiceOptions _options
Definition: serviceswf.cc:724
int recursive_rmdir(const Pathname &path)
Like &#39;rm -r DIR&#39;.
Definition: PathInfo.cc:417
~RepoManager()
Dtor.
Definition: RepoManager.cc:84
expected< zypp::Pathname > packagescache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the packages cache path for a repository.
Definition: repomanager.h:195
Extract credentials in Url authority and store them via CredentialManager.
static expected< repo::RefreshContextRef< ZyppContextRefType > > create(ZyppContextRefType zyppContext, zypp::RepoInfo info, RepoManagerRef< ContextRefType > repoManager)
Definition: refresh.cc:31
Repo manager settings.
void cleanCacheDirGarbage(const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove any subdirectories of cache directories which no longer belong to any of known repositories...
Definition: RepoManager.cc:169
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refresh specific service.
Definition: RepoManager.cc:255
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:659
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy=RefreshIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local raw cache.
Definition: RepoManager.cc:137
ResultType or_else(const expected< T, E > &exp, Function &&f)
Definition: expected.h:463
Simple callback to collect the results.
Definition: repomanager.h:134
Container< Ret > transform(Container< Msg, CArgs... > &&val, Transformation &&transformation)
Definition: transform.h:31
void modifyRepository(const std::string &alias, const RepoInfo &newinfo, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Modify repository attributes.
Definition: RepoManager.cc:202
Exp mtry(F &&f, Args &&...args)
Definition: mtry.h:28
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:515
expected< zypp::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...
Definition: repomanager.h:186
static RepoStatus fromCookieFileUseMtime(const Pathname &path)
Reads the status from a cookie file but uses the files mtime.
Definition: RepoStatus.cc:217
void refreshServices(const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refreshes all enabled services.
Definition: RepoManager.cc:252
void cleanPackages(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local package cache.
Definition: RepoManager.cc:147
RepoInfo getRepositoryInfo(const std::string &alias, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Find a matching repository info.
Definition: RepoManager.cc:213
bool collect(const RepoInfo &repo)
Definition: repomanager.cc:148
void removeRepository(const RepoInfo &repo)
Log recently removed repository.
Definition: HistoryLog.cc:301
int touch(const Pathname &path)
Change file&#39;s modification and access times.
Definition: PathInfo.cc:1242
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
Lightweight repository attribute value lookup.
Definition: LookupAttr.h:264
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
thrown when it was impossible to determine one url for this repo.
Definition: RepoException.h:78
const std::string & asString() const
String representation.
Definition: Pathname.h:93
std::string alias() const
unique identifier for this source.
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:286
void addService(const std::string &alias, const Url &url)
Adds a new service by its alias and URL.
Definition: RepoManager.cc:240
auto joinPipeline(ContextRef ctx, AsyncOpRef< T > res)
Definition: context.h:81
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:127
static const SolvAttr repositoryToolVersion
Definition: SolvAttr.h:193
expected< void > assert_alias(const RepoInfo &info)
Definition: repomanager.h:58
creates and provides information about known sources.
Definition: RepoManager.cc:38
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:126
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r prefixed with root_r, unless it is already prefixed.
Definition: Pathname.cc:272
#define WAR
Definition: Logger.h:101
void setMetadataPath(const Pathname &path)
Set the path where the local metadata is stored.
Definition: RepoInfo.cc:575
void setType(const repo::RepoType &t)
set the repository type
Definition: RepoInfo.cc:568
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
Definition: repomanager.cc:55
void addRepository(const RepoInfo &repo)
Log a newly added repository.
Definition: HistoryLog.cc:289
Writing the zypp history fileReference counted signleton for writhing the zypp history file...
Definition: HistoryLog.h:56
RepoInfoList repos
Definition: repomanager.h:145
Read repository data from a .repo file.
void modifyService(const std::string &oldAlias, const ServiceInfo &service)
Modifies service file (rewrites it with new values) and underlying repositories if needed...
Definition: RepoManager.cc:261
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:610
Base Exception for service handling.
std::list< Url > url_set
Definition: RepoInfo.h:108
bool requireStatusWithMediaFile() const
Returns true if this repository requires the media.1/media file to be included in the metadata status...
Definition: RepoInfo.cc:967
RepoSet::const_iterator RepoConstIterator
Definition: repomanager.h:299
std::vector< std::string > Arguments
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:253
std::string numstring(char n, int w=0)
Definition: String.h:289
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:705
static const RepoType NONE
Definition: RepoType.h:33
static expected success(ConsParams &&...params)
Definition: expected.h:115
Url url() const
The service url.
Definition: ServiceInfo.cc:102
zypp::RepoManagerFlags::RefreshServiceOptions RefreshServiceOptions
Definition: repomanager.h:265
void setPackagesPath(const Pathname &path)
set the path where the local packages are stored
Definition: RepoInfo.cc:578
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:51
bool userMayRX() const
Definition: PathInfo.h:358
static const RepoType RPMMD
Definition: RepoType.h:30
bool autoPruneInDir(const zypp::Pathname &path_r)
bsc#1204956: Tweak to prevent auto pruning package caches.
Definition: repomanager.cc:234
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
#define ZYPP_PRIVATE_CONSTR_ARG
Definition: zyppglobal.h:160
AsyncOpRef< expected< void > > refreshGeoIPData(ContextRef ctx, RepoInfo::url_set urls)
static const RepoType YAST2
Definition: RepoType.h:31
bool error(std::string msg_r, UserData userData_r=UserData())
send error text
AsyncOpRef< expected< zypp::repo::RepoType > > probeRepoType(ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional< zypp::Pathname > targetPath)
expected< void > assert_urls(const RepoInfo &info)
Definition: repomanager.cc:227
void addRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds a repository to the list of known repositories.
Definition: RepoManager.cc:178
const RepoStates & repoStates() const
Access the remembered repository states.
Definition: ServiceInfo.cc:164
Base class for Exception.
Definition: Exception.h:146
std::ostream & dumpAsIniOn(std::ostream &str) const override
Write this RepoInfo object into str in a .repo file format.
Definition: RepoInfo.cc:849
Exception for repository handling.
Definition: RepoException.h:37
std::set< ServiceInfo > ServiceSet
ServiceInfo typedefs.
Definition: repomanager.h:293
refresh is delayed due to settings
static Date now()
Return the current time.
Definition: Date.h:78
AsyncOpRef< expected< void > > refreshService(AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
Definition: serviceswf.cc:739
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:429
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
Definition: repomanager.h:99
The repository cache is not built yet so you can&#39;t create the repostories from the cache...
Definition: RepoException.h:65
void eraseFromPool()
Remove this Repository from its Pool.
Definition: Repository.cc:298
std::string targetDistribution() const
Distribution for which is this repository meant.
Definition: RepoInfo.cc:644
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
regex ZYPP_STR_REGEX regex ZYPP_STR_REGEX
Definition: Regex.h:70
void removeRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove the best matching repository from known repos list.
Definition: RepoManager.cc:195
AsyncOpRef< expected< repo::RefreshCheckStatus > > checkIfToRefreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
RefreshCheckStatus
Possibly return state of RepoManager::checkIfToRefreshMetadata function.
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition: expected.h:423
static const RepoType RPMPLAINDIR
Definition: RepoType.h:32
static const std::string & systemRepoAlias()
Reserved system repository alias .
Definition: Repository.cc:38
expected< zypp::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.
Definition: repomanager.h:172
RepoStatus metadataStatus(const RepoInfo &info) const
Status of local metadata.
Definition: RepoManager.cc:125
Track changing files or directories.
Definition: RepoStatus.h:40
The RepoManager class Provides knowledge and methods to maintain repo settings and metadata for a giv...
Definition: repomanager.h:247
AsyncOpRef< expected< RepoInfo > > addRepository(AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress)
Repository already exists and some unique attribute can&#39;t be duplicated.
std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
Generate a related filename from a repo/service infos alias.
Definition: repomanager.cc:137
std::string & replaceAll(std::string &str_r, const std::string &from_r, const std::string &to_r)
Replace all occurrences of from_r with to_r in str_r (inplace).
Definition: String.cc:331
void modifyRepository(const RepoInfo &oldrepo, const RepoInfo &newrepo)
Log certain modifications to a repository.
Definition: HistoryLog.cc:312
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition: Exception.h:436
std::ostream & operator<<(std::ostream &str, zypp::RepoManagerFlags::RawMetadataRefreshPolicy obj)
Definition: repomanager.cc:101
AsyncOpRef< expected< void > > addRepositories(AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress)
void refreshGeoIp(const RepoInfo::url_set &urls)
Definition: RepoManager.cc:264
repo::ServiceType type() const
Service type.
Definition: ServiceInfo.cc:111
std::string label() const
Label for use in messages for the user interface.
url_set baseUrls() const
The complete set of repository urls.
Definition: RepoInfo.cc:632
repo::RepoType type() const
Type of repository,.
Definition: RepoInfo.cc:605
bool collect(const Url &url_r)
Remember credentials stored in URL authority leaving the password in url_r.
auto incProgress(ProgressObserverRef progressObserver, double progrIncrease=1.0, std::optional< std::string > newStr={})
void cleanMetadata(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local metadata.
Definition: RepoManager.cc:144
Functor collecting ServiceInfos into a ServiceSet.
Definition: repomanager.h:215
#define OUTS(V)
Url manipulation class.
Definition: Url.h:92
expected< zypp::Pathname > solv_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the solv cache path for a repository.
Definition: repomanager.h:205
Repository type enumeration.
Definition: RepoType.h:28
void addRepositories(const Url &url, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds repositores from a repo file to the list of known repositories.
Definition: RepoManager.cc:192