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