libzypp 17.25.7
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
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>
40#include <zypp/ManagedFile.h>
41
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
57using std::endl;
58using std::string;
59using namespace zypp::repo;
60
61#define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc()
62
64namespace 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:
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::Format(_("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::Format(_("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() )
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() )
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 {
460
461 DBG << "reading repo file " << repo_file << ", local path: " << local << endl;
462
463 return repositories_in_file(local);
464 }
465
467 //
468 // class RepoManagerOptions
469 //
471
473 {
475 repoRawCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoMetadataPath() );
476 repoSolvCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoSolvfilesPath() );
477 repoPackagesCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoPackagesPath() );
482
483 rootDir = root_r;
484 }
485
487 {
489 ret.repoCachePath = root_r;
490 ret.repoRawCachePath = root_r/"raw";
491 ret.repoSolvCachePath = root_r/"solv";
492 ret.repoPackagesCachePath = root_r/"packages";
493 ret.knownReposPath = root_r/"repos.d";
494 ret.knownServicesPath = root_r/"services.d";
495 ret.pluginsPath = root_r/"plugins";
496 ret.rootDir = root_r;
497 return ret;
498 }
499
500 std:: ostream & operator<<( std::ostream & str, const RepoManagerOptions & obj )
501 {
502#define OUTS(X) str << " " #X "\t" << obj.X << endl
503 str << "RepoManagerOptions (" << obj.rootDir << ") {" << endl;
504 OUTS( repoRawCachePath );
505 OUTS( repoSolvCachePath );
506 OUTS( repoPackagesCachePath );
507 OUTS( knownReposPath );
508 OUTS( knownServicesPath );
509 OUTS( pluginsPath );
510 str << "}" << endl;
511#undef OUTS
512 return str;
513 }
514
521 {
522 public:
524 : _options(opt)
525 {
528 }
529
531 {
532 // trigger appdata refresh if some repos change
534 && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
535 {
536 try {
537 std::list<Pathname> entries;
538 filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
539 if ( ! entries.empty() )
540 {
542 cmd.push_back( "<" ); // discard stdin
543 cmd.push_back( ">" ); // discard stdout
544 cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
545 for ( const auto & rinfo : repos() )
546 {
547 if ( ! rinfo.enabled() )
548 continue;
549 cmd.push_back( "-R" );
550 cmd.push_back( rinfo.alias() );
551 cmd.push_back( "-t" );
552 cmd.push_back( rinfo.type().asString() );
553 cmd.push_back( "-p" );
554 cmd.push_back( rinfo.metadataPath().asString() );
555 }
556
557 for_( it, entries.begin(), entries.end() )
558 {
559 PathInfo pi( *it );
560 //DBG << "/tmp/xx ->" << pi << endl;
561 if ( pi.isFile() && pi.userMayRX() )
562 {
563 // trigger plugin
564 cmd[2] = pi.asString(); // [2] - PROGRAM
566 }
567 }
568 }
569 }
570 catch (...) {} // no throw in dtor
571 }
572 }
573
574 public:
575 bool repoEmpty() const { return repos().empty(); }
576 RepoSizeType repoSize() const { return repos().size(); }
577 RepoConstIterator repoBegin() const { return repos().begin(); }
578 RepoConstIterator repoEnd() const { return repos().end(); }
579
580 bool hasRepo( const std::string & alias ) const
581 { return foundAliasIn( alias, repos() ); }
582
583 RepoInfo getRepo( const std::string & alias ) const
584 {
585 RepoConstIterator it( findAlias( alias, repos() ) );
586 return it == repos().end() ? RepoInfo::noRepo : *it;
587 }
588
589 public:
590 Pathname metadataPath( const RepoInfo & info ) const
591 { return rawcache_path_for_repoinfo( _options, info ); }
592
593 Pathname packagesPath( const RepoInfo & info ) const
594 { return packagescache_path_for_repoinfo( _options, info ); }
595
596 RepoStatus metadataStatus( const RepoInfo & info ) const;
597
599
601
602 void cleanMetadata( const RepoInfo & info, OPT_PROGRESS );
603
604 void cleanPackages( const RepoInfo & info, OPT_PROGRESS );
605
606 void buildCache( const RepoInfo & info, CacheBuildPolicy policy, OPT_PROGRESS );
607
608 repo::RepoType probe( const Url & url, const Pathname & path = Pathname() ) const;
609 repo::RepoType probeCache( const Pathname & path_r ) const;
610
612
613 void cleanCache( const RepoInfo & info, OPT_PROGRESS );
614
615 bool isCached( const RepoInfo & info ) const
616 { return PathInfo(solv_path_for_repoinfo( _options, info ) / "solv").isExist(); }
617
618 RepoStatus cacheStatus( const RepoInfo & info ) const
619 { return RepoStatus::fromCookieFile(solv_path_for_repoinfo(_options, info) / "cookie"); }
620
621 void loadFromCache( const RepoInfo & info, OPT_PROGRESS );
622
623 void addRepository( const RepoInfo & info, OPT_PROGRESS );
624
625 void addRepositories( const Url & url, OPT_PROGRESS );
626
627 void removeRepository( const RepoInfo & info, OPT_PROGRESS );
628
629 void modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, OPT_PROGRESS );
630
631 RepoInfo getRepositoryInfo( const std::string & alias, OPT_PROGRESS );
633
634 public:
635 bool serviceEmpty() const { return _services.empty(); }
636 ServiceSizeType serviceSize() const { return _services.size(); }
637 ServiceConstIterator serviceBegin() const { return _services.begin(); }
638 ServiceConstIterator serviceEnd() const { return _services.end(); }
639
640 bool hasService( const std::string & alias ) const
641 { return foundAliasIn( alias, _services ); }
642
643 ServiceInfo getService( const std::string & alias ) const
644 {
645 ServiceConstIterator it( findAlias( alias, _services ) );
646 return it == _services.end() ? ServiceInfo::noService : *it;
647 }
648
649 public:
650 void addService( const ServiceInfo & service );
651 void addService( const std::string & alias, const Url & url )
652 { addService( ServiceInfo( alias, url ) ); }
653
654 void removeService( const std::string & alias );
655 void removeService( const ServiceInfo & service )
656 { removeService( service.alias() ); }
657
658 void refreshServices( const RefreshServiceOptions & options_r );
659
660 void refreshService( const std::string & alias, const RefreshServiceOptions & options_r );
661 void refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
662 { refreshService( service.alias(), options_r ); }
663
664 void modifyService( const std::string & oldAlias, const ServiceInfo & newService );
665
666 repo::ServiceType probeService( const Url & url ) const;
667
668 private:
669 void saveService( ServiceInfo & service ) const;
670
671 Pathname generateNonExistingName( const Pathname & dir, const std::string & basefilename ) const;
672
673 std::string generateFilename( const RepoInfo & info ) const
674 { return filenameFromAlias( info.alias(), "repo" ); }
675
676 std::string generateFilename( const ServiceInfo & info ) const
677 { return filenameFromAlias( info.alias(), "service" ); }
678
679 void setCacheStatus( const RepoInfo & info, const RepoStatus & status )
680 {
681 Pathname base = solv_path_for_repoinfo( _options, info );
683 status.saveToCookieFile( base / "cookie" );
684 }
685
686 void touchIndexFile( const RepoInfo & info );
687
688 template<typename OutputIterator>
689 void getRepositoriesInService( const std::string & alias, OutputIterator out ) const
690 {
691 MatchServiceAlias filter( alias );
692 std::copy( boost::make_filter_iterator( filter, repos().begin(), repos().end() ),
693 boost::make_filter_iterator( filter, repos().end(), repos().end() ),
694 out);
695 }
696
697 private:
698 void init_knownServices();
700
701 const RepoSet & repos() const { return _reposX; }
702 RepoSet & reposManip() { if ( ! _reposDirty ) _reposDirty = true; return _reposX; }
703
704 private:
708
710
711 private:
712 friend Impl * rwcowClone<Impl>( const Impl * rhs );
714 Impl * clone() const
715 { return new Impl( *this ); }
716 };
718
720 inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj )
721 { return str << "RepoManager::Impl"; }
722
724
726 {
729 generateFilename( service ) );
730 service.setFilepath( servfile );
731
732 MIL << "saving service in " << servfile << endl;
733
734 std::ofstream file( servfile.c_str() );
735 if ( !file )
736 {
737 // TranslatorExplanation '%s' is a filename
738 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), servfile.c_str() )));
739 }
740 service.dumpAsIniOn( file );
741 MIL << "done" << endl;
742 }
743
760 const std::string & basefilename ) const
761 {
762 std::string final_filename = basefilename;
763 int counter = 1;
764 while ( PathInfo(dir + final_filename).isExist() )
765 {
766 final_filename = basefilename + "_" + str::numstring(counter);
767 ++counter;
768 }
769 return dir + Pathname(final_filename);
770 }
771
773
775 {
776 Pathname dir = _options.knownServicesPath;
777 std::list<Pathname> entries;
778 if (PathInfo(dir).isExist())
779 {
780 if ( filesystem::readdir( entries, dir, false ) != 0 )
781 {
782 // TranslatorExplanation '%s' is a pathname
783 ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir.c_str())));
784 }
785
786 //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
787 for_(it, entries.begin(), entries.end() )
788 {
789 parser::ServiceFileReader(*it, ServiceCollector(_services));
790 }
791 }
792
793 repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services));
794 }
795
797 namespace {
803 inline void cleanupNonRepoMetadtaFolders( const Pathname & cachePath_r,
804 const Pathname & defaultCachePath_r,
805 const std::list<std::string> & repoEscAliases_r )
806 {
807 if ( cachePath_r != defaultCachePath_r )
808 return;
809
810 std::list<std::string> entries;
811 if ( filesystem::readdir( entries, cachePath_r, false ) == 0 )
812 {
813 entries.sort();
814 std::set<std::string> oldfiles;
815 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
816 std::inserter( oldfiles, oldfiles.end() ) );
817
818 // bsc#1178966: Files or symlinks here have been created by the user
819 // for whatever purpose. It's our cache, so we purge them now before
820 // they may later conflict with directories we need.
821 PathInfo pi;
822 for ( const std::string & old : oldfiles )
823 {
824 if ( old == Repository::systemRepoAlias() ) // don't remove the @System solv file
825 continue;
826 pi( cachePath_r/old );
827 if ( pi.isDir() )
829 else
830 filesystem::unlink( pi.path() );
831 }
832 }
833 }
834 } // namespace
837 {
838 MIL << "start construct known repos" << endl;
839
840 if ( PathInfo(_options.knownReposPath).isExist() )
841 {
842 std::list<std::string> repoEscAliases;
843 std::list<RepoInfo> orphanedRepos;
844 for ( RepoInfo & repoInfo : repositories_in_dir(_options.knownReposPath) )
845 {
846 // set the metadata path for the repo
847 repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo) );
848 // set the downloaded packages path for the repo
849 repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) );
850 // remember it
851 _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
852
853 // detect orphaned repos belonging to a deleted service
854 const std::string & serviceAlias( repoInfo.service() );
855 if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
856 {
857 WAR << "Schedule orphaned service repo for deletion: " << repoInfo << endl;
858 orphanedRepos.push_back( repoInfo );
859 continue; // don't remember it in repoEscAliases
860 }
861
862 repoEscAliases.push_back(repoInfo.escaped_alias());
863 }
864
865 // Cleanup orphanded service repos:
866 if ( ! orphanedRepos.empty() )
867 {
868 for ( const auto & repoInfo : orphanedRepos )
869 {
870 MIL << "Delete orphaned service repo " << repoInfo.alias() << endl;
871 // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
872 // %1% = service name
873 // %2% = repository name
874 JobReport::warning( str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'"))
875 % repoInfo.service()
876 % repoInfo.alias() );
877 try {
878 removeRepository( repoInfo );
879 }
880 catch ( const Exception & caugth )
881 {
883 }
884 }
885 }
886
887 // delete metadata folders without corresponding repo (e.g. old tmp directories)
888 //
889 // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise
890 // we'd need somemagic file to identify zypp cache directories. Without this
891 // we may easily remove user data (zypper --pkg-cache-dir . download ...)
892 repoEscAliases.sort();
893 RepoManagerOptions defaultCache( _options.rootDir );
894 cleanupNonRepoMetadtaFolders( _options.repoRawCachePath, defaultCache.repoRawCachePath, repoEscAliases );
895 cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath, defaultCache.repoSolvCachePath, repoEscAliases );
896 cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath, defaultCache.repoPackagesCachePath, repoEscAliases );
897 }
898 MIL << "end construct known repos" << endl;
899 }
900
902
904 {
905 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
906 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
907
908 RepoType repokind = info.type();
909 // If unknown, probe the local metadata
910 if ( repokind == RepoType::NONE )
911 repokind = probeCache( productdatapath );
912
913 // NOTE: The calling code expects an empty RepoStatus being returned
914 // if the metadata cache is empty. So additioanl components like the
915 // RepoInfos status are joined after the switch IFF the status is not
916 // empty.
917 RepoStatus status;
918 switch ( repokind.toEnum() )
919 {
920 case RepoType::RPMMD_e :
921 status = RepoStatus( productdatapath/"repodata/repomd.xml") && RepoStatus( mediarootpath/"media.1/media" );
922 break;
923
924 case RepoType::YAST2_e :
925 status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" );
926 break;
927
928 case RepoType::RPMPLAINDIR_e :
929 status = RepoStatus::fromCookieFile( productdatapath/"cookie" ); // dir status at last refresh
930 break;
931
932 case RepoType::NONE_e :
933 // Return default RepoStatus in case of RepoType::NONE
934 // indicating it should be created?
935 // ZYPP_THROW(RepoUnknownTypeException());
936 break;
937 }
938
939 if ( ! status.empty() )
940 status = status && RepoStatus( info );
941
942 return status;
943 }
944
945
947 {
948 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
949
950 RepoType repokind = info.type();
951 if ( repokind.toEnum() == RepoType::NONE_e )
952 // unknown, probe the local metadata
953 repokind = probeCache( productdatapath );
954 // if still unknown, just return
955 if (repokind == RepoType::NONE_e)
956 return;
957
958 Pathname p;
959 switch ( repokind.toEnum() )
960 {
961 case RepoType::RPMMD_e :
962 p = Pathname(productdatapath + "/repodata/repomd.xml");
963 break;
964
965 case RepoType::YAST2_e :
966 p = Pathname(productdatapath + "/content");
967 break;
968
969 case RepoType::RPMPLAINDIR_e :
970 p = Pathname(productdatapath + "/cookie");
971 break;
972
973 case RepoType::NONE_e :
974 default:
975 break;
976 }
977
978 // touch the file, ignore error (they are logged anyway)
980 }
981
982
984 {
985 assert_alias(info);
986 try
987 {
988 MIL << "Check if to refresh repo " << info.alias() << " at " << url << " (" << info.type() << ")" << endl;
989
990 // first check old (cached) metadata
991 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
992 filesystem::assert_dir( mediarootpath );
993 RepoStatus oldstatus = metadataStatus( info );
994
995 if ( oldstatus.empty() )
996 {
997 MIL << "No cached metadata, going to refresh" << endl;
998 return REFRESH_NEEDED;
999 }
1000
1001 if ( url.schemeIsVolatile() )
1002 {
1003 MIL << "Never refresh CD/DVD" << endl;
1004 return REPO_UP_TO_DATE;
1005 }
1006
1007 if ( policy == RefreshForced )
1008 {
1009 MIL << "Forced refresh!" << endl;
1010 return REFRESH_NEEDED;
1011 }
1012
1013 if ( url.schemeIsLocal() )
1014 {
1016 }
1017
1018 // Check whether repo.refresh.delay applies...
1019 if ( policy != RefreshIfNeededIgnoreDelay )
1020 {
1021 // bsc#1174016: Prerequisite to skipping the refresh is that metadata
1022 // and solv cache status match. They will not, if the repos URL was
1023 // changed e.g. due to changed repovars.
1024 RepoStatus cachestatus = cacheStatus( info );
1025
1026 if ( oldstatus == cachestatus )
1027 {
1028 // difference in seconds
1029 double diff = ::difftime( (Date::ValueType)Date::now(), (Date::ValueType)oldstatus.timestamp() ) / 60;
1030 if ( diff < ZConfig::instance().repo_refresh_delay() )
1031 {
1032 if ( diff < 0 )
1033 {
1034 WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
1035 }
1036 else
1037 {
1038 MIL << "Repository '" << info.alias()
1039 << "' has been refreshed less than repo.refresh.delay ("
1041 << ") minutes ago. Advising to skip refresh" << endl;
1042 return REPO_CHECK_DELAYED;
1043 }
1044 }
1045 }
1046 else {
1047 MIL << "Metadata and solv cache don't match. Check data on server..." << endl;
1048 }
1049 }
1050
1051 repo::RepoType repokind = info.type();
1052 // if unknown: probe it
1053 if ( repokind == RepoType::NONE )
1054 repokind = probe( url, info.path() );
1055
1056 // retrieve newstatus
1057 RepoStatus newstatus;
1058 switch ( repokind.toEnum() )
1059 {
1060 case RepoType::RPMMD_e:
1061 {
1062 MediaSetAccess media( url );
1063 newstatus = RepoStatus( info ) && yum::Downloader( info, mediarootpath ).status( media );
1064 }
1065 break;
1066
1067 case RepoType::YAST2_e:
1068 {
1069 MediaSetAccess media( url );
1070 newstatus = RepoStatus( info ) && susetags::Downloader( info, mediarootpath ).status( media );
1071 }
1072 break;
1073
1074 case RepoType::RPMPLAINDIR_e:
1075 newstatus = RepoStatus( info ) && RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status
1076 break;
1077
1078 default:
1079 case RepoType::NONE_e:
1081 break;
1082 }
1083
1084 // check status
1085 if ( oldstatus == newstatus )
1086 {
1087 MIL << "repo has not changed" << endl;
1088 touchIndexFile( info );
1089 return REPO_UP_TO_DATE;
1090 }
1091 else // includes newstatus.empty() if e.g. repo format changed
1092 {
1093 MIL << "repo has changed, going to refresh" << endl;
1094 return REFRESH_NEEDED;
1095 }
1096 }
1097 catch ( const Exception &e )
1098 {
1099 ZYPP_CAUGHT(e);
1100 ERR << "refresh check failed for " << url << endl;
1101 ZYPP_RETHROW(e);
1102 }
1103
1104 return REFRESH_NEEDED; // default
1105 }
1106
1107
1109 {
1110 assert_alias(info);
1111 assert_urls(info);
1112
1113 // we will throw this later if no URL checks out fine
1114 RepoException rexception( info, PL_("Valid metadata not found at specified URL",
1115 "Valid metadata not found at specified URLs",
1116 info.baseUrlsSize() ) );
1117
1118 // Suppress (interactive) media::MediaChangeReport if we in have multiple basurls (>1)
1120 // try urls one by one
1121 for ( RepoInfo::urls_const_iterator it = info.baseUrlsBegin(); it != info.baseUrlsEnd(); ++it )
1122 {
1123 try
1124 {
1125 Url url(*it);
1126
1127 // check whether to refresh metadata
1128 // if the check fails for this url, it throws, so another url will be checked
1129 if (checkIfToRefreshMetadata(info, url, policy)!=REFRESH_NEEDED)
1130 return;
1131
1132 MIL << "Going to refresh metadata from " << url << endl;
1133
1134 // bsc#1048315: Always re-probe in case of repo format change.
1135 // TODO: Would be sufficient to verify the type and re-probe
1136 // if verification failed (or type is RepoType::NONE)
1137 repo::RepoType repokind = info.type();
1138 {
1139 repo::RepoType probed = probe( *it, info.path() );
1140 if ( repokind != probed )
1141 {
1142 repokind = probed;
1143 // update probed type only for repos in system
1144 for_( it, repoBegin(), repoEnd() )
1145 {
1146 if ( info.alias() == (*it).alias() )
1147 {
1148 RepoInfo modifiedrepo = *it;
1149 modifiedrepo.setType( repokind );
1150 // don't modify .repo in refresh.
1151 // modifyRepository( info.alias(), modifiedrepo );
1152 break;
1153 }
1154 }
1155 // Adjust the probed type in RepoInfo
1156 info.setProbedType( repokind ); // lazy init!
1157 }
1158 // no need to continue with an unknown type
1159 if ( repokind.toEnum() == RepoType::NONE_e )
1161 }
1162
1163 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1164 if( filesystem::assert_dir(mediarootpath) )
1165 {
1166 Exception ex(str::form( _("Can't create %s"), mediarootpath.c_str()) );
1167 ZYPP_THROW(ex);
1168 }
1169
1170 // create temp dir as sibling of mediarootpath
1171 filesystem::TmpDir tmpdir( filesystem::TmpDir::makeSibling( mediarootpath ) );
1172 if( tmpdir.path().empty() )
1173 {
1174 Exception ex(_("Can't create metadata cache directory."));
1175 ZYPP_THROW(ex);
1176 }
1177
1178 if ( ( repokind.toEnum() == RepoType::RPMMD_e ) ||
1179 ( repokind.toEnum() == RepoType::YAST2_e ) )
1180 {
1181 MediaSetAccess media(url);
1182 shared_ptr<repo::Downloader> downloader_ptr;
1183
1184 MIL << "Creating downloader for [ " << info.alias() << " ]" << endl;
1185
1186 if ( repokind.toEnum() == RepoType::RPMMD_e )
1187 downloader_ptr.reset(new yum::Downloader(info, mediarootpath));
1188 else
1189 downloader_ptr.reset( new susetags::Downloader(info, mediarootpath) );
1190
1197 for_( it, repoBegin(), repoEnd() )
1198 {
1199 Pathname cachepath(rawcache_path_for_repoinfo( _options, *it ));
1200 if ( PathInfo(cachepath).isExist() )
1201 downloader_ptr->addCachePath(cachepath);
1202 }
1203
1204 downloader_ptr->download( media, tmpdir.path() );
1205 }
1206 else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e )
1207 {
1208 // as substitute for real metadata remember the checksum of the directory we refreshed
1209 MediaMounter media( url );
1210 RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) ); // dir status
1211
1212 Pathname productpath( tmpdir.path() / info.path() );
1213 filesystem::assert_dir( productpath );
1214 newstatus.saveToCookieFile( productpath/"cookie" );
1215 }
1216 else
1217 {
1219 }
1220
1221 // ok we have the metadata, now exchange
1222 // the contents
1223 filesystem::exchange( tmpdir.path(), mediarootpath );
1224 if ( ! isTmpRepo( info ) )
1225 reposManip(); // remember to trigger appdata refresh
1226
1227 // we are done.
1228 return;
1229 }
1230 catch ( const Exception &e )
1231 {
1232 ZYPP_CAUGHT(e);
1233 ERR << "Trying another url..." << endl;
1234
1235 // remember the exception caught for the *first URL*
1236 // if all other URLs fail, the rexception will be thrown with the
1237 // cause of the problem of the first URL remembered
1238 if (it == info.baseUrlsBegin())
1239 rexception.remember(e);
1240 else
1241 rexception.addHistory( e.asUserString() );
1242
1243 }
1244 } // for every url
1245 ERR << "No more urls..." << endl;
1246 ZYPP_THROW(rexception);
1247 }
1248
1250
1252 {
1253 ProgressData progress(100);
1254 progress.sendTo(progressfnc);
1255
1256 filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_options, info));
1257 progress.toMax();
1258 }
1259
1260
1262 {
1263 ProgressData progress(100);
1264 progress.sendTo(progressfnc);
1265
1266 filesystem::recursive_rmdir(packagescache_path_for_repoinfo(_options, info));
1267 progress.toMax();
1268 }
1269
1270
1272 {
1273 assert_alias(info);
1274 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1275 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
1276
1277 if( filesystem::assert_dir(_options.repoCachePath) )
1278 {
1279 Exception ex(str::form( _("Can't create %s"), _options.repoCachePath.c_str()) );
1280 ZYPP_THROW(ex);
1281 }
1282 RepoStatus raw_metadata_status = metadataStatus(info);
1283 if ( raw_metadata_status.empty() )
1284 {
1285 /* if there is no cache at this point, we refresh the raw
1286 in case this is the first time - if it's !autorefresh,
1287 we may still refresh */
1288 refreshMetadata(info, RefreshIfNeeded, progressrcv );
1289 raw_metadata_status = metadataStatus(info);
1290 }
1291
1292 bool needs_cleaning = false;
1293 if ( isCached( info ) )
1294 {
1295 MIL << info.alias() << " is already cached." << endl;
1296 RepoStatus cache_status = cacheStatus(info);
1297
1298 if ( cache_status == raw_metadata_status )
1299 {
1300 MIL << info.alias() << " cache is up to date with metadata." << endl;
1301 if ( policy == BuildIfNeeded )
1302 {
1303 // On the fly add missing solv.idx files for bash completion.
1304 const Pathname & base = solv_path_for_repoinfo( _options, info);
1305 if ( ! PathInfo(base/"solv.idx").isExist() )
1306 sat::updateSolvFileIndex( base/"solv" );
1307
1308 return;
1309 }
1310 else {
1311 MIL << info.alias() << " cache rebuild is forced" << endl;
1312 }
1313 }
1314
1315 needs_cleaning = true;
1316 }
1317
1318 ProgressData progress(100);
1320 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1321 progress.name(str::form(_("Building repository '%s' cache"), info.label().c_str()));
1322 progress.toMin();
1323
1324 if (needs_cleaning)
1325 {
1326 cleanCache(info);
1327 }
1328
1329 MIL << info.alias() << " building cache..." << info.type() << endl;
1330
1331 Pathname base = solv_path_for_repoinfo( _options, info);
1332
1333 if( filesystem::assert_dir(base) )
1334 {
1335 Exception ex(str::form( _("Can't create %s"), base.c_str()) );
1336 ZYPP_THROW(ex);
1337 }
1338
1339 if( ! PathInfo(base).userMayW() )
1340 {
1341 Exception ex(str::form( _("Can't create cache at %s - no writing permissions."), base.c_str()) );
1342 ZYPP_THROW(ex);
1343 }
1344 Pathname solvfile = base / "solv";
1345
1346 // do we have type?
1347 repo::RepoType repokind = info.type();
1348
1349 // if the type is unknown, try probing.
1350 switch ( repokind.toEnum() )
1351 {
1352 case RepoType::NONE_e:
1353 // unknown, probe the local metadata
1354 repokind = probeCache( productdatapath );
1355 break;
1356 default:
1357 break;
1358 }
1359
1360 MIL << "repo type is " << repokind << endl;
1361
1362 switch ( repokind.toEnum() )
1363 {
1364 case RepoType::RPMMD_e :
1365 case RepoType::YAST2_e :
1366 case RepoType::RPMPLAINDIR_e :
1367 {
1368 // Take care we unlink the solvfile on exception
1369 ManagedFile guard( solvfile, filesystem::unlink );
1370 scoped_ptr<MediaMounter> forPlainDirs;
1371
1373 cmd.push_back( PathInfo( "/usr/bin/repo2solv" ).isFile() ? "repo2solv" : "repo2solv.sh" );
1374 // repo2solv expects -o as 1st arg!
1375 cmd.push_back( "-o" );
1376 cmd.push_back( solvfile.asString() );
1377 cmd.push_back( "-X" ); // autogenerate pattern from pattern-package
1378 // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
1379
1380 if ( repokind == RepoType::RPMPLAINDIR )
1381 {
1382 forPlainDirs.reset( new MediaMounter( info.url() ) );
1383 // recusive for plaindir as 2nd arg!
1384 cmd.push_back( "-R" );
1385 // FIXME this does only work form dir: URLs
1386 cmd.push_back( forPlainDirs->getPathName( info.path() ).c_str() );
1387 }
1388 else
1389 cmd.push_back( productdatapath.asString() );
1390
1392 std::string errdetail;
1393
1394 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1395 WAR << " " << output;
1396 if ( errdetail.empty() ) {
1397 errdetail = prog.command();
1398 errdetail += '\n';
1399 }
1400 errdetail += output;
1401 }
1402
1403 int ret = prog.close();
1404 if ( ret != 0 )
1405 {
1406 RepoException ex(str::form( _("Failed to cache repo (%d)."), ret ));
1407 ex.remember( errdetail );
1408 ZYPP_THROW(ex);
1409 }
1410
1411 // We keep it.
1412 guard.resetDispose();
1413 sat::updateSolvFileIndex( solvfile ); // content digest for zypper bash completion
1414 }
1415 break;
1416 default:
1417 ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") ));
1418 break;
1419 }
1420 // update timestamp and checksum
1421 setCacheStatus(info, raw_metadata_status);
1422 MIL << "Commit cache.." << endl;
1423 progress.toMax();
1424 }
1425
1427
1428
1436 {
1437 MIL << "going to probe the repo type at " << url << " (" << path << ")" << endl;
1438
1439 if ( url.getScheme() == "dir" && ! PathInfo( url.getPathName()/path ).isDir() )
1440 {
1441 // Handle non existing local directory in advance, as
1442 // MediaSetAccess does not support it.
1443 MIL << "Probed type NONE (not exists) at " << url << " (" << path << ")" << endl;
1444 return repo::RepoType::NONE;
1445 }
1446
1447 // prepare exception to be thrown if the type could not be determined
1448 // due to a media exception. We can't throw right away, because of some
1449 // problems with proxy servers returning an incorrect error
1450 // on ftp file-not-found(bnc #335906). Instead we'll check another types
1451 // before throwing.
1452
1453 // TranslatorExplanation '%s' is an URL
1454 RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
1455 bool gotMediaException = false;
1456 try
1457 {
1458 MediaSetAccess access(url);
1459 try
1460 {
1461 if ( access.doesFileExist(path/"/repodata/repomd.xml") )
1462 {
1463 MIL << "Probed type RPMMD at " << url << " (" << path << ")" << endl;
1464 return repo::RepoType::RPMMD;
1465 }
1466 }
1467 catch ( const media::MediaException &e )
1468 {
1469 ZYPP_CAUGHT(e);
1470 DBG << "problem checking for repodata/repomd.xml file" << endl;
1471 enew.remember(e);
1472 gotMediaException = true;
1473 }
1474
1475 try
1476 {
1477 if ( access.doesFileExist(path/"/content") )
1478 {
1479 MIL << "Probed type YAST2 at " << url << " (" << path << ")" << endl;
1480 return repo::RepoType::YAST2;
1481 }
1482 }
1483 catch ( const media::MediaException &e )
1484 {
1485 ZYPP_CAUGHT(e);
1486 DBG << "problem checking for content file" << endl;
1487 enew.remember(e);
1488 gotMediaException = true;
1489 }
1490
1491 // if it is a non-downloading URL denoting a directory
1492 if ( ! url.schemeIsDownloading() )
1493 {
1494 MediaMounter media( url );
1495 if ( PathInfo(media.getPathName()/path).isDir() )
1496 {
1497 // allow empty dirs for now
1498 MIL << "Probed type RPMPLAINDIR at " << url << " (" << path << ")" << endl;
1500 }
1501 }
1502 }
1503 catch ( const Exception &e )
1504 {
1505 ZYPP_CAUGHT(e);
1506 // TranslatorExplanation '%s' is an URL
1507 Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
1508 enew.remember(e);
1509 ZYPP_THROW(enew);
1510 }
1511
1512 if (gotMediaException)
1513 ZYPP_THROW(enew);
1514
1515 MIL << "Probed type NONE at " << url << " (" << path << ")" << endl;
1516 return repo::RepoType::NONE;
1517 }
1518
1525 {
1526 MIL << "going to probe the cached repo at " << path_r << endl;
1527
1529
1530 if ( PathInfo(path_r/"/repodata/repomd.xml").isFile() )
1531 { ret = repo::RepoType::RPMMD; }
1532 else if ( PathInfo(path_r/"/content").isFile() )
1533 { ret = repo::RepoType::YAST2; }
1534 else if ( PathInfo(path_r).isDir() )
1536
1537 MIL << "Probed cached type " << ret << " at " << path_r << endl;
1538 return ret;
1539 }
1540
1542
1544 {
1545 MIL << "Going to clean up garbage in cache dirs" << endl;
1546
1547 ProgressData progress(300);
1548 progress.sendTo(progressrcv);
1549 progress.toMin();
1550
1551 std::list<Pathname> cachedirs;
1552 cachedirs.push_back(_options.repoRawCachePath);
1553 cachedirs.push_back(_options.repoPackagesCachePath);
1554 cachedirs.push_back(_options.repoSolvCachePath);
1555
1556 for_( dir, cachedirs.begin(), cachedirs.end() )
1557 {
1558 if ( PathInfo(*dir).isExist() )
1559 {
1560 std::list<Pathname> entries;
1561 if ( filesystem::readdir( entries, *dir, false ) != 0 )
1562 // TranslatorExplanation '%s' is a pathname
1563 ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir->c_str())));
1564
1565 unsigned sdircount = entries.size();
1566 unsigned sdircurrent = 1;
1567 for_( subdir, entries.begin(), entries.end() )
1568 {
1569 // if it does not belong known repo, make it disappear
1570 bool found = false;
1571 for_( r, repoBegin(), repoEnd() )
1572 if ( subdir->basename() == r->escaped_alias() )
1573 { found = true; break; }
1574
1575 if ( ! found && ( Date::now()-PathInfo(*subdir).mtime() > Date::day ) )
1576 filesystem::recursive_rmdir( *subdir );
1577
1578 progress.set( progress.val() + sdircurrent * 100 / sdircount );
1579 ++sdircurrent;
1580 }
1581 }
1582 else
1583 progress.set( progress.val() + 100 );
1584 }
1585 progress.toMax();
1586 }
1587
1589
1590 void RepoManager::Impl::cleanCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1591 {
1592 ProgressData progress(100);
1593 progress.sendTo(progressrcv);
1594 progress.toMin();
1595
1596 MIL << "Removing raw metadata cache for " << info.alias() << endl;
1597 filesystem::recursive_rmdir(solv_path_for_repoinfo(_options, info));
1598
1599 progress.toMax();
1600 }
1601
1603
1605 {
1606 assert_alias(info);
1607 Pathname solvfile = solv_path_for_repoinfo(_options, info) / "solv";
1608
1609 if ( ! PathInfo(solvfile).isExist() )
1611
1613 try
1614 {
1615 Repository repo = sat::Pool::instance().addRepoSolv( solvfile, info );
1616 // test toolversion in order to rebuild solv file in case
1617 // it was written by a different libsolv-tool parser.
1618 const std::string & toolversion( sat::LookupRepoAttr( sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
1619 if ( toolversion != LIBSOLV_TOOLVERSION )
1620 {
1621 repo.eraseFromPool();
1622 ZYPP_THROW(Exception(str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
1623 }
1624 }
1625 catch ( const Exception & exp )
1626 {
1627 ZYPP_CAUGHT( exp );
1628 MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1629 cleanCache( info, progressrcv );
1630 buildCache( info, BuildIfNeeded, progressrcv );
1631
1632 sat::Pool::instance().addRepoSolv( solvfile, info );
1633 }
1634 }
1635
1637
1639 {
1640 assert_alias(info);
1641
1642 ProgressData progress(100);
1644 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1645 progress.name(str::form(_("Adding repository '%s'"), info.label().c_str()));
1646 progress.toMin();
1647
1648 MIL << "Try adding repo " << info << endl;
1649
1650 RepoInfo tosave = info;
1651 if ( repos().find(tosave) != repos().end() )
1653
1654 // check the first url for now
1655 if ( _options.probe )
1656 {
1657 DBG << "unknown repository type, probing" << endl;
1658 assert_urls(tosave);
1659
1660 RepoType probedtype( probe( tosave.url(), info.path() ) );
1661 if ( probedtype == RepoType::NONE )
1663 else
1664 tosave.setType(probedtype);
1665 }
1666
1667 progress.set(50);
1668
1669 // assert the directory exists
1670 filesystem::assert_dir(_options.knownReposPath);
1671
1672 Pathname repofile = generateNonExistingName(
1673 _options.knownReposPath, generateFilename(tosave));
1674 // now we have a filename that does not exists
1675 MIL << "Saving repo in " << repofile << endl;
1676
1677 std::ofstream file(repofile.c_str());
1678 if (!file)
1679 {
1680 // TranslatorExplanation '%s' is a filename
1681 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1682 }
1683
1684 tosave.dumpAsIniOn(file);
1685 tosave.setFilepath(repofile);
1686 tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1687 tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1688 {
1689 // We should fix the API as we must inject those paths
1690 // into the repoinfo in order to keep it usable.
1691 RepoInfo & oinfo( const_cast<RepoInfo &>(info) );
1692 oinfo.setFilepath(repofile);
1693 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1694 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1695 }
1696 reposManip().insert(tosave);
1697
1698 progress.set(90);
1699
1700 // check for credentials in Urls
1701 UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
1702
1703 HistoryLog(_options.rootDir).addRepository(tosave);
1704
1705 progress.toMax();
1706 MIL << "done" << endl;
1707 }
1708
1709
1711 {
1712 std::list<RepoInfo> repos = readRepoFile(url);
1713 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
1714 it != repos.end();
1715 ++it )
1716 {
1717 // look if the alias is in the known repos.
1718 for_ ( kit, repoBegin(), repoEnd() )
1719 {
1720 if ( (*it).alias() == (*kit).alias() )
1721 {
1722 ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << endl;
1724 }
1725 }
1726 }
1727
1728 std::string filename = Pathname(url.getPathName()).basename();
1729
1730 if ( filename == Pathname() )
1731 {
1732 // TranslatorExplanation '%s' is an URL
1733 ZYPP_THROW(RepoException(str::form( _("Invalid repo file name at '%s'"), url.asString().c_str() )));
1734 }
1735
1736 // assert the directory exists
1737 filesystem::assert_dir(_options.knownReposPath);
1738
1739 Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
1740 // now we have a filename that does not exists
1741 MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
1742
1743 std::ofstream file(repofile.c_str());
1744 if (!file)
1745 {
1746 // TranslatorExplanation '%s' is a filename
1747 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1748 }
1749
1750 for ( std::list<RepoInfo>::iterator it = repos.begin();
1751 it != repos.end();
1752 ++it )
1753 {
1754 MIL << "Saving " << (*it).alias() << endl;
1755 it->dumpAsIniOn(file);
1756 it->setFilepath(repofile);
1757 it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
1758 it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
1759 reposManip().insert(*it);
1760
1761 HistoryLog(_options.rootDir).addRepository(*it);
1762 }
1763
1764 MIL << "done" << endl;
1765 }
1766
1768
1770 {
1771 ProgressData progress;
1773 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1774 progress.name(str::form(_("Removing repository '%s'"), info.label().c_str()));
1775
1776 MIL << "Going to delete repo " << info.alias() << endl;
1777
1778 for_( it, repoBegin(), repoEnd() )
1779 {
1780 // they can be the same only if the provided is empty, that means
1781 // the provided repo has no alias
1782 // then skip
1783 if ( (!info.alias().empty()) && ( info.alias() != (*it).alias() ) )
1784 continue;
1785
1786 // TODO match by url
1787
1788 // we have a matcing repository, now we need to know
1789 // where it does come from.
1790 RepoInfo todelete = *it;
1791 if (todelete.filepath().empty())
1792 {
1793 ZYPP_THROW(RepoException( todelete, _("Can't figure out where the repo is stored.") ));
1794 }
1795 else
1796 {
1797 // figure how many repos are there in the file:
1798 std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath());
1799 if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
1800 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
1801 {
1802 // easy: file does not exist, contains no or only the repo to delete: delete the file
1803 int ret = filesystem::unlink( todelete.filepath() );
1804 if ( ! ( ret == 0 || ret == ENOENT ) )
1805 {
1806 // TranslatorExplanation '%s' is a filename
1807 ZYPP_THROW(RepoException( todelete, str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
1808 }
1809 MIL << todelete.alias() << " successfully deleted." << endl;
1810 }
1811 else
1812 {
1813 // there are more repos in the same file
1814 // write them back except the deleted one.
1815 //TmpFile tmp;
1816 //std::ofstream file(tmp.path().c_str());
1817
1818 // assert the directory exists
1820
1821 std::ofstream file(todelete.filepath().c_str());
1822 if (!file)
1823 {
1824 // TranslatorExplanation '%s' is a filename
1825 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
1826 }
1827 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1828 fit != filerepos.end();
1829 ++fit )
1830 {
1831 if ( (*fit).alias() != todelete.alias() )
1832 (*fit).dumpAsIniOn(file);
1833 }
1834 }
1835
1836 CombinedProgressData cSubprogrcv(progress, 20);
1837 CombinedProgressData mSubprogrcv(progress, 40);
1838 CombinedProgressData pSubprogrcv(progress, 40);
1839 // now delete it from cache
1840 if ( isCached(todelete) )
1841 cleanCache( todelete, cSubprogrcv);
1842 // now delete metadata (#301037)
1843 cleanMetadata( todelete, mSubprogrcv );
1844 cleanPackages( todelete, pSubprogrcv );
1845 reposManip().erase(todelete);
1846 MIL << todelete.alias() << " successfully deleted." << endl;
1847 HistoryLog(_options.rootDir).removeRepository(todelete);
1848 return;
1849 } // else filepath is empty
1850
1851 }
1852 // should not be reached on a sucess workflow
1854 }
1855
1857
1858 void RepoManager::Impl::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, const ProgressData::ReceiverFnc & progressrcv )
1859 {
1860 RepoInfo toedit = getRepositoryInfo(alias);
1861 RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
1862
1863 // check if the new alias already exists when renaming the repo
1864 if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
1865 {
1867 }
1868
1869 if (toedit.filepath().empty())
1870 {
1871 ZYPP_THROW(RepoException( toedit, _("Can't figure out where the repo is stored.") ));
1872 }
1873 else
1874 {
1875 // figure how many repos are there in the file:
1876 std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath());
1877
1878 // there are more repos in the same file
1879 // write them back except the deleted one.
1880 //TmpFile tmp;
1881 //std::ofstream file(tmp.path().c_str());
1882
1883 // assert the directory exists
1885
1886 std::ofstream file(toedit.filepath().c_str());
1887 if (!file)
1888 {
1889 // TranslatorExplanation '%s' is a filename
1890 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
1891 }
1892 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1893 fit != filerepos.end();
1894 ++fit )
1895 {
1896 // if the alias is different, dump the original
1897 // if it is the same, dump the provided one
1898 if ( (*fit).alias() != toedit.alias() )
1899 (*fit).dumpAsIniOn(file);
1900 else
1901 newinfo.dumpAsIniOn(file);
1902 }
1903
1904 if ( toedit.enabled() && !newinfo.enabled() )
1905 {
1906 // On the fly remove solv.idx files for bash completion if a repo gets disabled.
1907 const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/"solv.idx";
1908 if ( PathInfo(solvidx).isExist() )
1909 filesystem::unlink( solvidx );
1910 }
1911
1912 newinfo.setFilepath(toedit.filepath());
1913 newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1914 newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1915 {
1916 // We should fix the API as we must inject those paths
1917 // into the repoinfo in order to keep it usable.
1918 RepoInfo & oinfo( const_cast<RepoInfo &>(newinfo_r) );
1919 oinfo.setFilepath(toedit.filepath());
1920 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1921 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1922 }
1923 reposManip().erase(toedit);
1924 reposManip().insert(newinfo);
1925 // check for credentials in Urls
1926 UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
1927 HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
1928 MIL << "repo " << alias << " modified" << endl;
1929 }
1930 }
1931
1933
1934 RepoInfo RepoManager::Impl::getRepositoryInfo( const std::string & alias, const ProgressData::ReceiverFnc & progressrcv )
1935 {
1936 RepoConstIterator it( findAlias( alias, repos() ) );
1937 if ( it != repos().end() )
1938 return *it;
1939 RepoInfo info;
1940 info.setAlias( alias );
1942 }
1943
1944
1945 RepoInfo RepoManager::Impl::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
1946 {
1947 for_( it, repoBegin(), repoEnd() )
1948 {
1949 for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
1950 {
1951 if ( (*urlit).asString(urlview) == url.asString(urlview) )
1952 return *it;
1953 }
1954 }
1955 RepoInfo info;
1956 info.setBaseUrl( url );
1958 }
1959
1961 //
1962 // Services
1963 //
1965
1967 {
1968 assert_alias( service );
1969
1970 // check if service already exists
1971 if ( hasService( service.alias() ) )
1973
1974 // Writable ServiceInfo is needed to save the location
1975 // of the .service file. Finaly insert into the service list.
1976 ServiceInfo toSave( service );
1977 saveService( toSave );
1978 _services.insert( toSave );
1979
1980 // check for credentials in Url
1981 UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1982
1983 MIL << "added service " << toSave.alias() << endl;
1984 }
1985
1987
1988 void RepoManager::Impl::removeService( const std::string & alias )
1989 {
1990 MIL << "Going to delete service " << alias << endl;
1991
1992 const ServiceInfo & service = getService( alias );
1993
1994 Pathname location = service.filepath();
1995 if( location.empty() )
1996 {
1997 ZYPP_THROW(ServiceException( service, _("Can't figure out where the service is stored.") ));
1998 }
1999
2000 ServiceSet tmpSet;
2001 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2002
2003 // only one service definition in the file
2004 if ( tmpSet.size() == 1 )
2005 {
2006 if ( filesystem::unlink(location) != 0 )
2007 {
2008 // TranslatorExplanation '%s' is a filename
2009 ZYPP_THROW(ServiceException( service, str::form( _("Can't delete '%s'"), location.c_str() ) ));
2010 }
2011 MIL << alias << " successfully deleted." << endl;
2012 }
2013 else
2014 {
2015 filesystem::assert_dir(location.dirname());
2016
2017 std::ofstream file(location.c_str());
2018 if( !file )
2019 {
2020 // TranslatorExplanation '%s' is a filename
2021 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), location.c_str() )));
2022 }
2023
2024 for_(it, tmpSet.begin(), tmpSet.end())
2025 {
2026 if( it->alias() != alias )
2027 it->dumpAsIniOn(file);
2028 }
2029
2030 MIL << alias << " successfully deleted from file " << location << endl;
2031 }
2032
2033 // now remove all repositories added by this service
2034 RepoCollector rcollector;
2036 boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) );
2037 // cannot do this directly in getRepositoriesInService - would invalidate iterators
2038 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
2039 removeRepository(*rit);
2040 }
2041
2043
2045 {
2046 // copy the set of services since refreshService
2047 // can eventually invalidate the iterator
2049 for_( it, services.begin(), services.end() )
2050 {
2051 if ( !it->enabled() )
2052 continue;
2053
2054 try {
2055 refreshService(*it, options_r);
2056 }
2057 catch ( const repo::ServicePluginInformalException & e )
2058 { ;/* ignore ServicePluginInformalException */ }
2059 }
2060 }
2061
2062 void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2063 {
2064 ServiceInfo service( getService( alias ) );
2065 assert_alias( service );
2066 assert_url( service );
2067 MIL << "Going to refresh service '" << service.alias() << "', url: " << service.url() << ", opts: " << options_r << endl;
2068
2069 if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
2070 {
2071 // Service defines a TTL; maybe we can re-use existing data without refresh.
2072 Date lrf = service.lrf();
2073 if ( lrf )
2074 {
2075 Date now( Date::now() );
2076 if ( lrf <= now )
2077 {
2078 if ( (lrf+=service.ttl()) > now ) // lrf+= !
2079 {
2080 MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
2081 return;
2082 }
2083 }
2084 else
2085 WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
2086 }
2087 }
2088
2089 // NOTE: It might be necessary to modify and rewrite the service info.
2090 // Either when probing the type, or when adjusting the repositories
2091 // enable/disable state.:
2092 bool serviceModified = false;
2093
2095
2096 // if the type is unknown, try probing.
2097 if ( service.type() == repo::ServiceType::NONE )
2098 {
2099 repo::ServiceType type = probeService( service.url() );
2100 if ( type != ServiceType::NONE )
2101 {
2102 service.setProbedType( type ); // lazy init!
2103 serviceModified = true;
2104 }
2105 }
2106
2107 // get target distro identifier
2108 std::string servicesTargetDistro = _options.servicesTargetDistro;
2109 if ( servicesTargetDistro.empty() )
2110 {
2111 servicesTargetDistro = Target::targetDistribution( Pathname() );
2112 }
2113 DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
2114
2115 // parse it
2116 Date::Duration origTtl = service.ttl(); // FIXME Ugly hack: const service.ttl modified when parsing
2117 RepoCollector collector(servicesTargetDistro);
2118 // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
2119 // which is actually a notification. Using an exception for this
2120 // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
2121 // and in zypper.
2122 std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
2123 try {
2124 // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they
2125 // are not aware of the RepoManagers rootDir. The service url, as created in known_services,
2126 // contains the full path to the script. The script however has to be executed chrooted.
2127 // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace
2128 // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it
2129 // to ServiceRepos.
2130 ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
2131 }
2132 catch ( const repo::ServicePluginInformalException & e )
2133 {
2134 /* ignore ServicePluginInformalException and throw later */
2135 uglyHack.first = true;
2136 uglyHack.second = e;
2137 }
2138 if ( service.ttl() != origTtl ) // repoindex.xml changed ttl
2139 {
2140 if ( !service.ttl() )
2141 service.setLrf( Date() ); // don't need lrf when zero ttl
2142 serviceModified = true;
2143 }
2145 // On the fly remember the new repo states as defined the reopoindex.xml.
2146 // Move into ServiceInfo later.
2147 ServiceInfo::RepoStates newRepoStates;
2148
2149 // set service alias and base url for all collected repositories
2150 for_( it, collector.repos.begin(), collector.repos.end() )
2151 {
2152 // First of all: Prepend service alias:
2153 it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
2154 // set reference to the parent service
2155 it->setService( service.alias() );
2156
2157 // remember the new parsed repo state
2158 newRepoStates[it->alias()] = *it;
2159
2160 // - If the repo url was not set by the repoindex parser, set service's url.
2161 // - Libzypp currently has problem with separate url + path handling so just
2162 // append a path, if set, to the baseurls
2163 // - Credentials in the url authority will be extracted later, either if the
2164 // repository is added or if we check for changed urls.
2165 Pathname path;
2166 if ( !it->path().empty() )
2167 {
2168 if ( it->path() != "/" )
2169 path = it->path();
2170 it->setPath("");
2171 }
2172
2173 if ( it->baseUrlsEmpty() )
2174 {
2175 Url url( service.rawUrl() );
2176 if ( !path.empty() )
2177 url.setPathName( url.getPathName() / path );
2178 it->setBaseUrl( std::move(url) );
2179 }
2180 else if ( !path.empty() )
2181 {
2182 RepoInfo::url_set urls( it->rawBaseUrls() );
2183 for ( Url & url : urls )
2184 {
2185 url.setPathName( url.getPathName() / path );
2186 }
2187 it->setBaseUrls( std::move(urls) );
2188 }
2189 }
2190
2192 // Now compare collected repos with the ones in the system...
2193 //
2194 RepoInfoList oldRepos;
2195 getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
2196
2198 // find old repositories to remove...
2199 for_( oldRepo, oldRepos.begin(), oldRepos.end() )
2200 {
2201 if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
2202 {
2203 if ( oldRepo->enabled() )
2204 {
2205 // Currently enabled. If this was a user modification remember the state.
2206 const auto & last = service.repoStates().find( oldRepo->alias() );
2207 if ( last != service.repoStates().end() && ! last->second.enabled )
2208 {
2209 DBG << "Service removes user enabled repo " << oldRepo->alias() << endl;
2210 service.addRepoToEnable( oldRepo->alias() );
2211 serviceModified = true;
2212 }
2213 else
2214 DBG << "Service removes enabled repo " << oldRepo->alias() << endl;
2215 }
2216 else
2217 DBG << "Service removes disabled repo " << oldRepo->alias() << endl;
2218
2219 removeRepository( *oldRepo );
2220 }
2221 }
2222
2224 // create missing repositories and modify existing ones if needed...
2225 UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
2226 for_( it, collector.repos.begin(), collector.repos.end() )
2227 {
2228 // User explicitly requested the repo being enabled?
2229 // User explicitly requested the repo being disabled?
2230 // And hopefully not both ;) If so, enable wins.
2231
2232 TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request
2233 DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl;
2234
2235 if ( options_r.testFlag( RefreshService_restoreStatus ) )
2236 {
2237 DBG << "Opt RefreshService_restoreStatus " << it->alias() << endl;
2238 // this overrides any pending request!
2239 // Remove from enable request list.
2240 // NOTE: repoToDisable is handled differently.
2241 // It gets cleared on each refresh.
2242 service.delRepoToEnable( it->alias() );
2243 // toBeEnabled stays indeterminate!
2244 }
2245 else
2246 {
2247 if ( service.repoToEnableFind( it->alias() ) )
2248 {
2249 DBG << "User request to enable service repo " << it->alias() << endl;
2250 toBeEnabled = true;
2251 // Remove from enable request list.
2252 // NOTE: repoToDisable is handled differently.
2253 // It gets cleared on each refresh.
2254 service.delRepoToEnable( it->alias() );
2255 serviceModified = true;
2256 }
2257 else if ( service.repoToDisableFind( it->alias() ) )
2258 {
2259 DBG << "User request to disable service repo " << it->alias() << endl;
2260 toBeEnabled = false;
2261 }
2262 }
2263
2264 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2265 if ( oldRepo == oldRepos.end() )
2266 {
2267 // Not found in oldRepos ==> a new repo to add
2268
2269 // Make sure the service repo is created with the appropriate enablement
2270 if ( ! indeterminate(toBeEnabled) )
2271 it->setEnabled( ( bool ) toBeEnabled );
2272
2273 DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl;
2274 addRepository( *it );
2275 }
2276 else
2277 {
2278 // ==> an exising repo to check
2279 bool oldRepoModified = false;
2280
2281 if ( indeterminate(toBeEnabled) )
2282 {
2283 // No user request: check for an old user modificaton otherwise follow service request.
2284 // NOTE: Assert toBeEnabled is boolean afterwards!
2285 if ( oldRepo->enabled() == it->enabled() )
2286 toBeEnabled = it->enabled(); // service requests no change to the system
2287 else if (options_r.testFlag( RefreshService_restoreStatus ) )
2288 {
2289 toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
2290 DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl;
2291 }
2292 else
2293 {
2294 const auto & last = service.repoStates().find( oldRepo->alias() );
2295 if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
2296 toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
2297 else
2298 {
2299 toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
2300 DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << endl;
2301 }
2302 }
2303 }
2304
2305 // changed enable?
2306 if ( toBeEnabled == oldRepo->enabled() )
2307 {
2308 DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl;
2309 }
2310 else if ( toBeEnabled )
2311 {
2312 DBG << "Service repo " << it->alias() << " gets enabled" << endl;
2313 oldRepo->setEnabled( true );
2314 oldRepoModified = true;
2315 }
2316 else
2317 {
2318 DBG << "Service repo " << it->alias() << " gets disabled" << endl;
2319 oldRepo->setEnabled( false );
2320 oldRepoModified = true;
2321 }
2322
2323 // all other attributes follow the service request:
2324
2325 // changed name (raw!)
2326 if ( oldRepo->rawName() != it->rawName() )
2327 {
2328 DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
2329 oldRepo->setName( it->rawName() );
2330 oldRepoModified = true;
2331 }
2332
2333 // changed autorefresh
2334 if ( oldRepo->autorefresh() != it->autorefresh() )
2335 {
2336 DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl;
2337 oldRepo->setAutorefresh( it->autorefresh() );
2338 oldRepoModified = true;
2339 }
2340
2341 // changed priority?
2342 if ( oldRepo->priority() != it->priority() )
2343 {
2344 DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl;
2345 oldRepo->setPriority( it->priority() );
2346 oldRepoModified = true;
2347 }
2348
2349 // changed url?
2350 {
2351 RepoInfo::url_set newUrls( it->rawBaseUrls() );
2352 urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
2353 if ( oldRepo->rawBaseUrls() != newUrls )
2354 {
2355 DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
2356 oldRepo->setBaseUrls( std::move(newUrls) );
2357 oldRepoModified = true;
2358 }
2359 }
2360
2361 // changed gpg check settings?
2362 // ATM only plugin services can set GPG values.
2363 if ( service.type() == ServiceType::PLUGIN )
2364 {
2365 TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
2366 TriBool ngpg[3];
2367 oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
2368 it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
2369#define Z_CHKGPG(I,N) \
2370 if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
2371 { \
2372 DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
2373 oldRepo->set##N##Check( ngpg[I] ); \
2374 oldRepoModified = true; \
2375 }
2376 Z_CHKGPG( 0, Gpg );
2377 Z_CHKGPG( 1, RepoGpg );
2378 Z_CHKGPG( 2, PkgGpg );
2379#undef Z_CHKGPG
2380 }
2381
2382 // save if modified:
2383 if ( oldRepoModified )
2384 {
2385 modifyRepository( oldRepo->alias(), *oldRepo );
2386 }
2387 }
2388 }
2389
2390 // Unlike reposToEnable, reposToDisable is always cleared after refresh.
2391 if ( ! service.reposToDisableEmpty() )
2392 {
2393 service.clearReposToDisable();
2394 serviceModified = true;
2395 }
2396
2397 // Remember original service request for next refresh
2398 if ( service.repoStates() != newRepoStates )
2399 {
2400 service.setRepoStates( std::move(newRepoStates) );
2401 serviceModified = true;
2402 }
2403
2405 // save service if modified: (unless a plugin service)
2406 if ( service.type() != ServiceType::PLUGIN )
2407 {
2408 if ( service.ttl() )
2409 {
2410 service.setLrf( Date::now() ); // remember last refresh
2411 serviceModified = true; // or use a cookie file
2412 }
2413
2414 if ( serviceModified )
2415 {
2416 // write out modified service file.
2417 modifyService( service.alias(), service );
2418 }
2419 }
2420
2421 if ( uglyHack.first )
2422 {
2423 throw( uglyHack.second ); // intentionally not ZYPP_THROW
2424 }
2425 }
2426
2428
2429 void RepoManager::Impl::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
2430 {
2431 MIL << "Going to modify service " << oldAlias << endl;
2432
2433 // we need a writable copy to link it to the file where
2434 // it is saved if we modify it
2435 ServiceInfo service(newService);
2436
2437 if ( service.type() == ServiceType::PLUGIN )
2438 {
2440 }
2441
2442 const ServiceInfo & oldService = getService(oldAlias);
2443
2444 Pathname location = oldService.filepath();
2445 if( location.empty() )
2446 {
2447 ZYPP_THROW(ServiceException( oldService, _("Can't figure out where the service is stored.") ));
2448 }
2449
2450 // remember: there may multiple services being defined in one file:
2451 ServiceSet tmpSet;
2452 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2453
2454 filesystem::assert_dir(location.dirname());
2455 std::ofstream file(location.c_str());
2456 for_(it, tmpSet.begin(), tmpSet.end())
2457 {
2458 if( *it != oldAlias )
2459 it->dumpAsIniOn(file);
2460 }
2461 service.dumpAsIniOn(file);
2462 file.close();
2463 service.setFilepath(location);
2464
2465 _services.erase(oldAlias);
2466 _services.insert(service);
2467 // check for credentials in Urls
2468 UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
2469
2470
2471 // changed properties affecting also repositories
2472 if ( oldAlias != service.alias() // changed alias
2473 || oldService.enabled() != service.enabled() ) // changed enabled status
2474 {
2475 std::vector<RepoInfo> toModify;
2476 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
2477 for_( it, toModify.begin(), toModify.end() )
2478 {
2479 if ( oldService.enabled() != service.enabled() )
2480 {
2481 if ( service.enabled() )
2482 {
2483 // reset to last refreshs state
2484 const auto & last = service.repoStates().find( it->alias() );
2485 if ( last != service.repoStates().end() )
2486 it->setEnabled( last->second.enabled );
2487 }
2488 else
2489 it->setEnabled( false );
2490 }
2491
2492 if ( oldAlias != service.alias() )
2493 it->setService(service.alias());
2494
2495 modifyRepository(it->alias(), *it);
2496 }
2497 }
2498
2500 }
2501
2503
2505 {
2506 try
2507 {
2508 MediaSetAccess access(url);
2509 if ( access.doesFileExist("/repo/repoindex.xml") )
2511 }
2512 catch ( const media::MediaException &e )
2513 {
2514 ZYPP_CAUGHT(e);
2515 // TranslatorExplanation '%s' is an URL
2516 RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
2517 enew.remember(e);
2518 ZYPP_THROW(enew);
2519 }
2520 catch ( const Exception &e )
2521 {
2522 ZYPP_CAUGHT(e);
2523 // TranslatorExplanation '%s' is an URL
2524 Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
2525 enew.remember(e);
2526 ZYPP_THROW(enew);
2527 }
2528
2530 }
2531
2533 //
2534 // CLASS NAME : RepoManager
2535 //
2537
2539 : _pimpl( new Impl(opt) )
2540 {}
2541
2543 {}
2544
2546 { return _pimpl->repoEmpty(); }
2547
2549 { return _pimpl->repoSize(); }
2550
2552 { return _pimpl->repoBegin(); }
2553
2555 { return _pimpl->repoEnd(); }
2556
2557 RepoInfo RepoManager::getRepo( const std::string & alias ) const
2558 { return _pimpl->getRepo( alias ); }
2559
2560 bool RepoManager::hasRepo( const std::string & alias ) const
2561 { return _pimpl->hasRepo( alias ); }
2562
2563 std::string RepoManager::makeStupidAlias( const Url & url_r )
2564 {
2565 std::string ret( url_r.getScheme() );
2566 if ( ret.empty() )
2567 ret = "repo-";
2568 else
2569 ret += "-";
2570
2571 std::string host( url_r.getHost() );
2572 if ( ! host.empty() )
2573 {
2574 ret += host;
2575 ret += "-";
2576 }
2577
2578 static Date::ValueType serial = Date::now();
2579 ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8);
2580 return ret;
2581 }
2582
2584 { return _pimpl->metadataStatus( info ); }
2585
2587 { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
2588
2590 { return _pimpl->metadataPath( info ); }
2591
2593 { return _pimpl->packagesPath( info ); }
2594
2596 { return _pimpl->refreshMetadata( info, policy, progressrcv ); }
2597
2598 void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2599 { return _pimpl->cleanMetadata( info, progressrcv ); }
2600
2601 void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2602 { return _pimpl->cleanPackages( info, progressrcv ); }
2603
2605 { return _pimpl->cacheStatus( info ); }
2606
2607 void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
2608 { return _pimpl->buildCache( info, policy, progressrcv ); }
2609
2610 void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2611 { return _pimpl->cleanCache( info, progressrcv ); }
2612
2613 bool RepoManager::isCached( const RepoInfo &info ) const
2614 { return _pimpl->isCached( info ); }
2615
2616 void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2617 { return _pimpl->loadFromCache( info, progressrcv ); }
2618
2620 { return _pimpl->cleanCacheDirGarbage( progressrcv ); }
2621
2622 repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const
2623 { return _pimpl->probe( url, path ); }
2624
2626 { return _pimpl->probe( url ); }
2627
2628 void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2629 { return _pimpl->addRepository( info, progressrcv ); }
2630
2632 { return _pimpl->addRepositories( url, progressrcv ); }
2633
2634 void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
2635 { return _pimpl->removeRepository( info, progressrcv ); }
2636
2637 void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv )
2638 { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
2639
2640 RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv )
2641 { return _pimpl->getRepositoryInfo( alias, progressrcv ); }
2642
2644 { return _pimpl->getRepositoryInfo( url, urlview, progressrcv ); }
2645
2647 { return _pimpl->serviceEmpty(); }
2648
2650 { return _pimpl->serviceSize(); }
2651
2653 { return _pimpl->serviceBegin(); }
2654
2656 { return _pimpl->serviceEnd(); }
2657
2658 ServiceInfo RepoManager::getService( const std::string & alias ) const
2659 { return _pimpl->getService( alias ); }
2660
2661 bool RepoManager::hasService( const std::string & alias ) const
2662 { return _pimpl->hasService( alias ); }
2663
2665 { return _pimpl->probeService( url ); }
2666
2667 void RepoManager::addService( const std::string & alias, const Url& url )
2668 { return _pimpl->addService( alias, url ); }
2669
2670 void RepoManager::addService( const ServiceInfo & service )
2671 { return _pimpl->addService( service ); }
2672
2673 void RepoManager::removeService( const std::string & alias )
2674 { return _pimpl->removeService( alias ); }
2675
2677 { return _pimpl->removeService( service ); }
2678
2680 { return _pimpl->refreshServices( options_r ); }
2681
2682 void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2683 { return _pimpl->refreshService( alias, options_r ); }
2684
2685 void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
2686 { return _pimpl->refreshService( service, options_r ); }
2687
2688 void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service )
2689 { return _pimpl->modifyService( oldAlias, service ); }
2690
2692
2693 std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
2694 { return str << *obj._pimpl; }
2695
2697} // namespace zypp
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:400
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:396
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
Interface to gettext.
#define PL_(MSG1, MSG2, N)
Definition: Gettext.h:40
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:78
#define MIL
Definition: Logger.h:79
#define ERR
Definition: Logger.h:81
#define WAR
Definition: Logger.h:80
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:70
Url url
Definition: MediaCurl.cc:66
#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:189
static const std::string & sha1()
sha1
Definition: Digest.cc:49
Base class for Exception.
Definition: Exception.h:146
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 ...
const std::string & command() const
The command we're executing.
std::vector< std::string > Arguments
int close()
Wait for the progamm to complete.
Writing the zypp history file.
Definition: HistoryLog.h:57
void modifyRepository(const RepoInfo &oldrepo, const RepoInfo &newrepo)
Log certain modifications to a repository.
Definition: HistoryLog.cc:310
void addRepository(const RepoInfo &repo)
Log a newly added repository.
Definition: HistoryLog.cc:287
void removeRepository(const RepoInfo &repo)
Log recently removed repository.
Definition: HistoryLog.cc:299
Media access layer responsible for handling files distributed on a set of media with media change and...
static ManagedFile provideFileFromUrl(const Url &file_url, ProvideFileOptions options=PROVIDE_DEFAULT)
Provides file from url.
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
Pathname metadataPath() const
Path where this repo metadata was read from.
Definition: RepoInfo.cc:680
bool baseUrlsEmpty() const
whether repository urls are available
Definition: RepoInfo.cc:743
void setBaseUrl(const Url &url)
Clears current base URL list and adds url.
Definition: RepoInfo.cc:643
repo::RepoType type() const
Type of repository,.
Definition: RepoInfo.cc:689
urls_size_type baseUrlsSize() const
number of repository urls
Definition: RepoInfo.cc:740
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:737
void setPackagesPath(const Pathname &path)
set the path where the local packages are stored
Definition: RepoInfo.cc:665
virtual std::ostream & dumpAsIniOn(std::ostream &str) const
Write this RepoInfo object into str in a .repo file format.
Definition: RepoInfo.cc:933
Pathname path() const
Repository path.
Definition: RepoInfo.cc:722
url_set baseUrls() const
The complete set of repository urls.
Definition: RepoInfo.cc:716
bool usesAutoMethadataPaths() const
Whether metadataPath uses AUTO% setup.
Definition: RepoInfo.cc:686
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:658
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:734
void setMetadataPath(const Pathname &path)
Set the path where the local metadata is stored.
Definition: RepoInfo.cc:662
Pathname packagesPath() const
Path where this repo packages are cached.
Definition: RepoInfo.cc:683
transform_iterator< repo::RepoVariablesUrlReplacer, url_set::const_iterator > urls_const_iterator
Definition: RepoInfo.h:105
std::string targetDistribution() const
Distribution for which is this repository meant.
Definition: RepoInfo.cc:728
void setType(const repo::RepoType &t)
set the repository type
Definition: RepoInfo.cc:655
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
@ REFRESH_NEEDED
refresh is needed
Definition: RepoManager.h:197
@ REPO_UP_TO_DATE
repository not changed
Definition: RepoManager.h:198
@ REPO_CHECK_DELAYED
refresh is delayed due to settings
Definition: RepoManager.h:199
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.
@ RefreshService_forceRefresh
Force refresh even if TTL is not reached.
Definition: RepoManager.h:145
@ RefreshService_restoreStatus
Force restoring repo enabled/disabled status.
Definition: RepoManager.h:144
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.
Iterable< ServiceConstIterator > services() const
Iterate the known services.
Definition: RepoManager.h:711
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
Iterable< RepoConstIterator > repos() const
Iterate the known repositories.
Definition: RepoManager.h:707
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 getRepositoriesInService(const std::string &alias, OutputIterator out) const
fill to output iterator repositories in service name.
Definition: RepoManager.h:686
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:114
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:41
static RepoStatus fromCookieFile(const Pathname &path)
Reads the status from a cookie file.
Definition: RepoStatus.cc:194
Date timestamp() const
The time the data were changed the last time.
Definition: RepoStatus.cc:225
bool empty() const
Whether the status is empty (empty checksum)
Definition: RepoStatus.cc:222
void saveToCookieFile(const Pathname &path_r) const
Save the status information to a cookie file.
Definition: RepoStatus.cc:212
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:102
Url manipulation class.
Definition: Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:528
std::string asCompleteString() const
Returns a complete string representation of the Url object.
Definition: Url.cc:500
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:583
bool isValid() const
Verifies the Url.
Definition: Url.cc:484
void setPassword(const std::string &pass, EEncoding eflag=zypp::url::E_DECODED)
Set the password in the URL authority.
Definition: Url.cc:734
bool hasCredentialsInAuthority() const
Returns true if username and password are encoded in the authority component.
Definition: Url.h:375
unsigned repo_refresh_delay() const
Amount of time in minutes that must pass before another refresh.
Definition: ZConfig.cc:1013
bool repo_add_probe() const
Whether repository urls should be probed.
Definition: ZConfig.cc:1010
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:126
std::string receiveLine()
Read one line from the input stream.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
time_t mtime() const
Definition: PathInfo.h:376
bool userMayRX() const
Definition: PathInfo.h:350
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:246
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:248
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:170
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
const char * c_str() const
String representation.
Definition: Pathname.h:110
const std::string & asString() const
String representation.
Definition: Pathname.h:91
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
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
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:178
static TmpDir makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition: TmpPath.cc:295
Pathname path() const
Definition: TmpPath.cc:146
Just inherits Exception to separate media exceptions.
Manages access to the 'physical' media, e.g CDROM drives, Disk volumes, directory trees,...
Definition: MediaManager.h:471
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
void attach(MediaAccessId accessId)
Attach the media using the concrete handler (checks all devices).
void close(MediaAccessId accessId)
Close the media access with specified id.
void release(MediaAccessId accessId, const std::string &ejectDev="")
Release the attached media and optionally eject.
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for 'localRoot() + pathname', but returns an empty pathname if media is not attached.
Read repository data from a .repo file.
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.
std::string escaped_alias() const
Same as alias(), just escaped in a way to be a valid file name.
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) override
Status of the remote repository.
Definition: Downloader.cc:35
Downloader for YUM (rpm-nmd) repositories Encapsulates all the knowledge of which files have to be do...
Definition: Downloader.h:41
RepoStatus status(MediaSetAccess &media_r) override
Status of the remote repository.
Definition: Downloader.cc:198
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:112
Repository addRepoSolv(const Pathname &file_r, const std::string &name_r)
Load Solvables from a solv-file into a Repository named name_r.
Definition: Pool.cc:185
static Pool instance()
Singleton ctor.
Definition: Pool.h:55
static const SolvAttr repositoryToolVersion
Definition: SolvAttr.h:174
Regular expression.
Definition: Regex.h:95
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:598
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:662
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:1196
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition: PathInfo.cc:718
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
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition: Pool.cc:286
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:330
std::string numstring(char n, int w=0)
Definition: String.h:286
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:426
std::string hexstring(char n, int w=4)
Definition: String.h:321
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::ostream & operator<<(std::ostream &str, const Exception &obj)
Definition: Exception.cc:147
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
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:486
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:472
RepoManager implementation.
Definition: RepoManager.cc:521
RepoSizeType repoSize() const
Definition: RepoManager.cc:576
void saveService(ServiceInfo &service) const
Definition: RepoManager.cc:725
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r)
void addService(const ServiceInfo &service)
repo::ServiceType probeService(const Url &url) const
bool hasRepo(const std::string &alias) const
Definition: RepoManager.cc:580
bool serviceEmpty() const
Definition: RepoManager.cc:635
void refreshServices(const RefreshServiceOptions &options_r)
std::string generateFilename(const ServiceInfo &info) const
Definition: RepoManager.cc:676
const RepoSet & repos() const
Definition: RepoManager.cc:701
RepoInfo getRepositoryInfo(const Url &url, const url::ViewOption &urlview, OPT_PROGRESS)
RepoManagerOptions _options
Definition: RepoManager.cc:705
std::ostream & operator<<(std::ostream &str, const RepoManager::Impl &obj)
Stream output.
Definition: RepoManager.cc:720
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy, OPT_PROGRESS)
std::string generateFilename(const RepoInfo &info) const
Definition: RepoManager.cc:673
RepoConstIterator repoEnd() const
Definition: RepoManager.cc:578
Impl * clone() const
clone for RWCOW_pointer
Definition: RepoManager.cc:714
void buildCache(const RepoInfo &info, CacheBuildPolicy policy, OPT_PROGRESS)
ServiceSizeType serviceSize() const
Definition: RepoManager.cc:636
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:651
void removeService(const std::string &alias)
void getRepositoriesInService(const std::string &alias, OutputIterator out) const
Definition: RepoManager.cc:689
void cleanMetadata(const RepoInfo &info, OPT_PROGRESS)
RepoStatus cacheStatus(const RepoInfo &info) const
Definition: RepoManager.cc:618
void removeRepository(const RepoInfo &info, OPT_PROGRESS)
Pathname packagesPath(const RepoInfo &info) const
Definition: RepoManager.cc:593
void cleanPackages(const RepoInfo &info, OPT_PROGRESS)
RepoConstIterator repoBegin() const
Definition: RepoManager.cc:577
void addRepositories(const Url &url, OPT_PROGRESS)
ServiceInfo getService(const std::string &alias) const
Definition: RepoManager.cc:643
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:638
RepoInfo getRepositoryInfo(const std::string &alias, OPT_PROGRESS)
void touchIndexFile(const RepoInfo &info)
Definition: RepoManager.cc:946
Impl(const RepoManagerOptions &opt)
Definition: RepoManager.cc:523
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy)
Definition: RepoManager.cc:983
Pathname metadataPath(const RepoInfo &info) const
Definition: RepoManager.cc:590
bool isCached(const RepoInfo &info) const
Definition: RepoManager.cc:615
DefaultIntegral< bool, false > _reposDirty
Definition: RepoManager.cc:709
void cleanCache(const RepoInfo &info, OPT_PROGRESS)
void removeService(const ServiceInfo &service)
Definition: RepoManager.cc:655
void setCacheStatus(const RepoInfo &info, const RepoStatus &status)
Definition: RepoManager.cc:679
ServiceConstIterator serviceBegin() const
Definition: RepoManager.cc:637
void refreshService(const ServiceInfo &service, const RefreshServiceOptions &options_r)
Definition: RepoManager.cc:661
void cleanCacheDirGarbage(OPT_PROGRESS)
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:903
RepoInfo getRepo(const std::string &alias) const
Definition: RepoManager.cc:583
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:759
void modifyRepository(const std::string &alias, const RepoInfo &newinfo_r, OPT_PROGRESS)
bool hasService(const std::string &alias) const
Definition: RepoManager.cc:640
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
Convenient building of std::string with boost::format.
Definition: String.h:250
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:209
Url::asString() view options.
Definition: UrlBase.h:40