libzypp 17.29.1
RepoManager.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
13#include <cstdlib>
14#include <iostream>
15#include <fstream>
16#include <sstream>
17#include <list>
18#include <map>
19#include <algorithm>
20
21#include <solv/solvversion.h>
22
23#include <zypp-core/base/InputStream>
24#include <zypp/base/LogTools.h>
25#include <zypp/base/Gettext.h>
26#include <zypp-core/base/DefaultIntegral>
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
37#include <zypp-media/auth/CredentialManager>
38#include <zypp-media/MediaException>
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 errdetail += output;
1403 }
1404
1405 int ret = prog.close();
1406 if ( ret != 0 )
1407 {
1408 RepoException ex(info, str::form( _("Failed to cache repo (%d)."), ret ));
1409 ex.addHistory( str::Str() << prog.command() << endl << errdetail << prog.execError() ); // errdetail lines are NL-terminaled!
1410 ZYPP_THROW(ex);
1411 }
1412
1413 // We keep it.
1414 guard.resetDispose();
1415 sat::updateSolvFileIndex( solvfile ); // content digest for zypper bash completion
1416 }
1417 break;
1418 default:
1419 ZYPP_THROW(RepoUnknownTypeException( info, _("Unhandled repository type") ));
1420 break;
1421 }
1422 // update timestamp and checksum
1423 setCacheStatus(info, raw_metadata_status);
1424 MIL << "Commit cache.." << endl;
1425 progress.toMax();
1426 }
1427
1429
1430
1437 repo::RepoType RepoManager::Impl::probe( const Url & url, const Pathname & path ) const
1438 {
1439 MIL << "going to probe the repo type at " << url << " (" << path << ")" << endl;
1440
1441 if ( url.getScheme() == "dir" && ! PathInfo( url.getPathName()/path ).isDir() )
1442 {
1443 // Handle non existing local directory in advance, as
1444 // MediaSetAccess does not support it.
1445 MIL << "Probed type NONE (not exists) at " << url << " (" << path << ")" << endl;
1446 return repo::RepoType::NONE;
1447 }
1448
1449 // prepare exception to be thrown if the type could not be determined
1450 // due to a media exception. We can't throw right away, because of some
1451 // problems with proxy servers returning an incorrect error
1452 // on ftp file-not-found(bnc #335906). Instead we'll check another types
1453 // before throwing.
1454
1455 // TranslatorExplanation '%s' is an URL
1456 RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
1457 bool gotMediaException = false;
1458 try
1459 {
1460 MediaSetAccess access(url);
1461 try
1462 {
1463 if ( access.doesFileExist(path/"/repodata/repomd.xml") )
1464 {
1465 MIL << "Probed type RPMMD at " << url << " (" << path << ")" << endl;
1466 return repo::RepoType::RPMMD;
1467 }
1468 }
1469 catch ( const media::MediaException &e )
1470 {
1471 ZYPP_CAUGHT(e);
1472 DBG << "problem checking for repodata/repomd.xml file" << endl;
1473 enew.remember(e);
1474 gotMediaException = true;
1475 }
1476
1477 try
1478 {
1479 if ( access.doesFileExist(path/"/content") )
1480 {
1481 MIL << "Probed type YAST2 at " << url << " (" << path << ")" << endl;
1482 return repo::RepoType::YAST2;
1483 }
1484 }
1485 catch ( const media::MediaException &e )
1486 {
1487 ZYPP_CAUGHT(e);
1488 DBG << "problem checking for content file" << endl;
1489 enew.remember(e);
1490 gotMediaException = true;
1491 }
1492
1493 // if it is a non-downloading URL denoting a directory (bsc#1191286: and no plugin)
1494 if ( ! ( url.schemeIsDownloading() || url.schemeIsPlugin() ) )
1495 {
1496 MediaMounter media( url );
1497 if ( PathInfo(media.getPathName()/path).isDir() )
1498 {
1499 // allow empty dirs for now
1500 MIL << "Probed type RPMPLAINDIR at " << url << " (" << path << ")" << endl;
1502 }
1503 }
1504 }
1505 catch ( const Exception &e )
1506 {
1507 ZYPP_CAUGHT(e);
1508 // TranslatorExplanation '%s' is an URL
1509 Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
1510 enew.remember(e);
1511 ZYPP_THROW(enew);
1512 }
1513
1514 if (gotMediaException)
1515 ZYPP_THROW(enew);
1516
1517 MIL << "Probed type NONE at " << url << " (" << path << ")" << endl;
1518 return repo::RepoType::NONE;
1519 }
1520
1527 {
1528 MIL << "going to probe the cached repo at " << path_r << endl;
1529
1531
1532 if ( PathInfo(path_r/"/repodata/repomd.xml").isFile() )
1533 { ret = repo::RepoType::RPMMD; }
1534 else if ( PathInfo(path_r/"/content").isFile() )
1535 { ret = repo::RepoType::YAST2; }
1536 else if ( PathInfo(path_r).isDir() )
1538
1539 MIL << "Probed cached type " << ret << " at " << path_r << endl;
1540 return ret;
1541 }
1542
1544
1546 {
1547 MIL << "Going to clean up garbage in cache dirs" << endl;
1548
1549 ProgressData progress(300);
1550 progress.sendTo(progressrcv);
1551 progress.toMin();
1552
1553 std::list<Pathname> cachedirs;
1554 cachedirs.push_back(_options.repoRawCachePath);
1555 cachedirs.push_back(_options.repoPackagesCachePath);
1556 cachedirs.push_back(_options.repoSolvCachePath);
1557
1558 for_( dir, cachedirs.begin(), cachedirs.end() )
1559 {
1560 if ( PathInfo(*dir).isExist() )
1561 {
1562 std::list<Pathname> entries;
1563 if ( filesystem::readdir( entries, *dir, false ) != 0 )
1564 // TranslatorExplanation '%s' is a pathname
1565 ZYPP_THROW(Exception(str::form(_("Failed to read directory '%s'"), dir->c_str())));
1566
1567 unsigned sdircount = entries.size();
1568 unsigned sdircurrent = 1;
1569 for_( subdir, entries.begin(), entries.end() )
1570 {
1571 // if it does not belong known repo, make it disappear
1572 bool found = false;
1573 for_( r, repoBegin(), repoEnd() )
1574 if ( subdir->basename() == r->escaped_alias() )
1575 { found = true; break; }
1576
1577 if ( ! found && ( Date::now()-PathInfo(*subdir).mtime() > Date::day ) )
1578 filesystem::recursive_rmdir( *subdir );
1579
1580 progress.set( progress.val() + sdircurrent * 100 / sdircount );
1581 ++sdircurrent;
1582 }
1583 }
1584 else
1585 progress.set( progress.val() + 100 );
1586 }
1587 progress.toMax();
1588 }
1589
1591
1592 void RepoManager::Impl::cleanCache( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
1593 {
1594 ProgressData progress(100);
1595 progress.sendTo(progressrcv);
1596 progress.toMin();
1597
1598 MIL << "Removing raw metadata cache for " << info.alias() << endl;
1599 filesystem::recursive_rmdir(solv_path_for_repoinfo(_options, info));
1600
1601 progress.toMax();
1602 }
1603
1605
1607 {
1608 assert_alias(info);
1609 Pathname solvfile = solv_path_for_repoinfo(_options, info) / "solv";
1610
1611 if ( ! PathInfo(solvfile).isExist() )
1613
1615 try
1616 {
1617 Repository repo = sat::Pool::instance().addRepoSolv( solvfile, info );
1618 // test toolversion in order to rebuild solv file in case
1619 // it was written by a different libsolv-tool parser.
1620 const std::string & toolversion( sat::LookupRepoAttr( sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
1621 if ( toolversion != LIBSOLV_TOOLVERSION )
1622 {
1623 repo.eraseFromPool();
1624 ZYPP_THROW(Exception(str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
1625 }
1626 }
1627 catch ( const Exception & exp )
1628 {
1629 ZYPP_CAUGHT( exp );
1630 MIL << "Try to handle exception by rebuilding the solv-file" << endl;
1631 cleanCache( info, progressrcv );
1632 buildCache( info, BuildIfNeeded, progressrcv );
1633
1634 sat::Pool::instance().addRepoSolv( solvfile, info );
1635 }
1636 }
1637
1639
1641 {
1642 assert_alias(info);
1643
1644 ProgressData progress(100);
1646 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1647 progress.name(str::form(_("Adding repository '%s'"), info.label().c_str()));
1648 progress.toMin();
1649
1650 MIL << "Try adding repo " << info << endl;
1651
1652 RepoInfo tosave = info;
1653 if ( repos().find(tosave) != repos().end() )
1655
1656 // check the first url for now
1657 if ( _options.probe )
1658 {
1659 DBG << "unknown repository type, probing" << endl;
1660 assert_urls(tosave);
1661
1662 RepoType probedtype( probe( tosave.url(), info.path() ) );
1663 if ( probedtype == RepoType::NONE )
1665 else
1666 tosave.setType(probedtype);
1667 }
1668
1669 progress.set(50);
1670
1671 // assert the directory exists
1672 filesystem::assert_dir(_options.knownReposPath);
1673
1674 Pathname repofile = generateNonExistingName(
1675 _options.knownReposPath, generateFilename(tosave));
1676 // now we have a filename that does not exists
1677 MIL << "Saving repo in " << repofile << endl;
1678
1679 std::ofstream file(repofile.c_str());
1680 if (!file)
1681 {
1682 // TranslatorExplanation '%s' is a filename
1683 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1684 }
1685
1686 tosave.dumpAsIniOn(file);
1687 tosave.setFilepath(repofile);
1688 tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1689 tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1690 {
1691 // We should fix the API as we must inject those paths
1692 // into the repoinfo in order to keep it usable.
1693 RepoInfo & oinfo( const_cast<RepoInfo &>(info) );
1694 oinfo.setFilepath(repofile);
1695 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1696 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1697 }
1698 reposManip().insert(tosave);
1699
1700 progress.set(90);
1701
1702 // check for credentials in Urls
1703 UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
1704
1705 HistoryLog(_options.rootDir).addRepository(tosave);
1706
1707 progress.toMax();
1708 MIL << "done" << endl;
1709 }
1710
1711
1713 {
1714 std::list<RepoInfo> repos = readRepoFile(url);
1715 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
1716 it != repos.end();
1717 ++it )
1718 {
1719 // look if the alias is in the known repos.
1720 for_ ( kit, repoBegin(), repoEnd() )
1721 {
1722 if ( (*it).alias() == (*kit).alias() )
1723 {
1724 ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << endl;
1726 }
1727 }
1728 }
1729
1730 std::string filename = Pathname(url.getPathName()).basename();
1731
1732 if ( filename == Pathname() )
1733 {
1734 // TranslatorExplanation '%s' is an URL
1735 ZYPP_THROW(RepoException(str::form( _("Invalid repo file name at '%s'"), url.asString().c_str() )));
1736 }
1737
1738 // assert the directory exists
1739 filesystem::assert_dir(_options.knownReposPath);
1740
1741 Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
1742 // now we have a filename that does not exists
1743 MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << endl;
1744
1745 std::ofstream file(repofile.c_str());
1746 if (!file)
1747 {
1748 // TranslatorExplanation '%s' is a filename
1749 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
1750 }
1751
1752 for ( std::list<RepoInfo>::iterator it = repos.begin();
1753 it != repos.end();
1754 ++it )
1755 {
1756 MIL << "Saving " << (*it).alias() << endl;
1757 it->dumpAsIniOn(file);
1758 it->setFilepath(repofile);
1759 it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
1760 it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
1761 reposManip().insert(*it);
1762
1763 HistoryLog(_options.rootDir).addRepository(*it);
1764 }
1765
1766 MIL << "done" << endl;
1767 }
1768
1770
1772 {
1773 ProgressData progress;
1775 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1776 progress.name(str::form(_("Removing repository '%s'"), info.label().c_str()));
1777
1778 MIL << "Going to delete repo " << info.alias() << endl;
1779
1780 for_( it, repoBegin(), repoEnd() )
1781 {
1782 // they can be the same only if the provided is empty, that means
1783 // the provided repo has no alias
1784 // then skip
1785 if ( (!info.alias().empty()) && ( info.alias() != (*it).alias() ) )
1786 continue;
1787
1788 // TODO match by url
1789
1790 // we have a matcing repository, now we need to know
1791 // where it does come from.
1792 RepoInfo todelete = *it;
1793 if (todelete.filepath().empty())
1794 {
1795 ZYPP_THROW(RepoException( todelete, _("Can't figure out where the repo is stored.") ));
1796 }
1797 else
1798 {
1799 // figure how many repos are there in the file:
1800 std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath());
1801 if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
1802 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
1803 {
1804 // easy: file does not exist, contains no or only the repo to delete: delete the file
1805 int ret = filesystem::unlink( todelete.filepath() );
1806 if ( ! ( ret == 0 || ret == ENOENT ) )
1807 {
1808 // TranslatorExplanation '%s' is a filename
1809 ZYPP_THROW(RepoException( todelete, str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
1810 }
1811 MIL << todelete.alias() << " successfully deleted." << endl;
1812 }
1813 else
1814 {
1815 // there are more repos in the same file
1816 // write them back except the deleted one.
1817 //TmpFile tmp;
1818 //std::ofstream file(tmp.path().c_str());
1819
1820 // assert the directory exists
1822
1823 std::ofstream file(todelete.filepath().c_str());
1824 if (!file)
1825 {
1826 // TranslatorExplanation '%s' is a filename
1827 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
1828 }
1829 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1830 fit != filerepos.end();
1831 ++fit )
1832 {
1833 if ( (*fit).alias() != todelete.alias() )
1834 (*fit).dumpAsIniOn(file);
1835 }
1836 }
1837
1838 CombinedProgressData cSubprogrcv(progress, 20);
1839 CombinedProgressData mSubprogrcv(progress, 40);
1840 CombinedProgressData pSubprogrcv(progress, 40);
1841 // now delete it from cache
1842 if ( isCached(todelete) )
1843 cleanCache( todelete, cSubprogrcv);
1844 // now delete metadata (#301037)
1845 cleanMetadata( todelete, mSubprogrcv );
1846 cleanPackages( todelete, pSubprogrcv );
1847 reposManip().erase(todelete);
1848 MIL << todelete.alias() << " successfully deleted." << endl;
1849 HistoryLog(_options.rootDir).removeRepository(todelete);
1850 return;
1851 } // else filepath is empty
1852
1853 }
1854 // should not be reached on a sucess workflow
1856 }
1857
1859
1860 void RepoManager::Impl::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, const ProgressData::ReceiverFnc & progressrcv )
1861 {
1862 RepoInfo toedit = getRepositoryInfo(alias);
1863 RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
1864
1865 // check if the new alias already exists when renaming the repo
1866 if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
1867 {
1869 }
1870
1871 if (toedit.filepath().empty())
1872 {
1873 ZYPP_THROW(RepoException( toedit, _("Can't figure out where the repo is stored.") ));
1874 }
1875 else
1876 {
1877 // figure how many repos are there in the file:
1878 std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath());
1879
1880 // there are more repos in the same file
1881 // write them back except the deleted one.
1882 //TmpFile tmp;
1883 //std::ofstream file(tmp.path().c_str());
1884
1885 // assert the directory exists
1887
1888 std::ofstream file(toedit.filepath().c_str());
1889 if (!file)
1890 {
1891 // TranslatorExplanation '%s' is a filename
1892 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
1893 }
1894 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1895 fit != filerepos.end();
1896 ++fit )
1897 {
1898 // if the alias is different, dump the original
1899 // if it is the same, dump the provided one
1900 if ( (*fit).alias() != toedit.alias() )
1901 (*fit).dumpAsIniOn(file);
1902 else
1903 newinfo.dumpAsIniOn(file);
1904 }
1905
1906 if ( toedit.enabled() && !newinfo.enabled() )
1907 {
1908 // On the fly remove solv.idx files for bash completion if a repo gets disabled.
1909 const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/"solv.idx";
1910 if ( PathInfo(solvidx).isExist() )
1911 filesystem::unlink( solvidx );
1912 }
1913
1914 newinfo.setFilepath(toedit.filepath());
1915 newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1916 newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1917 {
1918 // We should fix the API as we must inject those paths
1919 // into the repoinfo in order to keep it usable.
1920 RepoInfo & oinfo( const_cast<RepoInfo &>(newinfo_r) );
1921 oinfo.setFilepath(toedit.filepath());
1922 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1923 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1924 }
1925 reposManip().erase(toedit);
1926 reposManip().insert(newinfo);
1927 // check for credentials in Urls
1928 UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
1929 HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
1930 MIL << "repo " << alias << " modified" << endl;
1931 }
1932 }
1933
1935
1936 RepoInfo RepoManager::Impl::getRepositoryInfo( const std::string & alias, const ProgressData::ReceiverFnc & progressrcv )
1937 {
1938 RepoConstIterator it( findAlias( alias, repos() ) );
1939 if ( it != repos().end() )
1940 return *it;
1941 RepoInfo info;
1942 info.setAlias( alias );
1944 }
1945
1946
1947 RepoInfo RepoManager::Impl::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
1948 {
1949 for_( it, repoBegin(), repoEnd() )
1950 {
1951 for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
1952 {
1953 if ( (*urlit).asString(urlview) == url.asString(urlview) )
1954 return *it;
1955 }
1956 }
1957 RepoInfo info;
1958 info.setBaseUrl( url );
1960 }
1961
1963 //
1964 // Services
1965 //
1967
1969 {
1970 assert_alias( service );
1971
1972 // check if service already exists
1973 if ( hasService( service.alias() ) )
1975
1976 // Writable ServiceInfo is needed to save the location
1977 // of the .service file. Finaly insert into the service list.
1978 ServiceInfo toSave( service );
1979 saveService( toSave );
1980 _services.insert( toSave );
1981
1982 // check for credentials in Url
1983 UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1984
1985 MIL << "added service " << toSave.alias() << endl;
1986 }
1987
1989
1990 void RepoManager::Impl::removeService( const std::string & alias )
1991 {
1992 MIL << "Going to delete service " << alias << endl;
1993
1994 const ServiceInfo & service = getService( alias );
1995
1996 Pathname location = service.filepath();
1997 if( location.empty() )
1998 {
1999 ZYPP_THROW(ServiceException( service, _("Can't figure out where the service is stored.") ));
2000 }
2001
2002 ServiceSet tmpSet;
2003 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2004
2005 // only one service definition in the file
2006 if ( tmpSet.size() == 1 )
2007 {
2008 if ( filesystem::unlink(location) != 0 )
2009 {
2010 // TranslatorExplanation '%s' is a filename
2011 ZYPP_THROW(ServiceException( service, str::form( _("Can't delete '%s'"), location.c_str() ) ));
2012 }
2013 MIL << alias << " successfully deleted." << endl;
2014 }
2015 else
2016 {
2017 filesystem::assert_dir(location.dirname());
2018
2019 std::ofstream file(location.c_str());
2020 if( !file )
2021 {
2022 // TranslatorExplanation '%s' is a filename
2023 ZYPP_THROW( Exception(str::form( _("Can't open file '%s' for writing."), location.c_str() )));
2024 }
2025
2026 for_(it, tmpSet.begin(), tmpSet.end())
2027 {
2028 if( it->alias() != alias )
2029 it->dumpAsIniOn(file);
2030 }
2031
2032 MIL << alias << " successfully deleted from file " << location << endl;
2033 }
2034
2035 // now remove all repositories added by this service
2036 RepoCollector rcollector;
2038 boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) );
2039 // cannot do this directly in getRepositoriesInService - would invalidate iterators
2040 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
2041 removeRepository(*rit);
2042 }
2043
2045
2047 {
2048 // copy the set of services since refreshService
2049 // can eventually invalidate the iterator
2051 for_( it, services.begin(), services.end() )
2052 {
2053 if ( !it->enabled() )
2054 continue;
2055
2056 try {
2057 refreshService(*it, options_r);
2058 }
2059 catch ( const repo::ServicePluginInformalException & e )
2060 { ;/* ignore ServicePluginInformalException */ }
2061 }
2062 }
2063
2064 void RepoManager::Impl::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2065 {
2066 ServiceInfo service( getService( alias ) );
2067 assert_alias( service );
2068 assert_url( service );
2069 MIL << "Going to refresh service '" << service.alias() << "', url: " << service.url() << ", opts: " << options_r << endl;
2070
2071 if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
2072 {
2073 // Service defines a TTL; maybe we can re-use existing data without refresh.
2074 Date lrf = service.lrf();
2075 if ( lrf )
2076 {
2077 Date now( Date::now() );
2078 if ( lrf <= now )
2079 {
2080 if ( (lrf+=service.ttl()) > now ) // lrf+= !
2081 {
2082 MIL << "Skip: '" << service.alias() << "' metadata valid until " << lrf << endl;
2083 return;
2084 }
2085 }
2086 else
2087 WAR << "Force: '" << service.alias() << "' metadata last refresh in the future: " << lrf << endl;
2088 }
2089 }
2090
2091 // NOTE: It might be necessary to modify and rewrite the service info.
2092 // Either when probing the type, or when adjusting the repositories
2093 // enable/disable state.:
2094 bool serviceModified = false;
2095
2097
2098 // if the type is unknown, try probing.
2099 if ( service.type() == repo::ServiceType::NONE )
2100 {
2101 repo::ServiceType type = probeService( service.url() );
2102 if ( type != ServiceType::NONE )
2103 {
2104 service.setProbedType( type ); // lazy init!
2105 serviceModified = true;
2106 }
2107 }
2108
2109 // get target distro identifier
2110 std::string servicesTargetDistro = _options.servicesTargetDistro;
2111 if ( servicesTargetDistro.empty() )
2112 {
2113 servicesTargetDistro = Target::targetDistribution( Pathname() );
2114 }
2115 DBG << "ServicesTargetDistro: " << servicesTargetDistro << endl;
2116
2117 // parse it
2118 Date::Duration origTtl = service.ttl(); // FIXME Ugly hack: const service.ttl modified when parsing
2119 RepoCollector collector(servicesTargetDistro);
2120 // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
2121 // which is actually a notification. Using an exception for this
2122 // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
2123 // and in zypper.
2124 std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
2125 try {
2126 // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they
2127 // are not aware of the RepoManagers rootDir. The service url, as created in known_services,
2128 // contains the full path to the script. The script however has to be executed chrooted.
2129 // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace
2130 // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it
2131 // to ServiceRepos.
2132 ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
2133 }
2134 catch ( const repo::ServicePluginInformalException & e )
2135 {
2136 /* ignore ServicePluginInformalException and throw later */
2137 uglyHack.first = true;
2138 uglyHack.second = e;
2139 }
2140 if ( service.ttl() != origTtl ) // repoindex.xml changed ttl
2141 {
2142 if ( !service.ttl() )
2143 service.setLrf( Date() ); // don't need lrf when zero ttl
2144 serviceModified = true;
2145 }
2147 // On the fly remember the new repo states as defined the reopoindex.xml.
2148 // Move into ServiceInfo later.
2149 ServiceInfo::RepoStates newRepoStates;
2150
2151 // set service alias and base url for all collected repositories
2152 for_( it, collector.repos.begin(), collector.repos.end() )
2153 {
2154 // First of all: Prepend service alias:
2155 it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
2156 // set reference to the parent service
2157 it->setService( service.alias() );
2158
2159 // remember the new parsed repo state
2160 newRepoStates[it->alias()] = *it;
2161
2162 // - If the repo url was not set by the repoindex parser, set service's url.
2163 // - Libzypp currently has problem with separate url + path handling so just
2164 // append a path, if set, to the baseurls
2165 // - Credentials in the url authority will be extracted later, either if the
2166 // repository is added or if we check for changed urls.
2167 Pathname path;
2168 if ( !it->path().empty() )
2169 {
2170 if ( it->path() != "/" )
2171 path = it->path();
2172 it->setPath("");
2173 }
2174
2175 if ( it->baseUrlsEmpty() )
2176 {
2177 Url url( service.rawUrl() );
2178 if ( !path.empty() )
2179 url.setPathName( url.getPathName() / path );
2180 it->setBaseUrl( std::move(url) );
2181 }
2182 else if ( !path.empty() )
2183 {
2184 RepoInfo::url_set urls( it->rawBaseUrls() );
2185 for ( Url & url : urls )
2186 {
2187 url.setPathName( url.getPathName() / path );
2188 }
2189 it->setBaseUrls( std::move(urls) );
2190 }
2191 }
2192
2194 // Now compare collected repos with the ones in the system...
2195 //
2196 RepoInfoList oldRepos;
2197 getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
2198
2200 // find old repositories to remove...
2201 for_( oldRepo, oldRepos.begin(), oldRepos.end() )
2202 {
2203 if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
2204 {
2205 if ( oldRepo->enabled() )
2206 {
2207 // Currently enabled. If this was a user modification remember the state.
2208 const auto & last = service.repoStates().find( oldRepo->alias() );
2209 if ( last != service.repoStates().end() && ! last->second.enabled )
2210 {
2211 DBG << "Service removes user enabled repo " << oldRepo->alias() << endl;
2212 service.addRepoToEnable( oldRepo->alias() );
2213 serviceModified = true;
2214 }
2215 else
2216 DBG << "Service removes enabled repo " << oldRepo->alias() << endl;
2217 }
2218 else
2219 DBG << "Service removes disabled repo " << oldRepo->alias() << endl;
2220
2221 removeRepository( *oldRepo );
2222 }
2223 }
2224
2226 // create missing repositories and modify existing ones if needed...
2227 UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
2228 for_( it, collector.repos.begin(), collector.repos.end() )
2229 {
2230 // User explicitly requested the repo being enabled?
2231 // User explicitly requested the repo being disabled?
2232 // And hopefully not both ;) If so, enable wins.
2233
2234 TriBool toBeEnabled( indeterminate ); // indeterminate - follow the service request
2235 DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << endl;
2236
2237 if ( options_r.testFlag( RefreshService_restoreStatus ) )
2238 {
2239 DBG << "Opt RefreshService_restoreStatus " << it->alias() << endl;
2240 // this overrides any pending request!
2241 // Remove from enable request list.
2242 // NOTE: repoToDisable is handled differently.
2243 // It gets cleared on each refresh.
2244 service.delRepoToEnable( it->alias() );
2245 // toBeEnabled stays indeterminate!
2246 }
2247 else
2248 {
2249 if ( service.repoToEnableFind( it->alias() ) )
2250 {
2251 DBG << "User request to enable service repo " << it->alias() << endl;
2252 toBeEnabled = true;
2253 // Remove from enable request list.
2254 // NOTE: repoToDisable is handled differently.
2255 // It gets cleared on each refresh.
2256 service.delRepoToEnable( it->alias() );
2257 serviceModified = true;
2258 }
2259 else if ( service.repoToDisableFind( it->alias() ) )
2260 {
2261 DBG << "User request to disable service repo " << it->alias() << endl;
2262 toBeEnabled = false;
2263 }
2264 }
2265
2266 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2267 if ( oldRepo == oldRepos.end() )
2268 {
2269 // Not found in oldRepos ==> a new repo to add
2270
2271 // Make sure the service repo is created with the appropriate enablement
2272 if ( ! indeterminate(toBeEnabled) )
2273 it->setEnabled( ( bool ) toBeEnabled );
2274
2275 DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << endl;
2276 addRepository( *it );
2277 }
2278 else
2279 {
2280 // ==> an exising repo to check
2281 bool oldRepoModified = false;
2282
2283 if ( indeterminate(toBeEnabled) )
2284 {
2285 // No user request: check for an old user modificaton otherwise follow service request.
2286 // NOTE: Assert toBeEnabled is boolean afterwards!
2287 if ( oldRepo->enabled() == it->enabled() )
2288 toBeEnabled = it->enabled(); // service requests no change to the system
2289 else if (options_r.testFlag( RefreshService_restoreStatus ) )
2290 {
2291 toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
2292 DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << endl;
2293 }
2294 else
2295 {
2296 const auto & last = service.repoStates().find( oldRepo->alias() );
2297 if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
2298 toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
2299 else
2300 {
2301 toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
2302 DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << endl;
2303 }
2304 }
2305 }
2306
2307 // changed enable?
2308 if ( toBeEnabled == oldRepo->enabled() )
2309 {
2310 DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << endl;
2311 }
2312 else if ( toBeEnabled )
2313 {
2314 DBG << "Service repo " << it->alias() << " gets enabled" << endl;
2315 oldRepo->setEnabled( true );
2316 oldRepoModified = true;
2317 }
2318 else
2319 {
2320 DBG << "Service repo " << it->alias() << " gets disabled" << endl;
2321 oldRepo->setEnabled( false );
2322 oldRepoModified = true;
2323 }
2324
2325 // all other attributes follow the service request:
2326
2327 // changed name (raw!)
2328 if ( oldRepo->rawName() != it->rawName() )
2329 {
2330 DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << endl;
2331 oldRepo->setName( it->rawName() );
2332 oldRepoModified = true;
2333 }
2334
2335 // changed autorefresh
2336 if ( oldRepo->autorefresh() != it->autorefresh() )
2337 {
2338 DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << endl;
2339 oldRepo->setAutorefresh( it->autorefresh() );
2340 oldRepoModified = true;
2341 }
2342
2343 // changed priority?
2344 if ( oldRepo->priority() != it->priority() )
2345 {
2346 DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << endl;
2347 oldRepo->setPriority( it->priority() );
2348 oldRepoModified = true;
2349 }
2350
2351 // changed url?
2352 {
2353 RepoInfo::url_set newUrls( it->rawBaseUrls() );
2354 urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
2355 if ( oldRepo->rawBaseUrls() != newUrls )
2356 {
2357 DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
2358 oldRepo->setBaseUrls( std::move(newUrls) );
2359 oldRepoModified = true;
2360 }
2361 }
2362
2363 // changed gpg check settings?
2364 // ATM only plugin services can set GPG values.
2365 if ( service.type() == ServiceType::PLUGIN )
2366 {
2367 TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
2368 TriBool ngpg[3];
2369 oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
2370 it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
2371#define Z_CHKGPG(I,N) \
2372 if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
2373 { \
2374 DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
2375 oldRepo->set##N##Check( ngpg[I] ); \
2376 oldRepoModified = true; \
2377 }
2378 Z_CHKGPG( 0, Gpg );
2379 Z_CHKGPG( 1, RepoGpg );
2380 Z_CHKGPG( 2, PkgGpg );
2381#undef Z_CHKGPG
2382 }
2383
2384 // save if modified:
2385 if ( oldRepoModified )
2386 {
2387 modifyRepository( oldRepo->alias(), *oldRepo );
2388 }
2389 }
2390 }
2391
2392 // Unlike reposToEnable, reposToDisable is always cleared after refresh.
2393 if ( ! service.reposToDisableEmpty() )
2394 {
2395 service.clearReposToDisable();
2396 serviceModified = true;
2397 }
2398
2399 // Remember original service request for next refresh
2400 if ( service.repoStates() != newRepoStates )
2401 {
2402 service.setRepoStates( std::move(newRepoStates) );
2403 serviceModified = true;
2404 }
2405
2407 // save service if modified: (unless a plugin service)
2408 if ( service.type() != ServiceType::PLUGIN )
2409 {
2410 if ( service.ttl() )
2411 {
2412 service.setLrf( Date::now() ); // remember last refresh
2413 serviceModified = true; // or use a cookie file
2414 }
2415
2416 if ( serviceModified )
2417 {
2418 // write out modified service file.
2419 modifyService( service.alias(), service );
2420 }
2421 }
2422
2423 if ( uglyHack.first )
2424 {
2425 throw( uglyHack.second ); // intentionally not ZYPP_THROW
2426 }
2427 }
2428
2430
2431 void RepoManager::Impl::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
2432 {
2433 MIL << "Going to modify service " << oldAlias << endl;
2434
2435 // we need a writable copy to link it to the file where
2436 // it is saved if we modify it
2437 ServiceInfo service(newService);
2438
2439 if ( service.type() == ServiceType::PLUGIN )
2440 {
2442 }
2443
2444 const ServiceInfo & oldService = getService(oldAlias);
2445
2446 Pathname location = oldService.filepath();
2447 if( location.empty() )
2448 {
2449 ZYPP_THROW(ServiceException( oldService, _("Can't figure out where the service is stored.") ));
2450 }
2451
2452 // remember: there may multiple services being defined in one file:
2453 ServiceSet tmpSet;
2454 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2455
2456 filesystem::assert_dir(location.dirname());
2457 std::ofstream file(location.c_str());
2458 for_(it, tmpSet.begin(), tmpSet.end())
2459 {
2460 if( *it != oldAlias )
2461 it->dumpAsIniOn(file);
2462 }
2463 service.dumpAsIniOn(file);
2464 file.close();
2465 service.setFilepath(location);
2466
2467 _services.erase(oldAlias);
2468 _services.insert(service);
2469 // check for credentials in Urls
2470 UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
2471
2472
2473 // changed properties affecting also repositories
2474 if ( oldAlias != service.alias() // changed alias
2475 || oldService.enabled() != service.enabled() ) // changed enabled status
2476 {
2477 std::vector<RepoInfo> toModify;
2478 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
2479 for_( it, toModify.begin(), toModify.end() )
2480 {
2481 if ( oldService.enabled() != service.enabled() )
2482 {
2483 if ( service.enabled() )
2484 {
2485 // reset to last refreshs state
2486 const auto & last = service.repoStates().find( it->alias() );
2487 if ( last != service.repoStates().end() )
2488 it->setEnabled( last->second.enabled );
2489 }
2490 else
2491 it->setEnabled( false );
2492 }
2493
2494 if ( oldAlias != service.alias() )
2495 it->setService(service.alias());
2496
2497 modifyRepository(it->alias(), *it);
2498 }
2499 }
2500
2502 }
2503
2505
2507 {
2508 try
2509 {
2510 MediaSetAccess access(url);
2511 if ( access.doesFileExist("/repo/repoindex.xml") )
2513 }
2514 catch ( const media::MediaException &e )
2515 {
2516 ZYPP_CAUGHT(e);
2517 // TranslatorExplanation '%s' is an URL
2518 RepoException enew(str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
2519 enew.remember(e);
2520 ZYPP_THROW(enew);
2521 }
2522 catch ( const Exception &e )
2523 {
2524 ZYPP_CAUGHT(e);
2525 // TranslatorExplanation '%s' is an URL
2526 Exception enew(str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
2527 enew.remember(e);
2528 ZYPP_THROW(enew);
2529 }
2530
2532 }
2533
2535 //
2536 // CLASS NAME : RepoManager
2537 //
2539
2541 : _pimpl( new Impl(opt) )
2542 {}
2543
2545 {}
2546
2548 { return _pimpl->repoEmpty(); }
2549
2551 { return _pimpl->repoSize(); }
2552
2554 { return _pimpl->repoBegin(); }
2555
2557 { return _pimpl->repoEnd(); }
2558
2559 RepoInfo RepoManager::getRepo( const std::string & alias ) const
2560 { return _pimpl->getRepo( alias ); }
2561
2562 bool RepoManager::hasRepo( const std::string & alias ) const
2563 { return _pimpl->hasRepo( alias ); }
2564
2565 std::string RepoManager::makeStupidAlias( const Url & url_r )
2566 {
2567 std::string ret( url_r.getScheme() );
2568 if ( ret.empty() )
2569 ret = "repo-";
2570 else
2571 ret += "-";
2572
2573 std::string host( url_r.getHost() );
2574 if ( ! host.empty() )
2575 {
2576 ret += host;
2577 ret += "-";
2578 }
2579
2580 static Date::ValueType serial = Date::now();
2581 ret += Digest::digest( Digest::sha1(), str::hexstring( ++serial ) +url_r.asCompleteString() ).substr(0,8);
2582 return ret;
2583 }
2584
2586 { return _pimpl->metadataStatus( info ); }
2587
2589 { return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
2590
2592 { return _pimpl->metadataPath( info ); }
2593
2595 { return _pimpl->packagesPath( info ); }
2596
2598 { return _pimpl->refreshMetadata( info, policy, progressrcv ); }
2599
2600 void RepoManager::cleanMetadata( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2601 { return _pimpl->cleanMetadata( info, progressrcv ); }
2602
2603 void RepoManager::cleanPackages( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2604 { return _pimpl->cleanPackages( info, progressrcv ); }
2605
2607 { return _pimpl->cacheStatus( info ); }
2608
2609 void RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, const ProgressData::ReceiverFnc & progressrcv )
2610 { return _pimpl->buildCache( info, policy, progressrcv ); }
2611
2612 void RepoManager::cleanCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2613 { return _pimpl->cleanCache( info, progressrcv ); }
2614
2615 bool RepoManager::isCached( const RepoInfo &info ) const
2616 { return _pimpl->isCached( info ); }
2617
2618 void RepoManager::loadFromCache( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2619 { return _pimpl->loadFromCache( info, progressrcv ); }
2620
2622 { return _pimpl->cleanCacheDirGarbage( progressrcv ); }
2623
2624 repo::RepoType RepoManager::probe( const Url & url, const Pathname & path ) const
2625 { return _pimpl->probe( url, path ); }
2626
2628 { return _pimpl->probe( url ); }
2629
2630 void RepoManager::addRepository( const RepoInfo &info, const ProgressData::ReceiverFnc & progressrcv )
2631 { return _pimpl->addRepository( info, progressrcv ); }
2632
2633 void RepoManager::addRepositories( const Url &url, const ProgressData::ReceiverFnc & progressrcv )
2634 { return _pimpl->addRepositories( url, progressrcv ); }
2635
2636 void RepoManager::removeRepository( const RepoInfo & info, const ProgressData::ReceiverFnc & progressrcv )
2637 { return _pimpl->removeRepository( info, progressrcv ); }
2638
2639 void RepoManager::modifyRepository( const std::string &alias, const RepoInfo & newinfo, const ProgressData::ReceiverFnc & progressrcv )
2640 { return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
2641
2642 RepoInfo RepoManager::getRepositoryInfo( const std::string &alias, const ProgressData::ReceiverFnc & progressrcv )
2643 { return _pimpl->getRepositoryInfo( alias, progressrcv ); }
2644
2645 RepoInfo RepoManager::getRepositoryInfo( const Url & url, const url::ViewOption & urlview, const ProgressData::ReceiverFnc & progressrcv )
2646 { return _pimpl->getRepositoryInfo( url, urlview, progressrcv ); }
2647
2649 { return _pimpl->serviceEmpty(); }
2650
2652 { return _pimpl->serviceSize(); }
2653
2655 { return _pimpl->serviceBegin(); }
2656
2658 { return _pimpl->serviceEnd(); }
2659
2660 ServiceInfo RepoManager::getService( const std::string & alias ) const
2661 { return _pimpl->getService( alias ); }
2662
2663 bool RepoManager::hasService( const std::string & alias ) const
2664 { return _pimpl->hasService( alias ); }
2665
2667 { return _pimpl->probeService( url ); }
2668
2669 void RepoManager::addService( const std::string & alias, const Url& url )
2670 { return _pimpl->addService( alias, url ); }
2671
2672 void RepoManager::addService( const ServiceInfo & service )
2673 { return _pimpl->addService( service ); }
2674
2675 void RepoManager::removeService( const std::string & alias )
2676 { return _pimpl->removeService( alias ); }
2677
2679 { return _pimpl->removeService( service ); }
2680
2682 { return _pimpl->refreshServices( options_r ); }
2683
2684 void RepoManager::refreshService( const std::string & alias, const RefreshServiceOptions & options_r )
2685 { return _pimpl->refreshService( alias, options_r ); }
2686
2687 void RepoManager::refreshService( const ServiceInfo & service, const RefreshServiceOptions & options_r )
2688 { return _pimpl->refreshService( service, options_r ); }
2689
2690 void RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & service )
2691 { return _pimpl->modifyService( oldAlias, service ); }
2692
2694
2695 std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
2696 { return str << *obj._pimpl; }
2697
2699} // 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:174
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:140
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
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
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 a new service by its 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 its 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:1015
Pathname builtinRepoSolvfilesPath() const
The builtin config file value.
Definition: ZConfig.cc:960
bool repo_add_probe() const
Whether repository urls should be probed.
Definition: ZConfig.cc:1012
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:126
Pathname builtinRepoPackagesPath() const
The builtin config file value.
Definition: ZConfig.cc:963
Pathname builtinRepoMetadataPath() const
The builtin config file value.
Definition: ZConfig.cc:957
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
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:167
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
std::list< RepoInfo > readRepoFile(const Url &repo_file)
Parses repo_file and returns a list of RepoInfo objects corresponding to repositories found within th...
Definition: RepoManager.cc:458
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:430
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:426
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:418
#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