libzypp  16.20.4
RepoManager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <cstdlib>
14 #include <iostream>
15 #include <fstream>
16 #include <sstream>
17 #include <list>
18 #include <map>
19 #include <algorithm>
20 
21 #include <solv/solvversion.h>
22 
23 #include "zypp/base/InputStream.h"
24 #include "zypp/base/LogTools.h"
25 #include "zypp/base/Gettext.h"
27 #include "zypp/base/Function.h"
28 #include "zypp/base/Regex.h"
29 #include "zypp/PathInfo.h"
30 #include "zypp/TmpPath.h"
31 
32 #include "zypp/ServiceInfo.h"
34 #include "zypp/RepoManager.h"
35 
38 #include "zypp/MediaSetAccess.h"
39 #include "zypp/ExternalProgram.h"
40 #include "zypp/ManagedFile.h"
41 
44 #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"
56 
57 using std::endl;
58 using std::string;
59 using namespace zypp::repo;
60 
61 #define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc()
62 
64 namespace zypp
65 {
66 
68  namespace env
69  {
72  {
73  const char * env = getenv("ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
74  return( env && str::strToBool( env, true ) );
75  }
76  } // namespace env
78 
80  namespace
81  {
103  class UrlCredentialExtractor
104  {
105  public:
106  UrlCredentialExtractor( Pathname & root_r )
107  : _root( root_r )
108  {}
109 
110  ~UrlCredentialExtractor()
111  { if ( _cmPtr ) _cmPtr->save(); }
112 
114  bool collect( const Url & url_r )
115  {
116  bool ret = url_r.hasCredentialsInAuthority();
117  if ( ret )
118  {
119  if ( !_cmPtr ) _cmPtr.reset( new media::CredentialManager( _root ) );
120  _cmPtr->addUserCred( url_r );
121  }
122  return ret;
123  }
125  template<class TContainer>
126  bool collect( const TContainer & urls_r )
127  { bool ret = false; for ( const Url & url : urls_r ) { if ( collect( url ) && !ret ) ret = true; } return ret; }
128 
130  bool extract( Url & url_r )
131  {
132  bool ret = collect( url_r );
133  if ( ret )
134  url_r.setPassword( std::string() );
135  return ret;
136  }
138  template<class TContainer>
139  bool extract( TContainer & urls_r )
140  { bool ret = false; for ( Url & url : urls_r ) { if ( extract( url ) && !ret ) ret = true; } return ret; }
141 
142  private:
143  const Pathname & _root;
144  scoped_ptr<media::CredentialManager> _cmPtr;
145  };
146  } // namespace
148 
150  namespace
151  {
155  class MediaMounter
156  {
157  public:
159  MediaMounter( const Url & url_r )
160  {
161  media::MediaManager mediamanager;
162  _mid = mediamanager.open( url_r );
163  mediamanager.attach( _mid );
164  }
165 
167  ~MediaMounter()
168  {
169  media::MediaManager mediamanager;
170  mediamanager.release( _mid );
171  mediamanager.close( _mid );
172  }
173 
178  Pathname getPathName( const Pathname & path_r = Pathname() ) const
179  {
180  media::MediaManager mediamanager;
181  return mediamanager.localPath( _mid, path_r );
182  }
183 
184  private:
186  };
188 
190  template <class Iterator>
191  inline bool foundAliasIn( const std::string & alias_r, Iterator begin_r, Iterator end_r )
192  {
193  for_( it, begin_r, end_r )
194  if ( it->alias() == alias_r )
195  return true;
196  return false;
197  }
199  template <class Container>
200  inline bool foundAliasIn( const std::string & alias_r, const Container & cont_r )
201  { return foundAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
202 
204  template <class Iterator>
205  inline Iterator findAlias( const std::string & alias_r, Iterator begin_r, Iterator end_r )
206  {
207  for_( it, begin_r, end_r )
208  if ( it->alias() == alias_r )
209  return it;
210  return end_r;
211  }
213  template <class Container>
214  inline typename Container::iterator findAlias( const std::string & alias_r, Container & cont_r )
215  { return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
217  template <class Container>
218  inline typename Container::const_iterator findAlias( const std::string & alias_r, const Container & cont_r )
219  { return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
220 
221 
223  inline std::string filenameFromAlias( const std::string & alias_r, const std::string & stem_r )
224  {
225  std::string filename( alias_r );
226  // replace slashes with underscores
227  str::replaceAll( filename, "/", "_" );
228 
229  filename = Pathname(filename).extend("."+stem_r).asString();
230  MIL << "generating filename for " << stem_r << " [" << alias_r << "] : '" << filename << "'" << endl;
231  return filename;
232  }
233 
249  struct RepoCollector : private base::NonCopyable
250  {
251  RepoCollector()
252  {}
253 
254  RepoCollector(const std::string & targetDistro_)
255  : targetDistro(targetDistro_)
256  {}
257 
258  bool collect( const RepoInfo &repo )
259  {
260  // skip repositories meant for other distros than specified
261  if (!targetDistro.empty()
262  && !repo.targetDistribution().empty()
263  && repo.targetDistribution() != targetDistro)
264  {
265  MIL
266  << "Skipping repository meant for '" << repo.targetDistribution()
267  << "' distribution (current distro is '"
268  << targetDistro << "')." << endl;
269 
270  return true;
271  }
272 
273  repos.push_back(repo);
274  return true;
275  }
276 
277  RepoInfoList repos;
278  std::string targetDistro;
279  };
281 
287  std::list<RepoInfo> repositories_in_file( const Pathname & file )
288  {
289  MIL << "repo file: " << file << endl;
290  RepoCollector collector;
291  parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) );
292  return std::move(collector.repos);
293  }
294 
296 
305  std::list<RepoInfo> repositories_in_dir( const Pathname &dir )
306  {
307  MIL << "directory " << dir << endl;
308  std::list<RepoInfo> repos;
309  bool nonroot( geteuid() != 0 );
310  if ( nonroot && ! PathInfo(dir).userMayRX() )
311  {
312  JobReport::warning( str::FormatNAC(_("Cannot read repo directory '%1%': Permission denied")) % dir );
313  }
314  else
315  {
316  std::list<Pathname> entries;
317  if ( filesystem::readdir( entries, dir, false ) != 0 )
318  {
319  // TranslatorExplanation '%s' is a pathname
320  ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str())));
321  }
322 
323  str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
324  for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
325  {
326  if ( str::regex_match(it->extension(), allowedRepoExt) )
327  {
328  if ( nonroot && ! PathInfo(*it).userMayR() )
329  {
330  JobReport::warning( str::FormatNAC(_("Cannot read repo file '%1%': Permission denied")) % *it );
331  }
332  else
333  {
334  const std::list<RepoInfo> & tmp( repositories_in_file( *it ) );
335  repos.insert( repos.end(), tmp.begin(), tmp.end() );
336  }
337  }
338  }
339  }
340  return repos;
341  }
342 
344 
345  inline void assert_alias( const RepoInfo & info )
346  {
347  if ( info.alias().empty() )
348  ZYPP_THROW( RepoNoAliasException( info ) );
349  // bnc #473834. Maybe we can match the alias against a regex to define
350  // and check for valid aliases
351  if ( info.alias()[0] == '.')
353  info, _("Repository alias cannot start with dot.")));
354  }
355 
356  inline void assert_alias( const ServiceInfo & info )
357  {
358  if ( info.alias().empty() )
360  // bnc #473834. Maybe we can match the alias against a regex to define
361  // and check for valid aliases
362  if ( info.alias()[0] == '.')
364  info, _("Service alias cannot start with dot.")));
365  }
366 
368 
369  inline void assert_urls( const RepoInfo & info )
370  {
371  if ( info.baseUrlsEmpty() )
372  ZYPP_THROW( RepoNoUrlException( info ) );
373  }
374 
375  inline void assert_url( const ServiceInfo & info )
376  {
377  if ( ! info.url().isValid() )
379  }
380 
382 
384  namespace
385  {
387  inline bool isTmpRepo( const RepoInfo & info_r )
388  { return( info_r.filepath().empty() && info_r.usesAutoMethadataPaths() ); }
389  } // namespace
391 
396  inline Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
397  {
398  assert_alias(info);
399  return isTmpRepo( info ) ? info.metadataPath() : opt.repoRawCachePath / info.escaped_alias();
400  }
401 
410  inline Pathname rawproductdata_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
411  { return rawcache_path_for_repoinfo( opt, info ) / info.path(); }
412 
416  inline Pathname packagescache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
417  {
418  assert_alias(info);
419  return isTmpRepo( info ) ? info.packagesPath() : opt.repoPackagesCachePath / info.escaped_alias();
420  }
421 
425  inline Pathname solv_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
426  {
427  assert_alias(info);
428  return isTmpRepo( info ) ? info.metadataPath().dirname() / "%SLV%" : opt.repoSolvCachePath / info.escaped_alias();
429  }
430 
432 
434  class ServiceCollector
435  {
436  public:
437  typedef std::set<ServiceInfo> ServiceSet;
438 
439  ServiceCollector( ServiceSet & services_r )
440  : _services( services_r )
441  {}
442 
443  bool operator()( const ServiceInfo & service_r ) const
444  {
445  _services.insert( service_r );
446  return true;
447  }
448 
449  private:
450  ServiceSet & _services;
451  };
453 
454  } // namespace
456 
457  std::list<RepoInfo> readRepoFile( const Url & repo_file )
458  {
459  // no interface to download a specific file, using workaround:
461  Url url(repo_file);
462  Pathname path(url.getPathName());
463  url.setPathName ("/");
464  MediaSetAccess access(url);
465  Pathname local = access.provideFile(path);
466 
467  DBG << "reading repo file " << repo_file << ", local path: " << local << endl;
468 
469  return repositories_in_file(local);
470  }
471 
473  //
474  // class RepoManagerOptions
475  //
477 
479  {
480  repoCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoCachePath() );
481  repoRawCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoMetadataPath() );
482  repoSolvCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoSolvfilesPath() );
483  repoPackagesCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoPackagesPath() );
484  knownReposPath = Pathname::assertprefix( root_r, ZConfig::instance().knownReposPath() );
485  knownServicesPath = Pathname::assertprefix( root_r, ZConfig::instance().knownServicesPath() );
486  pluginsPath = Pathname::assertprefix( root_r, ZConfig::instance().pluginsPath() );
487  probe = ZConfig::instance().repo_add_probe();
488 
489  rootDir = root_r;
490  }
491 
493  {
494  RepoManagerOptions ret;
495  ret.repoCachePath = root_r;
496  ret.repoRawCachePath = root_r/"raw";
497  ret.repoSolvCachePath = root_r/"solv";
498  ret.repoPackagesCachePath = root_r/"packages";
499  ret.knownReposPath = root_r/"repos.d";
500  ret.knownServicesPath = root_r/"services.d";
501  ret.pluginsPath = root_r/"plugins";
502  ret.rootDir = root_r;
503  return ret;
504  }
505 
506  std:: ostream & operator<<( std::ostream & str, const RepoManagerOptions & obj )
507  {
508 #define OUTS(X) str << " " #X "\t" << obj.X << endl
509  str << "RepoManagerOptions (" << obj.rootDir << ") {" << endl;
510  OUTS( repoRawCachePath );
511  OUTS( repoSolvCachePath );
512  OUTS( repoPackagesCachePath );
513  OUTS( knownReposPath );
514  OUTS( knownServicesPath );
515  OUTS( pluginsPath );
516  str << "}" << endl;
517 #undef OUTS
518  return str;
519  }
520 
527  {
528  public:
529  Impl( const RepoManagerOptions &opt )
530  : _options(opt)
531  {
532  init_knownServices();
533  init_knownRepositories();
534  }
535 
537  {
538  // trigger appdata refresh if some repos change
539  if ( ( _reposDirty || env::ZYPP_PLUGIN_APPDATA_FORCE_COLLECT() )
540  && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
541  {
542  try {
543  std::list<Pathname> entries;
544  filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
545  if ( ! entries.empty() )
546  {
548  cmd.push_back( "<" ); // discard stdin
549  cmd.push_back( ">" ); // discard stdout
550  cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
551  for ( const auto & rinfo : repos() )
552  {
553  if ( ! rinfo.enabled() )
554  continue;
555  cmd.push_back( "-R" );
556  cmd.push_back( rinfo.alias() );
557  cmd.push_back( "-t" );
558  cmd.push_back( rinfo.type().asString() );
559  cmd.push_back( "-p" );
560  cmd.push_back( rinfo.metadataPath().asString() );
561  }
562 
563  for_( it, entries.begin(), entries.end() )
564  {
565  PathInfo pi( *it );
566  //DBG << "/tmp/xx ->" << pi << endl;
567  if ( pi.isFile() && pi.userMayRX() )
568  {
569  // trigger plugin
570  cmd[2] = pi.asString(); // [2] - PROGRAM
572  }
573  }
574  }
575  }
576  catch (...) {} // no throw in dtor
577  }
578  }
579 
580  public:
581  bool repoEmpty() const { return repos().empty(); }
582  RepoSizeType repoSize() const { return repos().size(); }
583  RepoConstIterator repoBegin() const { return repos().begin(); }
584  RepoConstIterator repoEnd() const { return repos().end(); }
585 
586  bool hasRepo( const std::string & alias ) const
587  { return foundAliasIn( alias, repos() ); }
588 
589  RepoInfo getRepo( const std::string & alias ) const
590  {
591  RepoConstIterator it( findAlias( alias, repos() ) );
592  return it == repos().end() ? RepoInfo::noRepo : *it;
593  }
594 
595  public:
596  Pathname metadataPath( const RepoInfo & info ) const
597  { return rawcache_path_for_repoinfo( _options, info ); }
598 
599  Pathname packagesPath( const RepoInfo & info ) const
600  { return packagescache_path_for_repoinfo( _options, info ); }
601 
602  RepoStatus metadataStatus( const RepoInfo & info ) const;
603 
604  RefreshCheckStatus checkIfToRefreshMetadata( const RepoInfo & info, const Url & url, RawMetadataRefreshPolicy policy );
605 
606  void refreshMetadata( const RepoInfo & info, RawMetadataRefreshPolicy policy, OPT_PROGRESS );
607 
608  void cleanMetadata( const RepoInfo & info, OPT_PROGRESS );
609 
610  void cleanPackages( const RepoInfo & info, OPT_PROGRESS );
611 
612  void buildCache( const RepoInfo & info, CacheBuildPolicy policy, OPT_PROGRESS );
613 
614  repo::RepoType probe( const Url & url, const Pathname & path = Pathname() ) const;
615  repo::RepoType probeCache( const Pathname & path_r ) const;
616 
617  void cleanCacheDirGarbage( OPT_PROGRESS );
618 
619  void cleanCache( const RepoInfo & info, OPT_PROGRESS );
620 
621  bool isCached( const RepoInfo & info ) const
622  { return PathInfo(solv_path_for_repoinfo( _options, info ) / "solv").isExist(); }
623 
624  RepoStatus cacheStatus( const RepoInfo & info ) const
625  { return RepoStatus::fromCookieFile(solv_path_for_repoinfo(_options, info) / "cookie"); }
626 
627  void loadFromCache( const RepoInfo & info, OPT_PROGRESS );
628 
629  void addRepository( const RepoInfo & info, OPT_PROGRESS );
630 
631  void addRepositories( const Url & url, OPT_PROGRESS );
632 
633  void removeRepository( const RepoInfo & info, OPT_PROGRESS );
634 
635  void modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, OPT_PROGRESS );
636 
637  RepoInfo getRepositoryInfo( const std::string & alias, OPT_PROGRESS );
639 
640  public:
641  bool serviceEmpty() const { return _services.empty(); }
642  ServiceSizeType serviceSize() const { return _services.size(); }
643  ServiceConstIterator serviceBegin() const { return _services.begin(); }
644  ServiceConstIterator serviceEnd() const { return _services.end(); }
645 
646  bool hasService( const std::string & alias ) const
647  { return foundAliasIn( alias, _services ); }
648 
649  ServiceInfo getService( const std::string & alias ) const
650  {
651  ServiceConstIterator it( findAlias( alias, _services ) );
652  return it == _services.end() ? ServiceInfo::noService : *it;
653  }
654 
655  public:
656  void addService( const ServiceInfo & service );
657  void addService( const std::string & alias, const Url & url )
658  { addService( ServiceInfo( alias, url ) ); }
659 
660  void removeService( const std::string & alias );
661  void removeService( const ServiceInfo & service )
662  { removeService( service.alias() ); }
663 
664  void refreshServices( const RefreshServiceOptions & options_r );
665 
666  void refreshService( const std::string & alias, const RefreshServiceOptions & options_r );
667  void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
668  { refreshService( service.alias(), options_r ); }
669 
670  void modifyService( const std::string & oldAlias, const ServiceInfo & newService );
671 
672  repo::ServiceType probeService( const Url & url ) const;
673 
674  private:
675  void saveService( ServiceInfo & service ) const;
676 
677  Pathname generateNonExistingName( const Pathname & dir, const std::string & basefilename ) const;
678 
679  std::string generateFilename( const RepoInfo & info ) const
680  { return filenameFromAlias( info.alias(), "repo" ); }
681 
682  std::string generateFilename( const ServiceInfo & info ) const
683  { return filenameFromAlias( info.alias(), "service" ); }
684 
685  void setCacheStatus( const RepoInfo & info, const RepoStatus & status )
686  {
687  Pathname base = solv_path_for_repoinfo( _options, info );
689  status.saveToCookieFile( base / "cookie" );
690  }
691 
692  void touchIndexFile( const RepoInfo & info );
693 
694  template<typename OutputIterator>
695  void getRepositoriesInService( const std::string & alias, OutputIterator out ) const
696  {
697  MatchServiceAlias filter( alias );
698  std::copy( boost::make_filter_iterator( filter, repos().begin(), repos().end() ),
699  boost::make_filter_iterator( filter, repos().end(), repos().end() ),
700  out);
701  }
702 
703  private:
704  void init_knownServices();
705  void init_knownRepositories();
706 
707  const RepoSet & repos() const { return _reposX; }
708  RepoSet & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; }
709 
710  private:
714 
716 
717  private:
718  friend Impl * rwcowClone<Impl>( const Impl * rhs );
720  Impl * clone() const
721  { return new Impl( *this ); }
722  };
724 
726  inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj )
727  { return str << "RepoManager::Impl"; }
728 
730 
732  {
733  filesystem::assert_dir( _options.knownServicesPath );
734  Pathname servfile = generateNonExistingName( _options.knownServicesPath,
735  generateFilename( service ) );
736  service.setFilepath( servfile );
737 
738  MIL << "saving service in " << servfile << endl;
739 
740  std::ofstream file( servfile.c_str() );
741  if ( !file )
742  {
743  // TranslatorExplanation '%s' is a filename
744  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), servfile.c_str() )));
745  }
746  service.dumpAsIniOn( file );
747  MIL << "done" << endl;
748  }
749 
766  const std::string & basefilename ) const
767  {
768  std::string final_filename = basefilename;
769  int counter = 1;
770  while ( PathInfo(dir + final_filename).isExist() )
771  {
772  final_filename = basefilename + "_" + str::numstring(counter);
773  ++counter;
774  }
775  return dir + Pathname(final_filename);
776  }
777 
779 
781  {
782  Pathname dir = _options.knownServicesPath;
783  std::list<Pathname> entries;
784  if (PathInfo(dir).isExist())
785  {
786  if ( filesystem::readdir( entries, dir, false ) != 0 )
787  {
788  // TranslatorExplanation '%s' is a pathname
789  ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str())));
790  }
791 
792  //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
793  for_(it, entries.begin(), entries.end() )
794  {
795  parser::ServiceFileReader(*it, ServiceCollector(_services));
796  }
797  }
798 
799  repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services));
800  }
801 
803  namespace {
809  inline void cleanupNonRepoMetadtaFolders( const Pathname & cachePath_r,
810  const Pathname & defaultCachePath_r,
811  const std::list<std::string> & repoEscAliases_r )
812  {
813  if ( cachePath_r != defaultCachePath_r )
814  return;
815 
816  std::list<std::string> entries;
817  if ( filesystem::readdir( entries, cachePath_r, false ) == 0 )
818  {
819  entries.sort();
820  std::set<std::string> oldfiles;
821  set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
822  std::inserter( oldfiles, oldfiles.end() ) );
823  for ( const std::string & old : oldfiles )
824  {
825  if ( old == Repository::systemRepoAlias() ) // don't remove the @System solv file
826  continue;
827  filesystem::recursive_rmdir( cachePath_r / old );
828  }
829  }
830  }
831  } // namespace
834  {
835  MIL << "start construct known repos" << endl;
836 
837  if ( PathInfo(_options.knownReposPath).isExist() )
838  {
839  std::list<std::string> repoEscAliases;
840  std::list<RepoInfo> orphanedRepos;
841  for ( RepoInfo & repoInfo : repositories_in_dir(_options.knownReposPath) )
842  {
843  // set the metadata path for the repo
844  repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo) );
845  // set the downloaded packages path for the repo
846  repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) );
847  // remember it
848  _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
849 
850  // detect orphaned repos belonging to a deleted service
851  const std::string & serviceAlias( repoInfo.service() );
852  if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
853  {
854  WAR << "Schedule orphaned service repo for deletion: " << repoInfo << endl;
855  orphanedRepos.push_back( repoInfo );
856  continue; // don't remember it in repoEscAliases
857  }
858 
859  repoEscAliases.push_back(repoInfo.escaped_alias());
860  }
861 
862  // Cleanup orphanded service repos:
863  if ( ! orphanedRepos.empty() )
864  {
865  for ( const auto & repoInfo : orphanedRepos )
866  {
867  MIL << "Delete orphaned service repo " << repoInfo.alias() << endl;
868  // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
869  // %1% = service name
870  // %2% = repository name
871  JobReport::warning( str::FormatNAC(_("Unknown service '%1%': Removing orphaned service repository '%2%'"))
872  % repoInfo.service()
873  % repoInfo.alias() );
874  try {
875  removeRepository( repoInfo );
876  }
877  catch ( const Exception & caugth )
878  {
879  JobReport::error( caugth.asUserHistory() );
880  }
881  }
882  }
883 
884  // delete metadata folders without corresponding repo (e.g. old tmp directories)
885  //
886  // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise
887  // we'd need somemagic file to identify zypp cache directories. Without this
888  // we may easily remove user data (zypper --pkg-cache-dir . download ...)
889  repoEscAliases.sort();
890  RepoManagerOptions defaultCache( _options.rootDir );
891  cleanupNonRepoMetadtaFolders( _options.repoRawCachePath, defaultCache.repoRawCachePath, repoEscAliases );
892  cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath, defaultCache.repoSolvCachePath, repoEscAliases );
893  cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath, defaultCache.repoPackagesCachePath, repoEscAliases );
894  }
895  MIL << "end construct known repos" << endl;
896  }
897 
899 
901  {
902  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
903  Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
904 
905  RepoType repokind = info.type();
906  // If unknown, probe the local metadata
907  if ( repokind == RepoType::NONE )
908  repokind = probeCache( productdatapath );
909 
910  RepoStatus status;
911  switch ( repokind.toEnum() )
912  {
913  case RepoType::RPMMD_e :
914  status = RepoStatus( productdatapath/"repodata/repomd.xml") && RepoStatus( mediarootpath/"media.1/media" );
915  break;
916 
917  case RepoType::YAST2_e :
918  status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" );
919  break;
920 
922  status = RepoStatus::fromCookieFile( productdatapath/"cookie" );
923  break;
924 
925  case RepoType::NONE_e :
926  // Return default RepoStatus in case of RepoType::NONE
927  // indicating it should be created?
928  // ZYPP_THROW(RepoUnknownTypeException());
929  break;
930  }
931  return status;
932  }
933 
934 
936  {
937  Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
938 
939  RepoType repokind = info.type();
940  if ( repokind.toEnum() == RepoType::NONE_e )
941  // unknown, probe the local metadata
942  repokind = probeCache( productdatapath );
943  // if still unknown, just return
944  if (repokind == RepoType::NONE_e)
945  return;
946 
947  Pathname p;
948  switch ( repokind.toEnum() )
949  {
950  case RepoType::RPMMD_e :
951  p = Pathname(productdatapath + "/repodata/repomd.xml");
952  break;
953 
954  case RepoType::YAST2_e :
955  p = Pathname(productdatapath + "/content");
956  break;
957 
959  p = Pathname(productdatapath + "/cookie");
960  break;
961 
962  case RepoType::NONE_e :
963  default:
964  break;
965  }
966 
967  // touch the file, ignore error (they are logged anyway)
969  }
970 
971 
973  {
974  assert_alias(info);
975  try
976  {
977  MIL << "Going to try to check whether refresh is needed for " << url << " (" << info.type() << ")" << endl;
978 
979  // first check old (cached) metadata
980  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
981  filesystem::assert_dir( mediarootpath );
982  RepoStatus oldstatus = metadataStatus( info );
983  if ( oldstatus.empty() )
984  {
985  MIL << "No cached metadata, going to refresh" << endl;
986  return REFRESH_NEEDED;
987  }
988 
989  if ( url.schemeIsVolatile() )
990  {
991  MIL << "Never refresh CD/DVD" << endl;
992  return REPO_UP_TO_DATE;
993  }
994 
995  if ( policy == RefreshForced )
996  {
997  MIL << "Forced refresh!" << endl;
998  return REFRESH_NEEDED;
999  }
1000 
1001  if ( url.schemeIsLocal() )
1002  {
1003  policy = RefreshIfNeededIgnoreDelay;
1004  }
1005 
1006  // now we've got the old (cached) status, we can decide repo.refresh.delay
1007  if ( policy != RefreshIfNeededIgnoreDelay )
1008  {
1009  // difference in seconds
1010  double diff = difftime(
1012  (Date::ValueType)oldstatus.timestamp()) / 60;
1013 
1014  DBG << "oldstatus: " << (Date::ValueType)oldstatus.timestamp() << endl;
1015  DBG << "current time: " << (Date::ValueType)Date::now() << endl;
1016  DBG << "last refresh = " << diff << " minutes ago" << endl;
1017 
1018  if ( diff < ZConfig::instance().repo_refresh_delay() )
1019  {
1020  if ( diff < 0 )
1021  {
1022  WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
1023  }
1024  else
1025  {
1026  MIL << "Repository '" << info.alias()
1027  << "' has been refreshed less than repo.refresh.delay ("
1029  << ") minutes ago. Advising to skip refresh" << endl;
1030  return REPO_CHECK_DELAYED;
1031  }
1032  }
1033  }
1034 
1035  repo::RepoType repokind = info.type();
1036  // if unknown: probe it
1037  if ( repokind == RepoType::NONE )
1038  repokind = probe( url, info.path() );
1039 
1040  // retrieve newstatus
1041  RepoStatus newstatus;
1042  switch ( repokind.toEnum() )
1043  {
1044  case RepoType::RPMMD_e:
1045  {
1046  MediaSetAccess media( url );
1047  newstatus = yum::Downloader( info, mediarootpath ).status( media );
1048  }
1049  break;
1050 
1051  case RepoType::YAST2_e:
1052  {
1053  MediaSetAccess media( url );
1054  newstatus = susetags::Downloader( info, mediarootpath ).status( media );
1055  }
1056  break;
1057 
1059  newstatus = RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status
1060  break;
1061 
1062  default:
1063  case RepoType::NONE_e:
1065  break;
1066  }
1067 
1068  // check status
1069  if ( oldstatus == newstatus )
1070  {
1071  MIL << "repo has not changed" << endl;
1072  touchIndexFile( info );
1073  return REPO_UP_TO_DATE;
1074  }
1075  else // includes newstatus.empty() if e.g. repo format changed
1076  {
1077  MIL << "repo has changed, going to refresh" << endl;
1078  return REFRESH_NEEDED;
1079  }
1080  }
1081  catch ( const Exception &e )
1082  {
1083  ZYPP_CAUGHT(e);
1084  ERR << "refresh check failed for " << url << endl;
1085  ZYPP_RETHROW(e);
1086  }
1087 
1088  return REFRESH_NEEDED; // default
1089  }
1090 
1091 
1093  {
1094  assert_alias(info);
1095  assert_urls(info);
1096 
1097  // we will throw this later if no URL checks out fine
1098  RepoException rexception( info, PL_("Valid metadata not found at specified URL",
1099  "Valid metadata not found at specified URLs",
1100  info.baseUrlsSize() ) );
1101 
1102  // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
1104  // try urls one by one
1105  for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
1106  {
1107  try
1108  {
1109  Url url(*it);
1110 
1111  // check whether to refresh metadata
1112  // if the check fails for this url, it throws, so another url will be checked
1113  if (checkIfToRefreshMetadata(info, url, policy)!=REFRESH_NEEDED)
1114  return;
1115 
1116  MIL << "Going to refresh metadata from " << url << endl;
1117 
1118  // bsc#1048315: Always re-probe in case of repo format change.
1119  // TODO: Would be sufficient to verify the type and re-probe
1120  // if verification failed (or type is RepoType::NONE)
1121  repo::RepoType repokind = info.type();
1122  {
1123  repo::RepoType probed = probe( *it, info.path() );
1124  if ( repokind != probed )
1125  {
1126  repokind = probed;
1127  // Adjust the probed type in RepoInfo
1128  info.setProbedType( repokind ); // lazy init!
1129  //save probed type only for repos in system
1130  for_( it, repoBegin(), repoEnd() )
1131  {
1132  if ( info.alias() == (*it).alias() )
1133  {
1134  RepoInfo modifiedrepo = info;
1135  modifiedrepo.setType( repokind );
1136  modifyRepository( info.alias(), modifiedrepo );
1137  break;
1138  }
1139  }
1140  }
1141  }
1142 
1143  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1144  if( filesystem::assert_dir(mediarootpath) )
1145  {
1146  Exception ex(str::form( _("Can't create %s"), mediarootpath.c_str()) );
1147  ZYPP_THROW(ex);
1148  }
1149 
1150  // create temp dir as sibling of mediarootpath
1151  filesystem::TmpDir tmpdir( filesystem::TmpDir::makeSibling( mediarootpath ) );
1152  if( tmpdir.path().empty() )
1153  {
1154  Exception ex(_("Can't create metadata cache directory."));
1155  ZYPP_THROW(ex);
1156  }
1157 
1158  if ( ( repokind.toEnum() == RepoType::RPMMD_e ) ||
1159  ( repokind.toEnum() == RepoType::YAST2_e ) )
1160  {
1161  MediaSetAccess media(url);
1162  shared_ptr<repo::Downloader> downloader_ptr;
1163 
1164  MIL << "Creating downloader for [ " << info.alias() << " ]" << endl;
1165 
1166  if ( repokind.toEnum() == RepoType::RPMMD_e )
1167  downloader_ptr.reset(new yum::Downloader(info, mediarootpath));
1168  else
1169  downloader_ptr.reset( new susetags::Downloader(info, mediarootpath) );
1170 
1177  for_( it, repoBegin(), repoEnd() )
1178  {
1179  Pathname cachepath(rawcache_path_for_repoinfo( _options, *it ));
1180  if ( PathInfo(cachepath).isExist() )
1181  downloader_ptr->addCachePath(cachepath);
1182  }
1183 
1184  downloader_ptr->download( media, tmpdir.path() );
1185  }
1186  else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e )
1187  {
1188  MediaMounter media( url );
1189  RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) ); // dir status
1190 
1191  Pathname productpath( tmpdir.path() / info.path() );
1192  filesystem::assert_dir( productpath );
1193  newstatus.saveToCookieFile( productpath/"cookie" );
1194  }
1195  else
1196  {
1198  }
1199 
1200  // ok we have the metadata, now exchange
1201  // the contents
1202  filesystem::exchange( tmpdir.path(), mediarootpath );
1203  if ( ! isTmpRepo( info ) )
1204  reposManip(); // remember to trigger appdata refresh
1205 
1206  // we are done.
1207  return;
1208  }
1209  catch ( const Exception &e )
1210  {
1211  ZYPP_CAUGHT(e);
1212  ERR << "Trying another url..." << endl;
1213 
1214  // remember the exception caught for the *first URL*
1215  // if all other URLs fail, the rexception will be thrown with the
1216  // cause of the problem of the first URL remembered
1217  if (it == info.baseUrlsBegin())
1218  rexception.remember(e);
1219  else
1220  rexception.addHistory( e.asUserString() );
1221 
1222  }
1223  } // for every url
1224  ERR << "No more urls..." << endl;
1225  ZYPP_THROW(rexception);
1226  }
1227 
1229 
1230  void RepoManager::Impl::cleanMetadata( const RepoInfo & info, const ProgressData::ReceiverFnc & progressfnc )
1231  {
1232  ProgressData progress(100);
1233  progress.sendTo(progressfnc);
1234 
1235  filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_options, info));
1236  progress.toMax();
1237  }
1238 
1239 
1240  void RepoManager::Impl::cleanPackages( const RepoInfo & info, const ProgressData::ReceiverFnc & progressfnc )
1241  {
1242  ProgressData progress(100);
1243  progress.sendTo(progressfnc);
1244 
1245  filesystem::recursive_rmdir(packagescache_path_for_repoinfo(_options, info));
1246  progress.toMax();
1247  }
1248 
1249 
1250  void RepoManager::Impl::buildCache( const RepoInfo & info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
1251  {
1252  assert_alias(info);
1253  Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1254  Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
1255 
1256  if( filesystem::assert_dir(_options.repoCachePath) )
1257  {
1258  Exception ex(str::form( _("Can't create %s"), _options.repoCachePath.c_str()) );
1259  ZYPP_THROW(ex);
1260  }
1261  RepoStatus raw_metadata_status = metadataStatus(info);
1262  if ( raw_metadata_status.empty() )
1263  {
1264  /* if there is no cache at this point, we refresh the raw
1265  in case this is the first time - if it's !autorefresh,
1266  we may still refresh */
1267  refreshMetadata(info, RefreshIfNeeded, progressrcv );
1268  raw_metadata_status = metadataStatus(info);
1269  }
1270 
1271  bool needs_cleaning = false;
1272  if ( isCached( info ) )
1273  {
1274  MIL << info.alias() << " is already cached." << endl;
1275  RepoStatus cache_status = cacheStatus(info);
1276 
1277  if ( cache_status == raw_metadata_status )
1278  {
1279  MIL << info.alias() << " cache is up to date with metadata." << endl;
1280  if ( policy == BuildIfNeeded )
1281  {
1282  // On the fly add missing solv.idx files for bash completion.
1283  const Pathname & base = solv_path_for_repoinfo( _options, info);
1284  if ( ! PathInfo(base/"solv.idx").isExist() )
1285  sat::updateSolvFileIndex( base/"solv" );
1286 
1287  return;
1288  }
1289  else {
1290  MIL << info.alias() << " cache rebuild is forced" << endl;
1291  }
1292  }
1293 
1294  needs_cleaning = true;
1295  }
1296 
1297  ProgressData progress(100);
1299  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1300  progress.name(str::form(_("Building repository '%s' cache"), info.label().c_str()));
1301  progress.toMin();
1302 
1303  if (needs_cleaning)
1304  {
1305  cleanCache(info);
1306  }
1307 
1308  MIL << info.alias() << " building cache..." << info.type() << endl;
1309 
1310  Pathname base = solv_path_for_repoinfo( _options, info);
1311 
1312  if( filesystem::assert_dir(base) )
1313  {
1314  Exception ex(str::form( _("Can't create %s"), base.c_str()) );
1315  ZYPP_THROW(ex);
1316  }
1317 
1318  if( ! PathInfo(base).userMayW() )
1319  {
1320  Exception ex(str::form( _("Can't create cache at %s - no writing permissions."), base.c_str()) );
1321  ZYPP_THROW(ex);
1322  }
1323  Pathname solvfile = base / "solv";
1324 
1325  // do we have type?
1326  repo::RepoType repokind = info.type();
1327 
1328  // if the type is unknown, try probing.
1329  switch ( repokind.toEnum() )
1330  {
1331  case RepoType::NONE_e:
1332  // unknown, probe the local metadata
1333  repokind = probeCache( productdatapath );
1334  break;
1335  default:
1336  break;
1337  }
1338 
1339  MIL << "repo type is " << repokind << endl;
1340 
1341  switch ( repokind.toEnum() )
1342  {
1343  case RepoType::RPMMD_e :
1344  case RepoType::YAST2_e :
1346  {
1347  // Take care we unlink the solvfile on exception
1348  ManagedFile guard( solvfile, filesystem::unlink );
1349  scoped_ptr<MediaMounter> forPlainDirs;
1350 
1352  cmd.push_back( "/usr/lib/zypp/tools/repo2solv" );
1353  // repo2solv expects -o as 1st arg!
1354  cmd.push_back( "-o" );
1355  cmd.push_back( solvfile.asString() );
1356  cmd.push_back( "-X" ); // autogenerate pattern from pattern-package
1357  //cmd.push_back( "-A" ); // autogenerate application pseudo packages
1358 
1359  if ( repokind == RepoType::RPMPLAINDIR )
1360  {
1361  forPlainDirs.reset( new MediaMounter( info.url() ) );
1362  // recusive for plaindir as 2nd arg!
1363  cmd.push_back( "-R" );
1364  // FIXME this does only work form dir: URLs
1365  cmd.push_back( forPlainDirs->getPathName( info.path() ).c_str() );
1366  }
1367  else
1368  cmd.push_back( productdatapath.asString() );
1369 
1371  std::string errdetail;
1372 
1373  for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1374  WAR << " " << output;
1375  if ( errdetail.empty() ) {
1376  errdetail = prog.command();
1377  errdetail += '\n';
1378  }
1379  errdetail += output;
1380  }
1381 
1382  int ret = prog.close();
1383  if ( ret != 0 )
1384  {
1385  RepoException ex(str::form( _("Failed to cache repo (%d)."), ret ));
1386  ex.remember( errdetail );
1387  ZYPP_THROW(ex);
1388  }
1389 
1390  // We keep it.
1391  guard.resetDispose();
1392  sat::updateSolvFileIndex( solvfile ); // content digest for zypper bash completion
1393  }
1394  break;
1395  default:
1396  ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") ));
1397  break;
1398  }
1399  // update timestamp and checksum
1400  setCacheStatus(info, raw_metadata_status);
1401  MIL << "Commit cache.." << endl;
1402  progress.toMax();
1403  }
1404 
1406 
1407 
1414  repo::RepoType RepoManager::Impl::probe( const Url & url, const Pathname & path ) const
1415  {
1416  MIL << "going to probe the repo type at " << url << " (" << path << ")" << endl;
1417 
1418  if ( url.getScheme() == "dir" && ! PathInfo( url.getPathName()/path ).isDir() )
1419  {
1420  // Handle non existing local directory in advance, as
1421  // MediaSetAccess does not support it.
1422  MIL << "Probed type NONE (not exists) at " << url << " (" << path << ")" << endl;
1423  return repo::RepoType::NONE;
1424  }
1425 
1426  // prepare exception to be thrown if the type could not be determined
1427  // due to a media exception. We can't throw right away, because of some
1428  // problems with proxy servers returning an incorrect error
1429  // on ftp file-not-found(bnc #335906). Instead we'll check another types
1430  // before throwing.
1431 
1432  // TranslatorExplanation '%s' is an URL
1433  RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
1434  bool gotMediaException = false;
1435  try
1436  {
1437  MediaSetAccess access(url);
1438  try
1439  {
1440  if ( access.doesFileExist(path/"/repodata/repomd.xml") )
1441  {
1442  MIL << "Probed type RPMMD at " << url << " (" << path << ")" << endl;
1443  return repo::RepoType::RPMMD;
1444  }
1445  }
1446  catch ( const media::MediaException &e )
1447  {
1448  ZYPP_CAUGHT(e);
1449  DBG << "problem checking for repodata/repomd.xml file" << endl;
1450  enew.remember(e);
1451  gotMediaException = true;
1452  }
1453 
1454  try
1455  {
1456  if ( access.doesFileExist(path/"/content") )
1457  {
1458  MIL << "Probed type YAST2 at " << url << " (" << path << ")" << endl;
1459  return repo::RepoType::YAST2;
1460  }
1461  }
1462  catch ( const media::MediaException &e )
1463  {
1464  ZYPP_CAUGHT(e);
1465  DBG << "problem checking for content file" << endl;
1466  enew.remember(e);
1467  gotMediaException = true;
1468  }
1469 
1470  // if it is a non-downloading URL denoting a directory
1471  if ( ! url.schemeIsDownloading() )
1472  {
1473  MediaMounter media( url );
1474  if ( PathInfo(media.getPathName()/path).isDir() )
1475  {
1476  // allow empty dirs for now
1477  MIL << "Probed type RPMPLAINDIR at " << url << " (" << path << ")" << endl;
1479  }
1480  }
1481  }
1482  catch ( const Exception &e )
1483  {
1484  ZYPP_CAUGHT(e);
1485  // TranslatorExplanation '%s' is an URL
1486  Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
1487  enew.remember(e);
1488  ZYPP_THROW(enew);
1489  }
1490 
1491  if (gotMediaException)
1492  ZYPP_THROW(enew);
1493 
1494  MIL << "Probed type NONE at " << url << " (" << path << ")" << endl;
1495  return repo::RepoType::NONE;
1496  }
1497 
1504  {
1505  MIL << "going to probe the cached repo at " << path_r << endl;
1506 
1508 
1509  if ( PathInfo(path_r/"/repodata/repomd.xml").isFile() )
1510  { ret = repo::RepoType::RPMMD; }
1511  else if ( PathInfo(path_r/"/content").isFile() )
1512  { ret = repo::RepoType::YAST2; }
1513  else if ( PathInfo(path_r).isDir() )
1514  { ret = repo::RepoType::RPMPLAINDIR; }
1515 
1516  MIL << "Probed cached type " << ret << " at " << path_r << endl;
1517  return ret;
1518  }
1519 
1521 
1523  {
1524  MIL << "Going to clean up garbage in cache dirs" << endl;
1525 
1526  ProgressData progress(300);
1527  progress.sendTo(progressrcv);
1528  progress.toMin();
1529 
1530  std::list<Pathname> cachedirs;
1531  cachedirs.push_back(_options.repoRawCachePath);
1532  cachedirs.push_back(_options.repoPackagesCachePath);
1533  cachedirs.push_back(_options.repoSolvCachePath);
1534 
1535  for_( dir, cachedirs.begin(), cachedirs.end() )
1536  {
1537  if ( PathInfo(*dir).isExist() )
1538  {
1539  std::list<Pathname> entries;
1540  if ( filesystem::readdir( entries, *dir, false ) != 0 )
1541  // TranslatorExplanation '%s' is a pathname
1542  ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir->c_str())));
1543 
1544  unsigned sdircount = entries.size();
1545  unsigned sdircurrent = 1;
1546  for_( subdir, entries.begin(), entries.end() )
1547  {
1548  // if it does not belong known repo, make it disappear
1549  bool found = false;
1550  for_( r, repoBegin(), repoEnd() )
1551  if ( subdir->basename() == r->escaped_alias() )
1552  { found = true; break; }
1553 
1554  if ( ! found && ( Date::now()-PathInfo(*subdir).mtime() > Date::day ) )
1555  filesystem::recursive_rmdir( *subdir );
1556 
1557  progress.set( progress.val() + sdircurrent * 100 / sdircount );
1558  ++sdircurrent;
1559  }
1560  }
1561  else
1562  progress.set( progress.val() + 100 );
1563  }
1564  progress.toMax();
1565  }
1566 
1568 
1569  void RepoManager::Impl::cleanCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1570  {
1571  ProgressData progress(100);
1572  progress.sendTo(progressrcv);
1573  progress.toMin();
1574 
1575  MIL << "Removing raw metadata cache for " << info.alias() << endl;
1576  filesystem::recursive_rmdir(solv_path_for_repoinfo(_options, info));
1577 
1578  progress.toMax();
1579  }
1580 
1582 
1583  void RepoManager::Impl::loadFromCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1584  {
1585  assert_alias(info);
1586  Pathname solvfile = solv_path_for_repoinfo(_options, info) / "solv";
1587 
1588  if ( ! PathInfo(solvfile).isExist() )
1590 
1591  sat::Pool::instance().reposErase( info.alias() );
1592  try
1593  {
1594  Repository repo = sat::Pool::instance().addRepoSolv( solvfile, info );
1595  // test toolversion in order to rebuild solv file in case
1596  // it was written by a different libsolv-tool parser.
1597  const std::string & toolversion( sat::LookupRepoAttr( sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
1598  if ( toolversion != LIBSOLV_TOOLVERSION )
1599  {
1600  repo.eraseFromPool();
1601  ZYPP_THROW(Exception(str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
1602  }
1603  }
1604  catch ( const Exception & exp )
1605  {
1606  ZYPP_CAUGHT( exp );
1607  MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1608  cleanCache( info, progressrcv );
1609  buildCache( info, BuildIfNeeded, progressrcv );
1610 
1611  sat::Pool::instance().addRepoSolv( solvfile, info );
1612  }
1613  }
1614 
1616 
1617  void RepoManager::Impl::addRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1618  {
1619  assert_alias(info);
1620 
1621  ProgressData progress(100);
1623  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1624  progress.name(str::form(_("Adding repository '%s'"), info.label().c_str()));
1625  progress.toMin();
1626 
1627  MIL << "Try adding repo " << info << endl;
1628 
1629  RepoInfo tosave = info;
1630  if ( repos().find(tosave) != repos().end() )
1632 
1633  // check the first url for now
1634  if ( _options.probe )
1635  {
1636  DBG << "unknown repository type, probing" << endl;
1637  assert_urls(tosave);
1638 
1639  RepoType probedtype( probe( tosave.url(), info.path() ) );
1640  if ( probedtype == RepoType::NONE )
1642  else
1643  tosave.setType(probedtype);
1644  }
1645 
1646  progress.set(50);
1647 
1648  // assert the directory exists
1649  filesystem::assert_dir(_options.knownReposPath);
1650 
1651  Pathname repofile = generateNonExistingName(
1652  _options.knownReposPath, generateFilename(tosave));
1653  // now we have a filename that does not exists
1654  MIL << "Saving repo in " << repofile << endl;
1655 
1656  std::ofstream file(repofile.c_str());
1657  if (!file)
1658  {
1659  // TranslatorExplanation '%s' is a filename
1660  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1661  }
1662 
1663  tosave.dumpAsIniOn(file);
1664  tosave.setFilepath(repofile);
1665  tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1666  tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1667  {
1668  // We should fix the API as we must inject those paths
1669  // into the repoinfo in order to keep it usable.
1670  RepoInfo & oinfo( const_cast<RepoInfo &>(info) );
1671  oinfo.setFilepath(repofile);
1672  oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1673  oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1674  }
1675  reposManip().insert(tosave);
1676 
1677  progress.set(90);
1678 
1679  // check for credentials in Urls
1680  UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
1681 
1682  HistoryLog(_options.rootDir).addRepository(tosave);
1683 
1684  progress.toMax();
1685  MIL << "done" << endl;
1686  }
1687 
1688 
1690  {
1691  std::list<RepoInfo> repos = readRepoFile(url);
1692  for ( std::list<RepoInfo>::const_iterator it = repos.begin();
1693  it != repos.end();
1694  ++it )
1695  {
1696  // look if the alias is in the known repos.
1697  for_ ( kit, repoBegin(), repoEnd() )
1698  {
1699  if ( (*it).alias() == (*kit).alias() )
1700  {
1701  ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << endl;
1703  }
1704  }
1705  }
1706 
1707  std::string filename = Pathname(url.getPathName()).basename();
1708 
1709  if ( filename == Pathname() )
1710  {
1711  // TranslatorExplanation '%s' is an URL
1712  ZYPP_THROW(RepoException(str::form( _("Invalid repo file name at '%s'"), url.asString().c_str() )));
1713  }
1714 
1715  // assert the directory exists
1716  filesystem::assert_dir(_options.knownReposPath);
1717 
1718  Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
1719  // now we have a filename that does not exists
1720  MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
1721 
1722  std::ofstream file(repofile.c_str());
1723  if (!file)
1724  {
1725  // TranslatorExplanation '%s' is a filename
1726  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1727  }
1728 
1729  for ( std::list<RepoInfo>::iterator it = repos.begin();
1730  it != repos.end();
1731  ++it )
1732  {
1733  MIL << "Saving " << (*it).alias() << endl;
1734  it->dumpAsIniOn(file);
1735  it->setFilepath(repofile);
1736  it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
1737  it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
1738  reposManip().insert(*it);
1739 
1740  HistoryLog(_options.rootDir).addRepository(*it);
1741  }
1742 
1743  MIL << "done" << endl;
1744  }
1745 
1747 
1749  {
1750  ProgressData progress;
1752  progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1753  progress.name(str::form(_("Removing repository '%s'"), info.label().c_str()));
1754 
1755  MIL << "Going to delete repo " << info.alias() << endl;
1756 
1757  for_( it, repoBegin(), repoEnd() )
1758  {
1759  // they can be the same only if the provided is empty, that means
1760  // the provided repo has no alias
1761  // then skip
1762  if ( (!info.alias().empty()) && ( info.alias() != (*it).alias() ) )
1763  continue;
1764 
1765  // TODO match by url
1766 
1767  // we have a matcing repository, now we need to know
1768  // where it does come from.
1769  RepoInfo todelete = *it;
1770  if (todelete.filepath().empty())
1771  {
1772  ZYPP_THROW(RepoException( todelete, _("Can't figure out where the repo is stored.") ));
1773  }
1774  else
1775  {
1776  // figure how many repos are there in the file:
1777  std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath());
1778  if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
1779  ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
1780  {
1781  // easy: file does not exist, contains no or only the repo to delete: delete the file
1782  int ret = filesystem::unlink( todelete.filepath() );
1783  if ( ! ( ret == 0 || ret == ENOENT ) )
1784  {
1785  // TranslatorExplanation '%s' is a filename
1786  ZYPP_THROW(RepoException( todelete, str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
1787  }
1788  MIL << todelete.alias() << " successfully deleted." << endl;
1789  }
1790  else
1791  {
1792  // there are more repos in the same file
1793  // write them back except the deleted one.
1794  //TmpFile tmp;
1795  //std::ofstream file(tmp.path().c_str());
1796 
1797  // assert the directory exists
1798  filesystem::assert_dir(todelete.filepath().dirname());
1799 
1800  std::ofstream file(todelete.filepath().c_str());
1801  if (!file)
1802  {
1803  // TranslatorExplanation '%s' is a filename
1804  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
1805  }
1806  for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1807  fit != filerepos.end();
1808  ++fit )
1809  {
1810  if ( (*fit).alias() != todelete.alias() )
1811  (*fit).dumpAsIniOn(file);
1812  }
1813  }
1814 
1815  CombinedProgressData cSubprogrcv(progress, 20);
1816  CombinedProgressData mSubprogrcv(progress, 40);
1817  CombinedProgressData pSubprogrcv(progress, 40);
1818  // now delete it from cache
1819  if ( isCached(todelete) )
1820  cleanCache( todelete, cSubprogrcv);
1821  // now delete metadata (#301037)
1822  cleanMetadata( todelete, mSubprogrcv );
1823  cleanPackages( todelete, pSubprogrcv );
1824  reposManip().erase(todelete);
1825  MIL << todelete.alias() << " successfully deleted." << endl;
1826  HistoryLog(_options.rootDir).removeRepository(todelete);
1827  return;
1828  } // else filepath is empty
1829 
1830  }
1831  // should not be reached on a sucess workflow
1833  }
1834 
1836 
1837  void RepoManager::Impl::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, const ProgressData::ReceiverFnc & progressrcv )
1838  {
1839  RepoInfo toedit = getRepositoryInfo(alias);
1840  RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
1841 
1842  // check if the new alias already exists when renaming the repo
1843  if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
1844  {
1846  }
1847 
1848  if (toedit.filepath().empty())
1849  {
1850  ZYPP_THROW(RepoException( toedit, _("Can't figure out where the repo is stored.") ));
1851  }
1852  else
1853  {
1854  // figure how many repos are there in the file:
1855  std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath());
1856 
1857  // there are more repos in the same file
1858  // write them back except the deleted one.
1859  //TmpFile tmp;
1860  //std::ofstream file(tmp.path().c_str());
1861 
1862  // assert the directory exists
1864 
1865  std::ofstream file(toedit.filepath().c_str());
1866  if (!file)
1867  {
1868  // TranslatorExplanation '%s' is a filename
1869  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
1870  }
1871  for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1872  fit != filerepos.end();
1873  ++fit )
1874  {
1875  // if the alias is different, dump the original
1876  // if it is the same, dump the provided one
1877  if ( (*fit).alias() != toedit.alias() )
1878  (*fit).dumpAsIniOn(file);
1879  else
1880  newinfo.dumpAsIniOn(file);
1881  }
1882 
1883  if ( toedit.enabled() && !newinfo.enabled() )
1884  {
1885  // On the fly remove solv.idx files for bash completion if a repo gets disabled.
1886  const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/"solv.idx";
1887  if ( PathInfo(solvidx).isExist() )
1888  filesystem::unlink( solvidx );
1889  }
1890 
1891  newinfo.setFilepath(toedit.filepath());
1892  newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1893  newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1894  {
1895  // We should fix the API as we must inject those paths
1896  // into the repoinfo in order to keep it usable.
1897  RepoInfo & oinfo( const_cast<RepoInfo &>(newinfo_r) );
1898  oinfo.setFilepath(toedit.filepath());
1899  oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1900  oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1901  }
1902  reposManip().erase(toedit);
1903  reposManip().insert(newinfo);
1904  // check for credentials in Urls
1905  UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
1906  HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
1907  MIL << "repo " << alias << " modified" << endl;
1908  }
1909  }
1910 
1912 
1913  RepoInfo RepoManager::Impl::getRepositoryInfo( const std::string & alias, const ProgressData::ReceiverFnc & progressrcv )
1914  {
1915  RepoConstIterator it( findAlias( alias, repos() ) );
1916  if ( it != repos().end() )
1917  return *it;
1918  RepoInfo info;
1919  info.setAlias( alias );
1921  }
1922 
1923 
1924  RepoInfo RepoManager::Impl::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
1925  {
1926  for_( it, repoBegin(), repoEnd() )
1927  {
1928  for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
1929  {
1930  if ( (*urlit).asString(urlview) == url.asString(urlview) )
1931  return *it;
1932  }
1933  }
1934  RepoInfo info;
1935  info.setBaseUrl( url );
1937  }
1938 
1940  //
1941  // Services
1942  //
1944 
1946  {
1947  assert_alias( service );
1948 
1949  // check if service already exists
1950  if ( hasService( service.alias() ) )
1952 
1953  // Writable ServiceInfo is needed to save the location
1954  // of the .service file. Finaly insert into the service list.
1955  ServiceInfo toSave( service );
1956  saveService( toSave );
1957  _services.insert( toSave );
1958 
1959  // check for credentials in Url
1960  UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1961 
1962  MIL << "added service " << toSave.alias() << endl;
1963  }
1964 
1966 
1967  void RepoManager::Impl::removeService( const std::string & alias )
1968  {
1969  MIL << "Going to delete service " << alias << endl;
1970 
1971  const ServiceInfo & service = getService( alias );
1972 
1973  Pathname location = service.filepath();
1974  if( location.empty() )
1975  {
1976  ZYPP_THROW(ServiceException( service, _("Can't figure out where the service is stored.") ));
1977  }
1978 
1979  ServiceSet tmpSet;
1980  parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
1981 
1982  // only one service definition in the file
1983  if ( tmpSet.size() == 1 )
1984  {
1985  if ( filesystem::unlink(location) != 0 )
1986  {
1987  // TranslatorExplanation '%s' is a filename
1988  ZYPP_THROW(ServiceException( service, str::form( _("Can't delete '%s'"), location.c_str() ) ));
1989  }
1990  MIL << alias << " successfully deleted." << endl;
1991  }
1992  else
1993  {
1994  filesystem::assert_dir(location.dirname());
1995 
1996  std::ofstream file(location.c_str());
1997  if( !file )
1998  {
1999  // TranslatorExplanation '%s' is a filename
2000  ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), location.c_str() )));
2001  }
2002 
2003  for_(it, tmpSet.begin(), tmpSet.end())
2004  {
2005  if( it->alias() != alias )
2006  it->dumpAsIniOn(file);
2007  }
2008 
2009  MIL << alias << " successfully deleted from file " << location << endl;
2010  }
2011 
2012  // now remove all repositories added by this service
2013  RepoCollector rcollector;
2014  getRepositoriesInService( alias,
2015  boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) );
2016  // cannot do this directly in getRepositoriesInService - would invalidate iterators
2017  for_(rit, rcollector.repos.begin(), rcollector.repos.end())
2018  removeRepository(*rit);
2019  }
2020 
2022 
2024  {
2025  // copy the set of services since refreshService
2026  // can eventually invalidate the iterator
2027  ServiceSet services( serviceBegin(), serviceEnd() );
2028  for_( it, services.begin(), services.end() )
2029  {
2030  if ( !it->enabled() )
2031  continue;
2032 
2033  try {
2034  refreshService(*it, options_r);
2035  }
2036  catch ( const repo::ServicePluginInformalException & e )
2037  { ;/* ignore ServicePluginInformalException */ }
2038  }
2039  }
2040 
2041  void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2042  {
2043  ServiceInfo service( getService( alias ) );
2044  assert_alias( service );
2045  assert_url( service );
2046  MIL << "Going to refresh service '" << service.alias() << "', url: " << service.url() << ", opts: " << options_r << endl;
2047 
2048  if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
2049  {
2050  // Service defines a TTL; maybe we can re-use existing data without refresh.
2051  Date lrf = service.lrf();
2052  if ( lrf )
2053  {
2054  Date now( Date::now() );
2055  if ( lrf <= now )
2056  {
2057  if ( (lrf+=service.ttl()) > now ) // lrf+= !
2058  {
2059  MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
2060  return;
2061  }
2062  }
2063  else
2064  WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
2065  }
2066  }
2067 
2068  // NOTE: It might be necessary to modify and rewrite the service info.
2069  // Either when probing the type, or when adjusting the repositories
2070  // enable/disable state.:
2071  bool serviceModified = false;
2072 
2074 
2075  // if the type is unknown, try probing.
2076  if ( service.type() == repo::ServiceType::NONE )
2077  {
2078  repo::ServiceType type = probeService( service.url() );
2079  if ( type != ServiceType::NONE )
2080  {
2081  service.setProbedType( type ); // lazy init!
2082  serviceModified = true;
2083  }
2084  }
2085 
2086  // get target distro identifier
2087  std::string servicesTargetDistro = _options.servicesTargetDistro;
2088  if ( servicesTargetDistro.empty() )
2089  {
2090  servicesTargetDistro = Target::targetDistribution( Pathname() );
2091  }
2092  DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
2093 
2094  // parse it
2095  Date::Duration origTtl = service.ttl(); // FIXME Ugly hack: const service.ttl modified when parsing
2096  RepoCollector collector(servicesTargetDistro);
2097  // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
2098  // which is actually a notification. Using an exception for this
2099  // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
2100  // and in zypper.
2101  std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
2102  try {
2103  ServiceRepos( service, bind( &RepoCollector::collect, &collector, _1 ) );
2104  }
2105  catch ( const repo::ServicePluginInformalException & e )
2106  {
2107  /* ignore ServicePluginInformalException and throw later */
2108  uglyHack.first = true;
2109  uglyHack.second = e;
2110  }
2111  if ( service.ttl() != origTtl ) // repoindex.xml changed ttl
2112  {
2113  if ( !service.ttl() )
2114  service.setLrf( Date() ); // don't need lrf when zero ttl
2115  serviceModified = true;
2116  }
2118  // On the fly remember the new repo states as defined the reopoindex.xml.
2119  // Move into ServiceInfo later.
2120  ServiceInfo::RepoStates newRepoStates;
2121 
2122  // set service alias and base url for all collected repositories
2123  for_( it, collector.repos.begin(), collector.repos.end() )
2124  {
2125  // First of all: Prepend service alias:
2126  it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
2127  // set reference to the parent service
2128  it->setService( service.alias() );
2129 
2130  // remember the new parsed repo state
2131  newRepoStates[it->alias()] = *it;
2132 
2133  // - If the repo url was not set by the repoindex parser, set service's url.
2134  // - Libzypp currently has problem with separate url + path handling so just
2135  // append a path, if set, to the baseurls
2136  // - Credentials in the url authority will be extracted later, either if the
2137  // repository is added or if we check for changed urls.
2138  Pathname path;
2139  if ( !it->path().empty() )
2140  {
2141  if ( it->path() != "/" )
2142  path = it->path();
2143  it->setPath("");
2144  }
2145 
2146  if ( it->baseUrlsEmpty() )
2147  {
2148  Url url( service.rawUrl() );
2149  if ( !path.empty() )
2150  url.setPathName( url.getPathName() / path );
2151  it->setBaseUrl( std::move(url) );
2152  }
2153  else if ( !path.empty() )
2154  {
2155  RepoInfo::url_set urls( it->rawBaseUrls() );
2156  for ( Url & url : urls )
2157  {
2158  url.setPathName( url.getPathName() / path );
2159  }
2160  it->setBaseUrls( std::move(urls) );
2161  }
2162  }
2163 
2165  // Now compare collected repos with the ones in the system...
2166  //
2167  RepoInfoList oldRepos;
2168  getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
2169 
2171  // find old repositories to remove...
2172  for_( oldRepo, oldRepos.begin(), oldRepos.end() )
2173  {
2174  if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
2175  {
2176  if ( oldRepo->enabled() )
2177  {
2178  // Currently enabled. If this was a user modification remember the state.
2179  const auto & last = service.repoStates().find( oldRepo->alias() );
2180  if ( last != service.repoStates().end() && ! last->second.enabled )
2181  {
2182  DBG << "Service removes user enabled repo " << oldRepo->alias() << endl;
2183  service.addRepoToEnable( oldRepo->alias() );
2184  serviceModified = true;
2185  }
2186  else
2187  DBG << "Service removes enabled repo " << oldRepo->alias() << endl;
2188  }
2189  else
2190  DBG << "Service removes disabled repo " << oldRepo->alias() << endl;
2191 
2192  removeRepository( *oldRepo );
2193  }
2194  }
2195 
2197  // create missing repositories and modify existing ones if needed...
2198  UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
2199  for_( it, collector.repos.begin(), collector.repos.end() )
2200  {
2201  // User explicitly requested the repo being enabled?
2202  // User explicitly requested the repo being disabled?
2203  // And hopefully not both ;) If so, enable wins.
2204 
2205  TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request
2206  DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl;
2207 
2208  if ( options_r.testFlag( RefreshService_restoreStatus ) )
2209  {
2210  DBG << "Opt RefreshService_restoreStatus " << it->alias() << endl;
2211  // this overrides any pending request!
2212  // Remove from enable request list.
2213  // NOTE: repoToDisable is handled differently.
2214  // It gets cleared on each refresh.
2215  service.delRepoToEnable( it->alias() );
2216  // toBeEnabled stays indeterminate!
2217  }
2218  else
2219  {
2220  if ( service.repoToEnableFind( it->alias() ) )
2221  {
2222  DBG << "User request to enable service repo " << it->alias() << endl;
2223  toBeEnabled = true;
2224  // Remove from enable request list.
2225  // NOTE: repoToDisable is handled differently.
2226  // It gets cleared on each refresh.
2227  service.delRepoToEnable( it->alias() );
2228  serviceModified = true;
2229  }
2230  else if ( service.repoToDisableFind( it->alias() ) )
2231  {
2232  DBG << "User request to disable service repo " << it->alias() << endl;
2233  toBeEnabled = false;
2234  }
2235  }
2236 
2237  RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2238  if ( oldRepo == oldRepos.end() )
2239  {
2240  // Not found in oldRepos ==> a new repo to add
2241 
2242  // Make sure the service repo is created with the appropriate enablement
2243  if ( ! indeterminate(toBeEnabled) )
2244  it->setEnabled( ( bool ) toBeEnabled );
2245 
2246  DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl;
2247  addRepository( *it );
2248  }
2249  else
2250  {
2251  // ==> an exising repo to check
2252  bool oldRepoModified = false;
2253 
2254  if ( indeterminate(toBeEnabled) )
2255  {
2256  // No user request: check for an old user modificaton otherwise follow service request.
2257  // NOTE: Assert toBeEnabled is boolean afterwards!
2258  if ( oldRepo->enabled() == it->enabled() )
2259  toBeEnabled = it->enabled(); // service requests no change to the system
2260  else if (options_r.testFlag( RefreshService_restoreStatus ) )
2261  {
2262  toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
2263  DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl;
2264  }
2265  else
2266  {
2267  const auto & last = service.repoStates().find( oldRepo->alias() );
2268  if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
2269  toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
2270  else
2271  {
2272  toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
2273  DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << endl;
2274  }
2275  }
2276  }
2277 
2278  // changed enable?
2279  if ( toBeEnabled == oldRepo->enabled() )
2280  {
2281  DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl;
2282  }
2283  else if ( toBeEnabled )
2284  {
2285  DBG << "Service repo " << it->alias() << " gets enabled" << endl;
2286  oldRepo->setEnabled( true );
2287  oldRepoModified = true;
2288  }
2289  else
2290  {
2291  DBG << "Service repo " << it->alias() << " gets disabled" << endl;
2292  oldRepo->setEnabled( false );
2293  oldRepoModified = true;
2294  }
2295 
2296  // all other attributes follow the service request:
2297 
2298  // changed name (raw!)
2299  if ( oldRepo->rawName() != it->rawName() )
2300  {
2301  DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
2302  oldRepo->setName( it->rawName() );
2303  oldRepoModified = true;
2304  }
2305 
2306  // changed autorefresh
2307  if ( oldRepo->autorefresh() != it->autorefresh() )
2308  {
2309  DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl;
2310  oldRepo->setAutorefresh( it->autorefresh() );
2311  oldRepoModified = true;
2312  }
2313 
2314  // changed priority?
2315  if ( oldRepo->priority() != it->priority() )
2316  {
2317  DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl;
2318  oldRepo->setPriority( it->priority() );
2319  oldRepoModified = true;
2320  }
2321 
2322  // changed url?
2323  {
2324  RepoInfo::url_set newUrls( it->rawBaseUrls() );
2325  urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
2326  if ( oldRepo->rawBaseUrls() != newUrls )
2327  {
2328  DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
2329  oldRepo->setBaseUrls( std::move(newUrls) );
2330  oldRepoModified = true;
2331  }
2332  }
2333 
2334  // changed gpg check settings?
2335  // ATM only plugin services can set GPG values.
2336  if ( service.type() == ServiceType::PLUGIN )
2337  {
2338  TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
2339  TriBool ngpg[3];
2340  oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
2341  it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
2342 #define Z_CHKGPG(I,N) \
2343  if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
2344  { \
2345  DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
2346  oldRepo->set##N##Check( ngpg[I] ); \
2347  oldRepoModified = true; \
2348  }
2349  Z_CHKGPG( 0, Gpg );
2350  Z_CHKGPG( 1, RepoGpg );
2351  Z_CHKGPG( 2, PkgGpg );
2352 #undef Z_CHKGPG
2353  }
2354 
2355  // save if modified:
2356  if ( oldRepoModified )
2357  {
2358  modifyRepository( oldRepo->alias(), *oldRepo );
2359  }
2360  }
2361  }
2362 
2363  // Unlike reposToEnable, reposToDisable is always cleared after refresh.
2364  if ( ! service.reposToDisableEmpty() )
2365  {
2366  service.clearReposToDisable();
2367  serviceModified = true;
2368  }
2369 
2370  // Remember original service request for next refresh
2371  if ( service.repoStates() != newRepoStates )
2372  {
2373  service.setRepoStates( std::move(newRepoStates) );
2374  serviceModified = true;
2375  }
2376 
2378  // save service if modified: (unless a plugin service)
2379  if ( service.type() != ServiceType::PLUGIN )
2380  {
2381  if ( service.ttl() )
2382  {
2383  service.setLrf( Date::now() ); // remember last refresh
2384  serviceModified = true; // or use a cookie file
2385  }
2386 
2387  if ( serviceModified )
2388  {
2389  // write out modified service file.
2390  modifyService( service.alias(), service );
2391  }
2392  }
2393 
2394  if ( uglyHack.first )
2395  {
2396  throw( uglyHack.second ); // intentionally not ZYPP_THROW
2397  }
2398  }
2399 
2401 
2402  void RepoManager::Impl::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
2403  {
2404  MIL << "Going to modify service " << oldAlias << endl;
2405 
2406  // we need a writable copy to link it to the file where
2407  // it is saved if we modify it
2408  ServiceInfo service(newService);
2409 
2410  if ( service.type() == ServiceType::PLUGIN )
2411  {
2413  }
2414 
2415  const ServiceInfo & oldService = getService(oldAlias);
2416 
2417  Pathname location = oldService.filepath();
2418  if( location.empty() )
2419  {
2420  ZYPP_THROW(ServiceException( oldService, _("Can't figure out where the service is stored.") ));
2421  }
2422 
2423  // remember: there may multiple services being defined in one file:
2424  ServiceSet tmpSet;
2425  parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2426 
2427  filesystem::assert_dir(location.dirname());
2428  std::ofstream file(location.c_str());
2429  for_(it, tmpSet.begin(), tmpSet.end())
2430  {
2431  if( *it != oldAlias )
2432  it->dumpAsIniOn(file);
2433  }
2434  service.dumpAsIniOn(file);
2435  file.close();
2436  service.setFilepath(location);
2437 
2438  _services.erase(oldAlias);
2439  _services.insert(service);
2440  // check for credentials in Urls
2441  UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
2442 
2443 
2444  // changed properties affecting also repositories
2445  if ( oldAlias != service.alias() // changed alias
2446  || oldService.enabled() != service.enabled() ) // changed enabled status
2447  {
2448  std::vector<RepoInfo> toModify;
2449  getRepositoriesInService(oldAlias, std::back_inserter(toModify));
2450  for_( it, toModify.begin(), toModify.end() )
2451  {
2452  if ( oldService.enabled() != service.enabled() )
2453  {
2454  if ( service.enabled() )
2455  {
2456  // reset to last refreshs state
2457  const auto & last = service.repoStates().find( it->alias() );
2458  if ( last != service.repoStates().end() )
2459  it->setEnabled( last->second.enabled );
2460  }
2461  else
2462  it->setEnabled( false );
2463  }
2464 
2465  if ( oldAlias != service.alias() )
2466  it->setService(service.alias());
2467 
2468  modifyRepository(it->alias(), *it);
2469  }
2470  }
2471 
2473  }
2474 
2476 
2478  {
2479  try
2480  {
2481  MediaSetAccess access(url);
2482  if ( access.doesFileExist("/repo/repoindex.xml") )
2483  return repo::ServiceType::RIS;
2484  }
2485  catch ( const media::MediaException &e )
2486  {
2487  ZYPP_CAUGHT(e);
2488  // TranslatorExplanation '%s' is an URL
2489  RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
2490  enew.remember(e);
2491  ZYPP_THROW(enew);
2492  }
2493  catch ( const Exception &e )
2494  {
2495  ZYPP_CAUGHT(e);
2496  // TranslatorExplanation '%s' is an URL
2497  Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
2498  enew.remember(e);
2499  ZYPP_THROW(enew);
2500  }
2501 
2502  return repo::ServiceType::NONE;
2503  }
2504 
2506  //
2507  // CLASS NAME : RepoManager
2508  //
2510 
2512  : _pimpl( new Impl(opt) )
2513  {}
2514 
2516  {}
2517 
2519  { return _pimpl->repoEmpty(); }
2520 
2522  { return _pimpl->repoSize(); }
2523 
2525  { return _pimpl->repoBegin(); }
2526 
2528  { return _pimpl->repoEnd(); }
2529 
2530  RepoInfo RepoManager::getRepo( const std::string & alias ) const
2531  { return _pimpl->getRepo( alias ); }
2532 
2533  bool RepoManager::hasRepo( const std::string & alias ) const
2534  { return _pimpl->hasRepo( alias ); }
2535 
2536  std::string RepoManager::makeStupidAlias( const Url & url_r )
2537  {
2538  std::string ret( url_r.getScheme() );
2539  if ( ret.empty() )
2540  ret = "repo-";
2541  else
2542  ret += "-";
2543 
2544  std::string host( url_r.getHost() );
2545  if ( ! host.empty() )
2546  {
2547  ret += host;
2548  ret += "-";
2549  }
2550 
2551  static Date::ValueType serial = Date::now();
2552  ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8);
2553  return ret;
2554  }
2555 
2557  { return _pimpl->metadataStatus( info ); }
2558 
2560  { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
2561 
2563  { return _pimpl->metadataPath( info ); }
2564 
2566  { return _pimpl->packagesPath( info ); }
2567 
2569  { return _pimpl->refreshMetadata( info, policy, progressrcv ); }
2570 
2571  void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2572  { return _pimpl->cleanMetadata( info, progressrcv ); }
2573 
2574  void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2575  { return _pimpl->cleanPackages( info, progressrcv ); }
2576 
2578  { return _pimpl->cacheStatus( info ); }
2579 
2580  void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
2581  { return _pimpl->buildCache( info, policy, progressrcv ); }
2582 
2583  void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2584  { return _pimpl->cleanCache( info, progressrcv ); }
2585 
2586  bool RepoManager::isCached( const RepoInfo &info ) const
2587  { return _pimpl->isCached( info ); }
2588 
2589  void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2590  { return _pimpl->loadFromCache( info, progressrcv ); }
2591 
2593  { return _pimpl->cleanCacheDirGarbage( progressrcv ); }
2594 
2595  repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const
2596  { return _pimpl->probe( url, path ); }
2597 
2599  { return _pimpl->probe( url ); }
2600 
2601  void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2602  { return _pimpl->addRepository( info, progressrcv ); }
2603 
2605  { return _pimpl->addRepositories( url, progressrcv ); }
2606 
2607  void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
2608  { return _pimpl->removeRepository( info, progressrcv ); }
2609 
2610  void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv )
2611  { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
2612 
2613  RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv )
2614  { return _pimpl->getRepositoryInfo( alias, progressrcv ); }
2615 
2617  { return _pimpl->getRepositoryInfo( url, urlview, progressrcv ); }
2618 
2620  { return _pimpl->serviceEmpty(); }
2621 
2623  { return _pimpl->serviceSize(); }
2624 
2626  { return _pimpl->serviceBegin(); }
2627 
2629  { return _pimpl->serviceEnd(); }
2630 
2631  ServiceInfo RepoManager::getService( const std::string & alias ) const
2632  { return _pimpl->getService( alias ); }
2633 
2634  bool RepoManager::hasService( const std::string & alias ) const
2635  { return _pimpl->hasService( alias ); }
2636 
2638  { return _pimpl->probeService( url ); }
2639 
2640  void RepoManager::addService( const std::string & alias, const Url& url )
2641  { return _pimpl->addService( alias, url ); }
2642 
2643  void RepoManager::addService( const ServiceInfo & service )
2644  { return _pimpl->addService( service ); }
2645 
2646  void RepoManager::removeService( const std::string & alias )
2647  { return _pimpl->removeService( alias ); }
2648 
2649  void RepoManager::removeService( const ServiceInfo & service )
2650  { return _pimpl->removeService( service ); }
2651 
2653  { return _pimpl->refreshServices( options_r ); }
2654 
2655  void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2656  { return _pimpl->refreshService( alias, options_r ); }
2657 
2658  void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
2659  { return _pimpl->refreshService( service, options_r ); }
2660 
2661  void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service )
2662  { return _pimpl->modifyService( oldAlias, service ); }
2663 
2665 
2666  std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
2667  { return str << *obj._pimpl; }
2668 
2670 } // namespace zypp
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:358
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:354
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:350
Interface to gettext.
#define PL_(MSG1, MSG2, N)
Definition: Gettext.h:30
#define _(MSG)
Definition: Gettext.h:29
#define DBG
Definition: Logger.h:63
#define MIL
Definition: Logger.h:64
#define ERR
Definition: Logger.h:66
#define WAR
Definition: Logger.h:65
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:203
Url url
Definition: MediaCurl.cc:199
#define Z_CHKGPG(I, N)
const Pathname & _root
Definition: RepoManager.cc:143
ServiceSet & _services
Definition: RepoManager.cc:450
std::string targetDistro
Definition: RepoManager.cc:278
#define OPT_PROGRESS
Definition: RepoManager.cc:61
#define OUTS(X)
media::MediaAccessId _mid
Definition: RepoManager.cc:185
RepoInfoList repos
Definition: RepoManager.cc:277
scoped_ptr< media::CredentialManager > _cmPtr
Definition: RepoManager.cc:144
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
void resetDispose()
Set no dispose function.
Definition: AutoDispose.h:162
Progress callback from another progress.
Definition: ProgressData.h:391
Store and operate on date (time_t).
Definition: Date.h:33
time_t Duration
Definition: Date.h:39
static const ValueType day
Definition: Date.h:44
time_t ValueType
Definition: Date.h:38
static Date now()
Return the current time.
Definition: Date.h:78
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:188
static const std::string & sha1()
sha1
Definition: Digest.cc:47
Base class for Exception.
Definition: Exception.h:144
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
std::string asUserString() const
Translated error message as string suitable for the user.
Definition: Exception.cc:82
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition: Exception.cc:125
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:105
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
int close()
Wait for the progamm to complete.
const std::string & command() const
The command we're executing.
Writing the zypp history file.
Definition: HistoryLog.h:56
void modifyRepository(const RepoInfo &oldrepo, const RepoInfo &newrepo)
Log certain modifications to a repository.
Definition: HistoryLog.cc:312
void addRepository(const RepoInfo &repo)
Log a newly added repository.
Definition: HistoryLog.cc:289
void removeRepository(const RepoInfo &repo)
Log recently removed repository.
Definition: HistoryLog.cc:301
Media access layer responsible for handling files distributed on a set of media with media change and...
Pathname provideFile(const OnMediaLocation &resource, ProvideFileOptions options=PROVIDE_DEFAULT, const Pathname &deltafile=Pathname())
Provides a file from a media location.
bool doesFileExist(const Pathname &file, unsigned media_nr=1)
Checks if a file exists on the specified media, with user callbacks.
Maintain [min,max] and counter (value) for progress counting.
Definition: ProgressData.h:131
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
Definition: ProgressData.h:226
bool toMax()
Set counter value to current max value (unless no range).
Definition: ProgressData.h:273
void name(const std::string &name_r)
Set counter name.
Definition: ProgressData.h:222
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
Definition: ProgressData.h:139
bool toMin()
Set counter value to current min value.
Definition: ProgressData.h:269
bool set(value_type val_r)
Set new counter value.
Definition: ProgressData.h:246
value_type val() const
Definition: ProgressData.h:295
What is known about a repository.
Definition: RepoInfo.h:72
std::list< Url > url_set
Definition: RepoInfo.h:103
void setBaseUrl(const Url &url)
Clears current base URL list and adds url.
Definition: RepoInfo.cc:496
repo::RepoType type() const
Type of repository,.
Definition: RepoInfo.cc:542
urls_size_type baseUrlsSize() const
number of repository urls
Definition: RepoInfo.cc:593
Url url() const
Pars pro toto: The first repository url.
Definition: RepoInfo.h:131
static const RepoInfo noRepo
Represents no Repository (one with an empty alias).
Definition: RepoInfo.h:80
urls_const_iterator baseUrlsEnd() const
iterator that points at end of repository urls
Definition: RepoInfo.cc:590
void setPackagesPath(const Pathname &path)
set the path where the local packages are stored
Definition: RepoInfo.cc:518
virtual std::ostream & dumpAsIniOn(std::ostream &str) const
Write this RepoInfo object into str in a .repo file format.
Definition: RepoInfo.cc:786
Pathname path() const
Repository path.
Definition: RepoInfo.cc:575
url_set baseUrls() const
The complete set of repository urls.
Definition: RepoInfo.cc:569
void setProbedType(const repo::RepoType &t) const
This allows to adjust the RepoType lazy, from NONE to some probed value, even for const objects.
Definition: RepoInfo.cc:511
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:587
void setMetadataPath(const Pathname &path)
Set the path where the local metadata is stored.
Definition: RepoInfo.cc:515
transform_iterator< repo::RepoVariablesUrlReplacer, url_set::const_iterator > urls_const_iterator
Definition: RepoInfo.h:105
void setType(const repo::RepoType &t)
set the repository type
Definition: RepoInfo.cc:508
creates and provides information about known sources.
Definition: RepoManager.h:106
bool hasRepo(const std::string &alias) const
Return whether there is a known repository for alias.
ServiceSet::const_iterator ServiceConstIterator
Definition: RepoManager.h:115
void cleanCacheDirGarbage(const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove any subdirectories of cache directories which no longer belong to any of known repositories.
void cleanMetadata(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local metadata.
bool serviceEmpty() const
Gets true if no service is in RepoManager (so no one in specified location)
bool hasService(const std::string &alias) const
Return whether there is a known service for alias.
RefreshCheckStatus
Possibly return state of checkIfRefreshMEtadata function.
Definition: RepoManager.h:196
RepoSet::const_iterator RepoConstIterator
Definition: RepoManager.h:120
void addService(const std::string &alias, const Url &url)
Adds new service by it's alias and url.
bool isCached(const RepoInfo &info) const
Whether a repository exists in cache.
void removeService(const std::string &alias)
Removes service specified by its name.
RepoManager(const RepoManagerOptions &options=RepoManagerOptions())
RepoInfo getRepo(const std::string &alias) const
Find RepoInfo by alias or return RepoInfo::noRepo.
repo::ServiceType probeService(const Url &url) const
Probe the type or the service.
RWCOW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: RepoManager.h:698
void cleanCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
clean local cache
void refreshServices(const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refreshes all enabled services.
void addRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds a repository to the list of known repositories.
bool repoEmpty() const
Pathname metadataPath(const RepoInfo &info) const
Path where the metadata is downloaded and kept.
ServiceSet::size_type ServiceSizeType
Definition: RepoManager.h:116
std::set< RepoInfo > RepoSet
RepoInfo typedefs.
Definition: RepoManager.h:119
Pathname packagesPath(const RepoInfo &info) const
Path where the rpm packages are downloaded and kept.
RepoStatus cacheStatus(const RepoInfo &info) const
Status of metadata cache.
void addRepositories(const Url &url, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds repositores from a repo file to the list of known repositories.
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy=RefreshIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local raw cache.
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refresh specific service.
ServiceConstIterator serviceEnd() const
Iterator to place behind last service in internal storage.
ServiceConstIterator serviceBegin() const
Iterator to first service in internal storage.
RepoSizeType repoSize() const
void modifyRepository(const std::string &alias, const RepoInfo &newinfo, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Modify repository attributes.
void removeRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove the best matching repository from known repos list.
RepoInfo getRepositoryInfo(const std::string &alias, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Find a matching repository info.
ServiceSizeType serviceSize() const
Gets count of service in RepoManager (in specified location)
RepoSet::size_type RepoSizeType
Definition: RepoManager.h:121
ServiceInfo getService(const std::string &alias) const
Finds ServiceInfo by alias or return ServiceInfo::noService.
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy=RefreshIfNeeded)
Checks whether to refresh metadata for specified repository and url.
RepoConstIterator repoBegin() const
void buildCache(const RepoInfo &info, CacheBuildPolicy policy=BuildIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local cache.
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
Definition: RepoManager.h:150
void loadFromCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Load resolvables into the pool.
std::set< ServiceInfo > ServiceSet
ServiceInfo typedefs.
Definition: RepoManager.h:111
void cleanPackages(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local package cache.
RepoConstIterator repoEnd() const
RepoStatus metadataStatus(const RepoInfo &info) const
Status of local metadata.
void modifyService(const std::string &oldAlias, const ServiceInfo &service)
Modifies service file (rewrites it with new values) and underlying repositories if needed.
static std::string makeStupidAlias(const Url &url_r=Url())
Some stupid string but suitable as alias for your url if nothing better is available.
repo::RepoType probe(const Url &url, const Pathname &path) const
Probe repo metadata type.
Track changing files or directories.
Definition: RepoStatus.h:39
static RepoStatus fromCookieFile(const Pathname &path)
Reads the status from a cookie file.
Definition: RepoStatus.cc:108
Date timestamp() const
The time the data were changed the last time.
Definition: RepoStatus.cc:139
bool empty() const
Whether the status is empty (default constucted)
Definition: RepoStatus.cc:136
void saveToCookieFile(const Pathname &path_r) const
Save the status information to a cookie file.
Definition: RepoStatus.cc:126
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
Definition: Repository.cc:37
void eraseFromPool()
Remove this Repository from it's Pool.
Definition: Repository.cc:297
Service data.
Definition: ServiceInfo.h:37
repo::ServiceType type() const
Service type.
Definition: ServiceInfo.cc:108
Date::Duration ttl() const
Sugested TTL between two metadata auto-refreshs.
Definition: ServiceInfo.cc:112
void setLrf(Date lrf_r)
Set date of last refresh.
Definition: ServiceInfo.cc:117
Date lrf() const
Date of last refresh (if known).
Definition: ServiceInfo.cc:116
bool repoToDisableFind(const std::string &alias_r) const
Whether alias_r is mentioned in ReposToDisable.
Definition: ServiceInfo.cc:145
bool repoToEnableFind(const std::string &alias_r) const
Whether alias_r is mentioned in ReposToEnable.
Definition: ServiceInfo.cc:124
const RepoStates & repoStates() const
Access the remembered repository states.
Definition: ServiceInfo.cc:161
Url url() const
The service url.
Definition: ServiceInfo.cc:99
void setProbedType(const repo::ServiceType &t) const
Lazy init service type.
Definition: ServiceInfo.cc:110
std::map< std::string, RepoState > RepoStates
Definition: ServiceInfo.h:185
Url rawUrl() const
The service raw url (no variables replaced)
Definition: ServiceInfo.cc:102
void addRepoToEnable(const std::string &alias_r)
Add alias_r to the set of ReposToEnable.
Definition: ServiceInfo.cc:127
void clearReposToDisable()
Clear the set of ReposToDisable.
Definition: ServiceInfo.cc:157
void delRepoToEnable(const std::string &alias_r)
Remove alias_r from the set of ReposToEnable.
Definition: ServiceInfo.cc:133
virtual std::ostream & dumpAsIniOn(std::ostream &str) const
Writes ServiceInfo to stream in ".service" format.
Definition: ServiceInfo.cc:173
void setRepoStates(RepoStates newStates_r)
Remember a new set of repository states.
Definition: ServiceInfo.cc:162
static const ServiceInfo noService
Represents an empty service.
Definition: ServiceInfo.h:61
bool reposToDisableEmpty() const
Definition: ServiceInfo.cc:140
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: Target.cc:105
Url manipulation class.
Definition: Url.h:88
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:527
std::string asCompleteString() const
Returns a complete string representation of the Url object.
Definition: Url.cc:499
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:582
unsigned repo_refresh_delay() const
Amount of time in minutes that must pass before another refresh.
Definition: ZConfig.cc:965
bool repo_add_probe() const
Whether repository urls should be probed.
Definition: ZConfig.cc:962
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:125
std::string receiveLine()
Read one line from the input stream.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:248
time_t mtime() const
Definition: PathInfo.h:376
bool userMayRX() const
Definition: PathInfo.h:350
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:123
const std::string & asString() const
String representation.
Definition: Pathname.h:90
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:127
bool empty() const
Test for an empty path.
Definition: Pathname.h:113
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:235
const char * c_str() const
String representation.
Definition: Pathname.h:109
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:171
static TmpDir makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition: TmpPath.cc:287
Pathname path() const
Definition: TmpPath.cc:146
Just inherits Exception to separate media exceptions.
Read service data from a .service file.
Repository already exists and some unique attribute can't be duplicated.
Exception for repository handling.
Definition: RepoException.h:38
std::string label() const
Label for use in messages for the user interface.
void setFilepath(const Pathname &filename)
set the path to the .repo file
void setAlias(const std::string &alias)
set the repository alias
Definition: RepoInfoBase.cc:94
Pathname filepath() const
File where this repo was read from.
bool enabled() const
If enabled is false, then this repository must be ignored as if does not exists, except when checking...
std::string alias() const
unique identifier for this source.
Thrown when the repo alias is found to be invalid.
thrown when it was impossible to determine an alias for this repo.
Definition: RepoException.h:92
thrown when it was impossible to determine one url for this repo.
Definition: RepoException.h:79
The repository cache is not built yet so you can't create the repostories from the cache.
Definition: RepoException.h:66
thrown when it was impossible to match a repository
thrown when it was impossible to determine this repo type.
Service already exists and some unique attribute can't be duplicated.
Base Exception for service handling.
Thrown when the repo alias is found to be invalid.
Service without alias was used in an operation.
Service has no or invalid url defined.
Service plugin has trouble providing the metadata but this should not be treated as error.
Retrieval of repository list for a service.
Definition: ServiceRepos.h:26
Downloader for SUSETags (YaST2) repositories Encapsulates all the knowledge of which files have to be...
Definition: Downloader.h:35
RepoStatus status(MediaSetAccess &media)
Status of the remote repository.
Definition: Downloader.cc:36
Downloader for YUM (rpm-nmd) repositories Encapsulates all the knowledge of which files have to be do...
Definition: Downloader.h:42
RepoStatus status(MediaSetAccess &media)
Status of the remote repository.
Definition: Downloader.cc:38
Lightweight repository attribute value lookup.
Definition: LookupAttr.h:258
void reposErase(const std::string &alias_r)
Remove a Repository named alias_r.
Definition: Pool.h:110
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:164
static Pool instance()
Singleton ctor.
Definition: Pool.h:53
static const SolvAttr repositoryToolVersion
Definition: SolvAttr.h:173
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:30
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
Definition: RepoManager.cc:71
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:589
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:653
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:413
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
int touch(const Pathname &path)
Change file's modification and access times.
Definition: PathInfo.cc:1157
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition: PathInfo.cc:709
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:50
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:29
std::ostream & operator<<(std::ostream &str, const DeltaCandidates &obj)
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition: Pool.cc:263
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:328
std::string numstring(char n, int w=0)
Definition: String.h:305
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition: Regex.h:70
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:445
std::string hexstring(char n, int w=4)
Definition: String.h:340
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
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:457
std::ostream & operator<<(std::ostream &str, const Exception &obj)
Definition: Exception.cc:147
static bool warning(const std::string &msg_r, const UserData &userData_r=UserData())
send warning text
static bool error(const std::string &msg_r, const UserData &userData_r=UserData())
send error text
Repo manager settings.
Definition: RepoManager.h:54
static RepoManagerOptions makeTestSetup(const Pathname &root_r)
Test setup adjusting all paths to be located below one root_r directory.
Definition: RepoManager.cc:492
Pathname rootDir
remembers root_r value for later use
Definition: RepoManager.h:96
Pathname repoPackagesCachePath
Definition: RepoManager.h:82
RepoManagerOptions(const Pathname &root_r=Pathname())
Default ctor following ZConfig global settings.
Definition: RepoManager.cc:478
RepoManager implementation.
Definition: RepoManager.cc:527
RepoSizeType repoSize() const
Definition: RepoManager.cc:582
void saveService(ServiceInfo &service) const
Definition: RepoManager.cc:731
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r)
void addService(const ServiceInfo &service)
repo::ServiceType probeService(const Url &url) const
Impl * clone() const
clone for RWCOW_pointer
Definition: RepoManager.cc:720
bool hasRepo(const std::string &alias) const
Definition: RepoManager.cc:586
bool serviceEmpty() const
Definition: RepoManager.cc:641
void refreshServices(const RefreshServiceOptions &options_r)
std::string generateFilename(const ServiceInfo &info) const
Definition: RepoManager.cc:682
RepoInfo getRepositoryInfo(const Url &url, const url::ViewOption &urlview, OPT_PROGRESS)
RepoManagerOptions _options
Definition: RepoManager.cc:711
std::ostream & operator<<(std::ostream &str, const RepoManager::Impl &obj)
Stream output.
Definition: RepoManager.cc:726
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy, OPT_PROGRESS)
std::string generateFilename(const RepoInfo &info) const
Definition: RepoManager.cc:679
RepoConstIterator repoEnd() const
Definition: RepoManager.cc:584
void buildCache(const RepoInfo &info, CacheBuildPolicy policy, OPT_PROGRESS)
ServiceSizeType serviceSize() const
Definition: RepoManager.cc:642
void addRepository(const RepoInfo &info, OPT_PROGRESS)
void loadFromCache(const RepoInfo &info, OPT_PROGRESS)
void addService(const std::string &alias, const Url &url)
Definition: RepoManager.cc:657
void removeService(const std::string &alias)
void getRepositoriesInService(const std::string &alias, OutputIterator out) const
Definition: RepoManager.cc:695
void cleanMetadata(const RepoInfo &info, OPT_PROGRESS)
RepoStatus cacheStatus(const RepoInfo &info) const
Definition: RepoManager.cc:624
void removeRepository(const RepoInfo &info, OPT_PROGRESS)
Pathname packagesPath(const RepoInfo &info) const
Definition: RepoManager.cc:599
void cleanPackages(const RepoInfo &info, OPT_PROGRESS)
RepoConstIterator repoBegin() const
Definition: RepoManager.cc:583
void addRepositories(const Url &url, OPT_PROGRESS)
ServiceInfo getService(const std::string &alias) const
Definition: RepoManager.cc:649
void modifyService(const std::string &oldAlias, const ServiceInfo &newService)
repo::RepoType probeCache(const Pathname &path_r) const
Probe Metadata in a local cache directory.
ServiceConstIterator serviceEnd() const
Definition: RepoManager.cc:644
RepoInfo getRepositoryInfo(const std::string &alias, OPT_PROGRESS)
void touchIndexFile(const RepoInfo &info)
Definition: RepoManager.cc:935
Impl(const RepoManagerOptions &opt)
Definition: RepoManager.cc:529
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy)
Definition: RepoManager.cc:972
Pathname metadataPath(const RepoInfo &info) const
Definition: RepoManager.cc:596
bool isCached(const RepoInfo &info) const
Definition: RepoManager.cc:621
DefaultIntegral< bool, false > _reposDirty
Definition: RepoManager.cc:715
void cleanCache(const RepoInfo &info, OPT_PROGRESS)
void removeService(const ServiceInfo &service)
Definition: RepoManager.cc:661
void setCacheStatus(const RepoInfo &info, const RepoStatus &status)
Definition: RepoManager.cc:685
ServiceConstIterator serviceBegin() const
Definition: RepoManager.cc:643
void refreshService(const ServiceInfo &service, const RefreshServiceOptions &options_r)
Definition: RepoManager.cc:667
void cleanCacheDirGarbage(OPT_PROGRESS)
const RepoSet & repos() const
Definition: RepoManager.cc:707
repo::RepoType probe(const Url &url, const Pathname &path=Pathname()) const
Probe the metadata type of a repository located at url.
RepoStatus metadataStatus(const RepoInfo &info) const
Definition: RepoManager.cc:900
RepoInfo getRepo(const std::string &alias) const
Definition: RepoManager.cc:589
Pathname generateNonExistingName(const Pathname &dir, const std::string &basefilename) const
Generate a non existing filename in a directory, using a base name.
Definition: RepoManager.cc:765
void modifyRepository(const std::string &alias, const RepoInfo &newinfo_r, OPT_PROGRESS)
bool hasService(const std::string &alias) const
Definition: RepoManager.cc:646
Functor thats filter RepoInfo by service which it belongs to.
Definition: RepoManager.h:642
Temporarily disable MediaChangeReport Sometimes helpful to suppress interactive messages connected to...
Repository type enumeration.
Definition: RepoType.h:28
static const RepoType YAST2
Definition: RepoType.h:30
Type toEnum() const
Definition: RepoType.h:48
static const RepoType RPMMD
Definition: RepoType.h:29
static const RepoType NONE
Definition: RepoType.h:32
static const RepoType RPMPLAINDIR
Definition: RepoType.h:31
Service type enumeration.
Definition: ServiceType.h:27
static const ServiceType NONE
No service set.
Definition: ServiceType.h:34
static const ServiceType RIS
Repository Index Service (RIS) (formerly known as 'Novell Update' (NU) service)
Definition: ServiceType.h:32
static const ServiceType PLUGIN
Plugin services are scripts installed on your system that provide the package manager with repositori...
Definition: ServiceType.h:43
Format with (N)o (A)rgument (C)heck.
Definition: String.h:280
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
Url::asString() view options.
Definition: UrlBase.h:40