22#include <solv/solvversion.h>
24#include <zypp-core/base/InputStream>
25#include <zypp/base/LogTools.h>
26#include <zypp/base/Gettext.h>
27#include <zypp-core/base/DefaultIntegral>
28#include <zypp/base/Function.h>
29#include <zypp/base/Regex.h>
30#include <zypp/PathInfo.h>
31#include <zypp/TmpPath.h>
38#include <zypp-media/auth/CredentialManager>
39#include <zypp-media/MediaException>
41#include <zypp/ExternalProgram.h>
42#include <zypp/ManagedFile.h>
48#include <zypp/repo/yum/Downloader.h>
49#include <zypp/repo/susetags/Downloader.h>
66#define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc()
78 const char * env = getenv(
"ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
108 class UrlCredentialExtractor
111 UrlCredentialExtractor( Pathname & root_r )
115 ~UrlCredentialExtractor()
119 bool collect(
const Url & url_r )
121 bool ret = url_r.hasCredentialsInAuthority();
125 _cmPtr->addUserCred( url_r );
130 template<
class TContainer>
131 bool collect(
const TContainer & urls_r )
132 {
bool ret =
false;
for (
const Url & url : urls_r ) {
if ( collect( url ) && !ret ) ret =
true; }
return ret; }
135 bool extract( Url & url_r )
137 bool ret = collect( url_r );
139 url_r.setPassword( std::string() );
143 template<
class TContainer>
144 bool extract( TContainer & urls_r )
145 {
bool ret =
false;
for ( Url & url : urls_r ) {
if ( extract( url ) && !ret ) ret =
true; }
return ret; }
149 scoped_ptr<media::CredentialManager>
_cmPtr;
164 MediaMounter(
const Url & url_r )
166 media::MediaManager mediamanager;
167 _mid = mediamanager.open( url_r );
168 mediamanager.attach(
_mid );
174 media::MediaManager mediamanager;
175 mediamanager.release(
_mid );
176 mediamanager.close(
_mid );
183 Pathname getPathName(
const Pathname & path_r = Pathname() )
const
185 media::MediaManager mediamanager;
186 return mediamanager.localPath(
_mid, path_r );
195 template <
class Iterator>
196 inline bool foundAliasIn(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
198 for_( it, begin_r, end_r )
199 if ( it->alias() == alias_r )
204 template <
class Container>
205 inline bool foundAliasIn(
const std::string & alias_r,
const Container & cont_r )
206 {
return foundAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
209 template <
class Iterator>
210 inline Iterator findAlias(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
212 for_( it, begin_r, end_r )
213 if ( it->alias() == alias_r )
218 template <
class Container>
219 inline typename Container::iterator findAlias(
const std::string & alias_r, Container & cont_r )
220 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
222 template <
class Container>
223 inline typename Container::const_iterator findAlias(
const std::string & alias_r,
const Container & cont_r )
224 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
228 inline std::string filenameFromAlias(
const std::string & alias_r,
const std::string & stem_r )
230 std::string filename( alias_r );
234 filename = Pathname(filename).extend(
"."+stem_r).asString();
235 MIL <<
"generating filename for " << stem_r <<
" [" << alias_r <<
"] : '" << filename <<
"'" << endl;
259 RepoCollector(
const std::string & targetDistro_)
263 bool collect(
const RepoInfo &repo )
267 && !repo.targetDistribution().empty()
271 <<
"Skipping repository meant for '" << repo.targetDistribution()
272 <<
"' distribution (current distro is '"
278 repos.push_back(repo);
292 std::list<RepoInfo> repositories_in_file(
const Pathname & file )
294 MIL <<
"repo file: " << file << endl;
295 RepoCollector collector;
296 parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) );
297 return std::move(collector.repos);
310 std::list<RepoInfo> repositories_in_dir(
const Pathname &dir )
312 MIL <<
"directory " << dir << endl;
313 std::list<RepoInfo>
repos;
314 bool nonroot( geteuid() != 0 );
315 if ( nonroot && ! PathInfo(dir).userMayRX() )
317 JobReport::warning( str::Format(
_(
"Cannot read repo directory '%1%': Permission denied")) % dir );
321 std::list<Pathname> entries;
328 str::regex allowedRepoExt(
"^\\.repo(_[0-9]+)?$");
329 for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
333 if ( nonroot && ! PathInfo(*it).userMayR() )
335 JobReport::warning( str::Format(
_(
"Cannot read repo file '%1%': Permission denied")) % *it );
339 const std::list<RepoInfo> & tmp( repositories_in_file( *it ) );
340 repos.insert(
repos.end(), tmp.begin(), tmp.end() );
350 inline void assert_alias(
const RepoInfo & info )
352 if ( info.alias().empty() )
356 if ( info.alias()[0] ==
'.')
358 info,
_(
"Repository alias cannot start with dot.")));
361 inline void assert_alias(
const ServiceInfo & info )
363 if ( info.alias().empty() )
367 if ( info.alias()[0] ==
'.')
369 info,
_(
"Service alias cannot start with dot.")));
374 inline void assert_urls(
const RepoInfo & info )
376 if ( info.baseUrlsEmpty() )
380 inline void assert_url(
const ServiceInfo & info )
382 if ( ! info.url().isValid() )
392 inline bool isTmpRepo(
const RepoInfo & info_r )
393 {
return( info_r.filepath().empty() && info_r.usesAutoMethadataPaths() ); }
401 inline Pathname rawcache_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
404 return isTmpRepo( info ) ? info.metadataPath() : opt.repoRawCachePath / info.escaped_alias();
415 inline Pathname rawproductdata_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
416 {
return rawcache_path_for_repoinfo( opt, info ) / info.path(); }
421 inline Pathname packagescache_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
424 return isTmpRepo( info ) ? info.packagesPath() : opt.repoPackagesCachePath / info.escaped_alias();
430 inline Pathname solv_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
433 return isTmpRepo( info ) ? info.metadataPath().dirname() /
"%SLV%" : opt.repoSolvCachePath / info.escaped_alias();
439 class ServiceCollector
442 typedef std::set<ServiceInfo> ServiceSet;
444 ServiceCollector( ServiceSet & services_r )
448 bool operator()(
const ServiceInfo & service_r )
const
460 inline bool autoPruneInDir(
const Pathname & path_r )
461 {
return not PathInfo(path_r/
".no_auto_prune").isExist(); }
470 DBG <<
"reading repo file " << repo_file <<
", local path: " << local << endl;
472 return repositories_in_file(local);
511#define OUTS(X) str << " " #X "\t" << obj.X << endl
512 str <<
"RepoManagerOptions (" << obj.
rootDir <<
") {" << endl;
513 OUTS( repoRawCachePath );
514 OUTS( repoSolvCachePath );
515 OUTS( repoPackagesCachePath );
516 OUTS( knownReposPath );
517 OUTS( knownServicesPath );
534 , _pluginRepoverification( _options.pluginsPath/
"repoverification", _options.rootDir )
536 init_knownServices();
537 init_knownRepositories();
544 && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir ==
"/" ) )
547 std::list<Pathname> entries;
549 if ( ! entries.empty() )
552 cmd.push_back(
"<" );
553 cmd.push_back(
">" );
554 cmd.push_back(
"PROGRAM" );
555 for (
const auto & rinfo :
repos() )
557 if ( ! rinfo.enabled() )
559 cmd.push_back(
"-R" );
560 cmd.push_back( rinfo.alias() );
561 cmd.push_back(
"-t" );
562 cmd.push_back( rinfo.type().asString() );
563 cmd.push_back(
"-p" );
564 cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() );
567 for_( it, entries.begin(), entries.end() )
590 bool hasRepo(
const std::string & alias )
const
591 {
return foundAliasIn( alias,
repos() ); }
601 {
return rawcache_path_for_repoinfo( _options, info ); }
604 {
return packagescache_path_for_repoinfo( _options, info ); }
608 RefreshCheckStatus checkIfToRefreshMetadata(
const RepoInfo & info,
const Url & url, RawMetadataRefreshPolicy policy );
626 {
return PathInfo(solv_path_for_repoinfo( _options, info ) /
"solv").
isExist(); }
651 {
return foundAliasIn( alias,
_services ); }
664 void removeService(
const std::string & alias );
666 { removeService( service.
alias() ); }
668 void refreshServices(
const RefreshServiceOptions & options_r );
670 void refreshService(
const std::string & alias,
const RefreshServiceOptions & options_r );
672 { refreshService( service.
alias(), options_r ); }
674 void modifyService(
const std::string & oldAlias,
const ServiceInfo & newService );
686 {
return filenameFromAlias( info.
alias(),
"repo" ); }
689 {
return filenameFromAlias( info.
alias(),
"service" ); }
693 Pathname base = solv_path_for_repoinfo( _options, info );
700 template<
typename OutputIterator>
705 boost::make_filter_iterator( filter,
repos().end(),
repos().end() ),
726 friend Impl * rwcowClone<Impl>(
const Impl * rhs );
729 {
return new Impl( *
this ); }
735 {
return str <<
"RepoManager::Impl"; }
739 void RepoManager::Impl::saveService( ServiceInfo & service )
const
742 Pathname servfile = generateNonExistingName( _options.knownServicesPath,
743 generateFilename( service ) );
744 service.setFilepath( servfile );
746 MIL <<
"saving service in " << servfile << endl;
748 std::ofstream file( servfile.c_str() );
754 service.dumpAsIniOn( file );
755 MIL <<
"done" << endl;
773 Pathname RepoManager::Impl::generateNonExistingName(
const Pathname & dir,
774 const std::string & basefilename )
const
776 std::string final_filename = basefilename;
778 while ( PathInfo(dir + final_filename).isExist() )
783 return dir + Pathname(final_filename);
788 void RepoManager::Impl::init_knownServices()
790 Pathname dir = _options.knownServicesPath;
791 std::list<Pathname> entries;
792 if (PathInfo(dir).isExist())
801 for_(it, entries.begin(), entries.end() )
803 parser::ServiceFileReader(*it, ServiceCollector(
_services));
807 repo::PluginServices(_options.pluginsPath/
"services", ServiceCollector(
_services));
817 inline void cleanupNonRepoMetadtaFolders(
const Pathname & cachePath_r,
818 const Pathname & defaultCachePath_r,
819 const std::list<std::string> & repoEscAliases_r )
821 if ( cachePath_r != defaultCachePath_r )
824 std::list<std::string> entries;
828 std::set<std::string> oldfiles;
829 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
830 std::inserter( oldfiles, oldfiles.end() ) );
836 for (
const std::string & old : oldfiles )
840 pi( cachePath_r/old );
850 void RepoManager::Impl::init_knownRepositories()
852 MIL <<
"start construct known repos" << endl;
854 if ( PathInfo(_options.knownReposPath).isExist() )
856 std::list<std::string> repoEscAliases;
857 std::list<RepoInfo> orphanedRepos;
858 for ( RepoInfo & repoInfo : repositories_in_dir(_options.knownReposPath) )
861 repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo) );
863 repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) );
865 _reposX.insert( repoInfo );
868 const std::string & serviceAlias( repoInfo.service() );
869 if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
871 WAR <<
"Schedule orphaned service repo for deletion: " << repoInfo << endl;
872 orphanedRepos.push_back( repoInfo );
876 repoEscAliases.push_back(repoInfo.escaped_alias());
880 if ( ! orphanedRepos.empty() )
882 for (
const auto & repoInfo : orphanedRepos )
884 MIL <<
"Delete orphaned service repo " << repoInfo.alias() << endl;
888 JobReport::warning( str::Format(
_(
"Unknown service '%1%': Removing orphaned service repository '%2%'"))
890 % repoInfo.alias() );
892 removeRepository( repoInfo );
894 catch (
const Exception & caugth )
906 repoEscAliases.sort();
907 cleanupNonRepoMetadtaFolders( _options.repoRawCachePath,
910 cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath,
914 if ( autoPruneInDir( _options.repoPackagesCachePath ) )
915 cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath,
919 MIL <<
"end construct known repos" << endl;
924 RepoStatus RepoManager::Impl::metadataStatus(
const RepoInfo & info )
const
926 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
927 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
931 if ( repokind == RepoType::NONE )
932 repokind = probeCache( productdatapath );
939 switch ( repokind.
toEnum() )
941 case RepoType::RPMMD_e :
942 status = RepoStatus( productdatapath/
"repodata/repomd.xml");
943 if ( info.requireStatusWithMediaFile() )
944 status = status && RepoStatus( mediarootpath/
"media.1/media" );
947 case RepoType::YAST2_e :
948 status = RepoStatus( productdatapath/
"content" ) && RepoStatus( mediarootpath/
"media.1/media" );
951 case RepoType::RPMPLAINDIR_e :
955 case RepoType::NONE_e :
962 if ( ! status.empty() )
963 status = status && RepoStatus( info );
969 void RepoManager::Impl::touchIndexFile(
const RepoInfo & info )
971 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
974 if ( repokind.
toEnum() == RepoType::NONE_e )
976 repokind = probeCache( productdatapath );
978 if (repokind == RepoType::NONE_e)
982 switch ( repokind.
toEnum() )
984 case RepoType::RPMMD_e :
985 p = Pathname(productdatapath +
"/repodata/repomd.xml");
988 case RepoType::YAST2_e :
989 p = Pathname(productdatapath +
"/content");
992 case RepoType::RPMPLAINDIR_e :
993 p = Pathname(productdatapath +
"/cookie");
996 case RepoType::NONE_e :
1006 RepoManager::RefreshCheckStatus RepoManager::Impl::checkIfToRefreshMetadata(
const RepoInfo & info,
const Url & url, RawMetadataRefreshPolicy policy )
1011 MIL <<
"Check if to refresh repo " << info.alias() <<
" at " << url <<
" (" << info.type() <<
")" << endl;
1013 refreshGeoIPData( { url } );
1016 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1018 RepoStatus oldstatus = metadataStatus( info );
1020 if ( oldstatus.empty() )
1022 MIL <<
"No cached metadata, going to refresh" << endl;
1023 return REFRESH_NEEDED;
1026 if ( url.schemeIsVolatile() )
1028 MIL <<
"Never refresh CD/DVD" << endl;
1029 return REPO_UP_TO_DATE;
1032 if ( policy == RefreshForced )
1034 MIL <<
"Forced refresh!" << endl;
1035 return REFRESH_NEEDED;
1038 if ( url.schemeIsLocal() )
1040 policy = RefreshIfNeededIgnoreDelay;
1044 if ( policy != RefreshIfNeededIgnoreDelay )
1049 RepoStatus cachestatus = cacheStatus( info );
1051 if ( oldstatus == cachestatus )
1059 WAR <<
"Repository '" << info.alias() <<
"' was refreshed in the future!" << endl;
1063 MIL <<
"Repository '" << info.alias()
1064 <<
"' has been refreshed less than repo.refresh.delay ("
1066 <<
") minutes ago. Advising to skip refresh" << endl;
1067 return REPO_CHECK_DELAYED;
1072 MIL <<
"Metadata and solv cache don't match. Check data on server..." << endl;
1076 repo::RepoType repokind = info.type();
1078 if ( repokind == RepoType::NONE )
1079 repokind = probe( url, info.path() );
1082 RepoStatus newstatus;
1083 switch ( repokind.toEnum() )
1085 case RepoType::RPMMD_e:
1087 MediaSetAccess media( url );
1092 case RepoType::YAST2_e:
1094 MediaSetAccess media( url );
1099 case RepoType::RPMPLAINDIR_e:
1100 newstatus = RepoStatus( info ) && RepoStatus( MediaMounter(url).getPathName(info.path()) );
1104 case RepoType::NONE_e:
1110 if ( oldstatus == newstatus )
1112 MIL <<
"repo has not changed" << endl;
1113 touchIndexFile( info );
1114 return REPO_UP_TO_DATE;
1118 MIL <<
"repo has changed, going to refresh" << endl;
1119 return REFRESH_NEEDED;
1122 catch (
const Exception &e )
1125 ERR <<
"refresh check failed for " << url << endl;
1129 return REFRESH_NEEDED;
1133 void RepoManager::Impl::refreshMetadata(
const RepoInfo & info, RawMetadataRefreshPolicy policy,
const ProgressData::ReceiverFnc & progress )
1139 refreshGeoIPData( info.baseUrls() );
1142 RepoException rexception( info,
PL_(
"Valid metadata not found at specified URL",
1143 "Valid metadata not found at specified URLs",
1144 info.baseUrlsSize() ) );
1147 media::ScopedDisableMediaChangeReport guard( info.baseUrlsSize() > 1 );
1157 if (checkIfToRefreshMetadata(info, url, policy)!=REFRESH_NEEDED)
1160 MIL <<
"Going to refresh metadata from " << url << endl;
1165 repo::RepoType repokind = info.type();
1167 repo::RepoType probed = probe( *it, info.path() );
1168 if ( repokind != probed )
1172 for_( it, repoBegin(), repoEnd() )
1174 if ( info.alias() == (*it).alias() )
1176 RepoInfo modifiedrepo = *it;
1177 modifiedrepo.setType( repokind );
1184 info.setProbedType( repokind );
1187 if ( repokind.toEnum() == RepoType::NONE_e )
1191 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1194 Exception ex(
str::form(
_(
"Can't create %s"), mediarootpath.c_str()) );
1200 if( tmpdir.path().empty() )
1202 Exception ex(
_(
"Can't create metadata cache directory."));
1206 if ( ( repokind.toEnum() == RepoType::RPMMD_e ) ||
1207 ( repokind.toEnum() == RepoType::YAST2_e ) )
1209 MediaSetAccess media(url);
1210 shared_ptr<repo::Downloader> downloader_ptr;
1212 MIL <<
"Creating downloader for [ " << info.alias() <<
" ]" << endl;
1214 if ( repokind.toEnum() == RepoType::RPMMD_e ) {
1216 if ( _pluginRepoverification.checkIfNeeded() )
1217 downloader_ptr->setPluginRepoverification( _pluginRepoverification );
1228 for_( it, repoBegin(), repoEnd() )
1230 Pathname cachepath(rawcache_path_for_repoinfo( _options, *it ));
1231 if ( PathInfo(cachepath).isExist() )
1232 downloader_ptr->addCachePath(cachepath);
1235 downloader_ptr->download( media, tmpdir.path() );
1237 else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e )
1240 MediaMounter media( url );
1241 RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) );
1243 Pathname productpath( tmpdir.path() / info.path() );
1245 newstatus.saveToCookieFile( productpath/
"cookie" );
1255 if ( ! isTmpRepo( info ) )
1261 catch (
const Exception &e )
1264 ERR <<
"Trying another url..." << endl;
1269 if (it == info.baseUrlsBegin())
1270 rexception.remember(e);
1272 rexception.addHistory( e.asUserString() );
1276 ERR <<
"No more urls..." << endl;
1284 ProgressData progress(100);
1285 progress.sendTo(progressfnc);
1292 void RepoManager::Impl::cleanPackages(
const RepoInfo & info,
const ProgressData::ReceiverFnc & progressfnc,
bool isAutoClean_r )
1294 ProgressData progress(100);
1295 progress.sendTo(progressfnc);
1298 const Pathname & rpc { packagescache_path_for_repoinfo(_options, info) };
1299 if ( not isAutoClean_r || autoPruneInDir( rpc.dirname() ) )
1305 void RepoManager::Impl::buildCache(
const RepoInfo & info, CacheBuildPolicy policy,
const ProgressData::ReceiverFnc & progressrcv )
1308 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1309 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
1313 Exception ex(
str::form(
_(
"Can't create %s"), _options.repoCachePath.c_str()) );
1316 RepoStatus raw_metadata_status = metadataStatus(info);
1317 if ( raw_metadata_status.empty() )
1322 refreshMetadata(info, RefreshIfNeeded, progressrcv );
1323 raw_metadata_status = metadataStatus(info);
1326 bool needs_cleaning =
false;
1327 if ( isCached( info ) )
1329 MIL << info.alias() <<
" is already cached." << endl;
1330 RepoStatus cache_status = cacheStatus(info);
1332 if ( cache_status == raw_metadata_status )
1334 MIL << info.alias() <<
" cache is up to date with metadata." << endl;
1335 if ( policy == BuildIfNeeded )
1338 const Pathname & base = solv_path_for_repoinfo( _options, info);
1339 if ( ! PathInfo(base/
"solv.idx").isExist() )
1345 MIL << info.alias() <<
" cache rebuild is forced" << endl;
1349 needs_cleaning =
true;
1352 ProgressData progress(100);
1353 callback::SendReport<ProgressReport> report;
1354 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1355 progress.name(
str::form(
_(
"Building repository '%s' cache"), info.label().c_str()));
1363 MIL << info.alias() <<
" building cache..." << info.type() << endl;
1365 Pathname base = solv_path_for_repoinfo( _options, info);
1369 Exception ex(
str::form(
_(
"Can't create %s"), base.c_str()) );
1373 if( ! PathInfo(base).userMayW() )
1375 Exception ex(
str::form(
_(
"Can't create cache at %s - no writing permissions."), base.c_str()) );
1378 Pathname solvfile = base /
"solv";
1381 repo::RepoType repokind = info.type();
1384 switch ( repokind.toEnum() )
1386 case RepoType::NONE_e:
1388 repokind = probeCache( productdatapath );
1394 MIL <<
"repo type is " << repokind << endl;
1396 switch ( repokind.toEnum() )
1398 case RepoType::RPMMD_e :
1399 case RepoType::YAST2_e :
1400 case RepoType::RPMPLAINDIR_e :
1404 scoped_ptr<MediaMounter> forPlainDirs;
1407 cmd.push_back( PathInfo(
"/usr/bin/repo2solv" ).isFile() ?
"repo2solv" :
"repo2solv.sh" );
1409 cmd.push_back(
"-o" );
1410 cmd.push_back( solvfile.asString() );
1411 cmd.push_back(
"-X" );
1414 if ( repokind == RepoType::RPMPLAINDIR )
1416 forPlainDirs.reset(
new MediaMounter( info.url() ) );
1418 cmd.push_back(
"-R" );
1420 cmd.push_back( forPlainDirs->getPathName( info.path() ).c_str() );
1423 cmd.push_back( productdatapath.asString() );
1426 std::string errdetail;
1428 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1429 WAR <<
" " << output;
1430 errdetail += output;
1433 int ret = prog.close();
1437 ex.addHistory( str::Str() << prog.command() << endl << errdetail << prog.execError() );
1442 guard.resetDispose();
1451 setCacheStatus(info, raw_metadata_status);
1452 MIL <<
"Commit cache.." << endl;
1465 repo::RepoType RepoManager::Impl::probe(
const Url & url,
const Pathname & path )
const
1467 MIL <<
"going to probe the repo type at " << url <<
" (" << path <<
")" << endl;
1469 if ( url.getScheme() ==
"dir" && ! PathInfo( url.getPathName()/path ).isDir() )
1473 MIL <<
"Probed type NONE (not exists) at " << url <<
" (" << path <<
")" << endl;
1485 bool gotMediaException =
false;
1488 MediaSetAccess access(url);
1491 if ( access.doesFileExist(path/
"/repodata/repomd.xml") )
1493 MIL <<
"Probed type RPMMD at " << url <<
" (" << path <<
")" << endl;
1497 catch (
const media::MediaException &e )
1500 DBG <<
"problem checking for repodata/repomd.xml file" << endl;
1502 gotMediaException =
true;
1507 if ( access.doesFileExist(path/
"/content") )
1509 MIL <<
"Probed type YAST2 at " << url <<
" (" << path <<
")" << endl;
1513 catch (
const media::MediaException &e )
1516 DBG <<
"problem checking for content file" << endl;
1518 gotMediaException =
true;
1522 if ( ! ( url.schemeIsDownloading() || url.schemeIsPlugin() ) )
1524 MediaMounter media( url );
1525 if ( PathInfo(media.getPathName()/path).isDir() )
1528 MIL <<
"Probed type RPMPLAINDIR at " << url <<
" (" << path <<
")" << endl;
1533 catch (
const Exception &e )
1537 Exception enew(
str::form(
_(
"Unknown error reading from '%s'"), url.asString().c_str() ));
1542 if (gotMediaException)
1545 MIL <<
"Probed type NONE at " << url <<
" (" << path <<
")" << endl;
1554 repo::RepoType RepoManager::Impl::probeCache(
const Pathname & path_r )
const
1556 MIL <<
"going to probe the cached repo at " << path_r << endl;
1560 if ( PathInfo(path_r/
"/repodata/repomd.xml").isFile() )
1562 else if ( PathInfo(path_r/
"/content").isFile() )
1564 else if ( PathInfo(path_r).isDir() )
1567 MIL <<
"Probed cached type " << ret <<
" at " << path_r << endl;
1575 MIL <<
"Going to clean up garbage in cache dirs" << endl;
1577 ProgressData progress(300);
1578 progress.sendTo(progressrcv);
1581 std::list<Pathname> cachedirs;
1582 cachedirs.push_back(_options.repoRawCachePath);
1583 cachedirs.push_back(_options.repoPackagesCachePath);
1584 cachedirs.push_back(_options.repoSolvCachePath);
1586 for_( dir, cachedirs.begin(), cachedirs.end() )
1588 if ( PathInfo(*dir).isExist() )
1590 std::list<Pathname> entries;
1595 unsigned sdircount = entries.size();
1596 unsigned sdircurrent = 1;
1597 for_( subdir, entries.begin(), entries.end() )
1601 for_( r, repoBegin(), repoEnd() )
1602 if ( subdir->basename() == r->escaped_alias() )
1603 { found =
true;
break; }
1608 progress.set( progress.val() + sdircurrent * 100 / sdircount );
1613 progress.set( progress.val() + 100 );
1622 ProgressData progress(100);
1623 progress.sendTo(progressrcv);
1626 MIL <<
"Removing raw metadata cache for " << info.alias() << endl;
1637 Pathname solvfile = solv_path_for_repoinfo(_options, info) /
"solv";
1639 if ( ! PathInfo(solvfile).isExist() )
1649 if ( toolversion != LIBSOLV_TOOLVERSION )
1651 repo.eraseFromPool();
1652 ZYPP_THROW(Exception(str::Str() <<
"Solv-file was created by '"<<toolversion<<
"'-parser (want "<<LIBSOLV_TOOLVERSION<<
")."));
1655 catch (
const Exception & exp )
1658 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1659 cleanCache( info, progressrcv );
1660 buildCache( info, BuildIfNeeded, progressrcv );
1672 ProgressData progress(100);
1673 callback::SendReport<ProgressReport> report;
1674 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1675 progress.name(
str::form(
_(
"Adding repository '%s'"), info.label().c_str()));
1678 MIL <<
"Try adding repo " << info << endl;
1680 RepoInfo tosave = info;
1685 if ( _options.probe )
1687 DBG <<
"unknown repository type, probing" << endl;
1688 assert_urls(tosave);
1690 RepoType probedtype( probe( tosave.url(), info.path() ) );
1691 if ( probedtype == RepoType::NONE )
1694 tosave.setType(probedtype);
1702 Pathname repofile = generateNonExistingName(
1703 _options.knownReposPath, generateFilename(tosave));
1705 MIL <<
"Saving repo in " << repofile << endl;
1707 std::ofstream file(repofile.c_str());
1714 tosave.dumpAsIniOn(file);
1715 tosave.setFilepath(repofile);
1716 tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1717 tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1721 RepoInfo & oinfo(
const_cast<RepoInfo &
>(info) );
1722 oinfo.setFilepath(repofile);
1723 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1724 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1726 reposManip().insert(tosave);
1731 UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
1733 HistoryLog(_options.rootDir).addRepository(tosave);
1736 MIL <<
"done" << endl;
1743 for ( std::list<RepoInfo>::const_iterator it =
repos.begin();
1748 for_ ( kit, repoBegin(), repoEnd() )
1750 if ( (*it).alias() == (*kit).alias() )
1752 ERR <<
"To be added repo " << (*it).alias() <<
" conflicts with existing repo " << (*kit).alias() << endl;
1758 std::string filename = Pathname(url.getPathName()).basename();
1760 if ( filename == Pathname() )
1769 Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
1771 MIL <<
"Saving " <<
repos.size() <<
" repo" << (
repos.size() ?
"s" :
"" ) <<
" in " << repofile << endl;
1773 std::ofstream file(repofile.c_str());
1780 for ( std::list<RepoInfo>::iterator it =
repos.begin();
1784 MIL <<
"Saving " << (*it).alias() << endl;
1785 it->dumpAsIniOn(file);
1786 it->setFilepath(repofile);
1787 it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
1788 it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
1789 reposManip().insert(*it);
1791 HistoryLog(_options.rootDir).addRepository(*it);
1794 MIL <<
"done" << endl;
1801 ProgressData progress;
1802 callback::SendReport<ProgressReport> report;
1803 progress.sendTo( ProgressReportAdaptor( progressrcv, report ) );
1804 progress.name(
str::form(
_(
"Removing repository '%s'"), info.label().c_str()));
1806 MIL <<
"Going to delete repo " << info.alias() << endl;
1808 for_( it, repoBegin(), repoEnd() )
1813 if ( (!info.alias().empty()) && ( info.alias() != (*it).alias() ) )
1820 RepoInfo todelete = *it;
1821 if (todelete.filepath().empty())
1828 std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath());
1829 if ( filerepos.size() == 0
1830 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
1834 if ( ! ( ret == 0 || ret == ENOENT ) )
1839 MIL << todelete.alias() <<
" successfully deleted." << endl;
1851 std::ofstream file(todelete.filepath().c_str());
1855 ZYPP_THROW( Exception(
str::form(
_(
"Can't open file '%s' for writing."), todelete.filepath().c_str() )));
1857 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1858 fit != filerepos.end();
1861 if ( (*fit).alias() != todelete.alias() )
1862 (*fit).dumpAsIniOn(file);
1866 CombinedProgressData cSubprogrcv(progress, 20);
1867 CombinedProgressData mSubprogrcv(progress, 40);
1868 CombinedProgressData pSubprogrcv(progress, 40);
1870 if ( isCached(todelete) )
1871 cleanCache( todelete, cSubprogrcv);
1873 cleanMetadata( todelete, mSubprogrcv );
1874 cleanPackages( todelete, pSubprogrcv,
true );
1875 reposManip().erase(todelete);
1876 MIL << todelete.alias() <<
" successfully deleted." << endl;
1877 HistoryLog(_options.rootDir).removeRepository(todelete);
1888 void RepoManager::Impl::modifyRepository(
const std::string & alias,
const RepoInfo & newinfo_r,
const ProgressData::ReceiverFnc & progressrcv )
1890 RepoInfo toedit = getRepositoryInfo(alias);
1891 RepoInfo newinfo( newinfo_r );
1894 if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
1899 if (toedit.filepath().empty())
1906 std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath());
1916 std::ofstream file(toedit.filepath().c_str());
1920 ZYPP_THROW( Exception(
str::form(
_(
"Can't open file '%s' for writing."), toedit.filepath().c_str() )));
1922 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1923 fit != filerepos.end();
1928 if ( (*fit).alias() != toedit.alias() )
1929 (*fit).dumpAsIniOn(file);
1931 newinfo.dumpAsIniOn(file);
1934 if ( toedit.enabled() && !newinfo.enabled() )
1937 const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/
"solv.idx";
1938 if ( PathInfo(solvidx).isExist() )
1942 newinfo.setFilepath(toedit.filepath());
1943 newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1944 newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1948 RepoInfo & oinfo(
const_cast<RepoInfo &
>(newinfo_r) );
1949 oinfo.setFilepath(toedit.filepath());
1950 oinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1951 oinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1953 reposManip().erase(toedit);
1954 reposManip().insert(newinfo);
1956 UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
1957 HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
1958 MIL <<
"repo " << alias <<
" modified" << endl;
1964 RepoInfo RepoManager::Impl::getRepositoryInfo(
const std::string & alias,
const ProgressData::ReceiverFnc & progressrcv )
1966 RepoConstIterator it( findAlias( alias,
repos() ) );
1967 if ( it !=
repos().end() )
1970 info.setAlias( alias );
1975 RepoInfo RepoManager::Impl::getRepositoryInfo(
const Url & url,
const url::ViewOption & urlview,
const ProgressData::ReceiverFnc & progressrcv )
1977 for_( it, repoBegin(), repoEnd() )
1979 for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
1981 if ( (*urlit).asString(urlview) == url.asString(urlview) )
1986 info.setBaseUrl( url );
1996 void RepoManager::Impl::addService(
const ServiceInfo & service )
1998 assert_alias( service );
2001 if ( hasService( service.alias() ) )
2006 ServiceInfo toSave( service );
2007 saveService( toSave );
2011 UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
2013 MIL <<
"added service " << toSave.alias() << endl;
2018 void RepoManager::Impl::removeService(
const std::string & alias )
2020 MIL <<
"Going to delete service " << alias << endl;
2022 const ServiceInfo & service = getService( alias );
2024 Pathname location = service.filepath();
2025 if( location.empty() )
2031 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2034 if ( tmpSet.size() == 1 )
2041 MIL << alias <<
" successfully deleted." << endl;
2047 std::ofstream file(location.c_str());
2054 for_(it, tmpSet.begin(), tmpSet.end())
2056 if( it->alias() != alias )
2057 it->dumpAsIniOn(file);
2060 MIL << alias <<
" successfully deleted from file " << location << endl;
2064 RepoCollector rcollector;
2065 getRepositoriesInService( alias,
2066 boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) );
2068 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
2069 removeRepository(*rit);
2074 void RepoManager::
Impl::refreshServices( const RefreshServiceOptions & options_r )
2078 ServiceSet services( serviceBegin(), serviceEnd() );
2079 for_( it, services.begin(), services.end() )
2081 if ( !it->enabled() )
2085 refreshService(*it, options_r);
2087 catch (
const repo::ServicePluginInformalException & e )
2092 void RepoManager::Impl::refreshService(
const std::string & alias,
const RefreshServiceOptions & options_r )
2094 ServiceInfo service( getService( alias ) );
2095 assert_alias( service );
2096 assert_url( service );
2097 MIL <<
"Going to refresh service '" << service.alias() <<
"', url: " << service.url() <<
", opts: " << options_r << endl;
2099 if ( service.ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
2102 Date lrf = service.lrf();
2108 if ( (lrf+=service.ttl()) > now )
2110 MIL <<
"Skip: '" << service.alias() <<
"' metadata valid until " << lrf << endl;
2115 WAR <<
"Force: '" << service.alias() <<
"' metadata last refresh in the future: " << lrf << endl;
2122 bool serviceModified =
false;
2129 repo::ServiceType type = probeService( service.url() );
2130 if ( type != ServiceType::NONE )
2132 service.setProbedType( type );
2133 serviceModified =
true;
2138 std::string servicesTargetDistro = _options.servicesTargetDistro;
2139 if ( servicesTargetDistro.empty() )
2143 DBG <<
"ServicesTargetDistro: " << servicesTargetDistro << endl;
2147 RepoCollector collector(servicesTargetDistro);
2152 std::pair<DefaultIntegral<bool,false>, repo::ServicePluginInformalException> uglyHack;
2160 ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
2162 catch (
const repo::ServicePluginInformalException & e )
2165 uglyHack.first =
true;
2166 uglyHack.second = e;
2168 if ( service.ttl() != origTtl )
2170 if ( !service.ttl() )
2171 service.setLrf( Date() );
2172 serviceModified =
true;
2180 for_( it, collector.repos.begin(), collector.repos.end() )
2183 it->setAlias(
str::form(
"%s:%s", service.alias().c_str(), it->alias().c_str() ) );
2185 it->setService( service.alias() );
2188 newRepoStates[it->alias()] = *it;
2196 if ( !it->path().empty() )
2198 if ( it->path() !=
"/" )
2203 if ( it->baseUrlsEmpty() )
2205 Url url( service.rawUrl() );
2206 if ( !path.empty() )
2207 url.setPathName( url.getPathName() / path );
2208 it->setBaseUrl( std::move(url) );
2210 else if ( !path.empty() )
2213 for ( Url & url : urls )
2215 url.setPathName( url.getPathName() / path );
2217 it->setBaseUrls( std::move(urls) );
2224 RepoInfoList oldRepos;
2225 getRepositoriesInService( service.alias(), std::back_inserter( oldRepos ) );
2229 for_( oldRepo, oldRepos.begin(), oldRepos.end() )
2231 if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
2233 if ( oldRepo->enabled() )
2236 const auto & last = service.repoStates().find( oldRepo->alias() );
2237 if ( last != service.repoStates().end() && ! last->second.enabled )
2239 DBG <<
"Service removes user enabled repo " << oldRepo->alias() << endl;
2240 service.addRepoToEnable( oldRepo->alias() );
2241 serviceModified =
true;
2244 DBG <<
"Service removes enabled repo " << oldRepo->alias() << endl;
2247 DBG <<
"Service removes disabled repo " << oldRepo->alias() << endl;
2249 removeRepository( *oldRepo );
2255 UrlCredentialExtractor urlCredentialExtractor( _options.rootDir );
2256 for_( it, collector.repos.begin(), collector.repos.end() )
2262 TriBool toBeEnabled( indeterminate );
2263 DBG <<
"Service request to " << (it->enabled()?
"enable":
"disable") <<
" service repo " << it->alias() << endl;
2265 if ( options_r.testFlag( RefreshService_restoreStatus ) )
2267 DBG <<
"Opt RefreshService_restoreStatus " << it->alias() << endl;
2272 service.delRepoToEnable( it->alias() );
2277 if ( service.repoToEnableFind( it->alias() ) )
2279 DBG <<
"User request to enable service repo " << it->alias() << endl;
2284 service.delRepoToEnable( it->alias() );
2285 serviceModified =
true;
2287 else if ( service.repoToDisableFind( it->alias() ) )
2289 DBG <<
"User request to disable service repo " << it->alias() << endl;
2290 toBeEnabled =
false;
2294 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2295 if ( oldRepo == oldRepos.end() )
2300 if ( ! indeterminate(toBeEnabled) )
2301 it->setEnabled( (
bool ) toBeEnabled );
2303 DBG <<
"Service adds repo " << it->alias() <<
" " << (it->enabled()?
"enabled":
"disabled") << endl;
2304 addRepository( *it );
2309 bool oldRepoModified =
false;
2311 if ( indeterminate(toBeEnabled) )
2315 if ( oldRepo->enabled() == it->enabled() )
2316 toBeEnabled = it->enabled();
2317 else if (options_r.testFlag( RefreshService_restoreStatus ) )
2319 toBeEnabled = it->enabled();
2320 DBG <<
"Opt RefreshService_restoreStatus " << it->alias() <<
" forces " << (toBeEnabled?
"enabled":
"disabled") << endl;
2324 const auto & last = service.repoStates().find( oldRepo->alias() );
2325 if ( last == service.repoStates().end() || last->second.enabled != it->enabled() )
2326 toBeEnabled = it->enabled();
2329 toBeEnabled = oldRepo->enabled();
2330 DBG <<
"User modified service repo " << it->alias() <<
" may stay " << (toBeEnabled?
"enabled":
"disabled") << endl;
2336 if ( toBeEnabled == oldRepo->enabled() )
2338 DBG <<
"Service repo " << it->alias() <<
" stays " << (oldRepo->enabled()?
"enabled":
"disabled") << endl;
2340 else if ( toBeEnabled )
2342 DBG <<
"Service repo " << it->alias() <<
" gets enabled" << endl;
2343 oldRepo->setEnabled(
true );
2344 oldRepoModified =
true;
2348 DBG <<
"Service repo " << it->alias() <<
" gets disabled" << endl;
2349 oldRepo->setEnabled(
false );
2350 oldRepoModified =
true;
2356 if ( oldRepo->rawName() != it->rawName() )
2358 DBG <<
"Service repo " << it->alias() <<
" gets new NAME " << it->rawName() << endl;
2359 oldRepo->setName( it->rawName() );
2360 oldRepoModified =
true;
2364 if ( oldRepo->autorefresh() != it->autorefresh() )
2366 DBG <<
"Service repo " << it->alias() <<
" gets new AUTOREFRESH " << it->autorefresh() << endl;
2367 oldRepo->setAutorefresh( it->autorefresh() );
2368 oldRepoModified =
true;
2372 if ( oldRepo->priority() != it->priority() )
2374 DBG <<
"Service repo " << it->alias() <<
" gets new PRIORITY " << it->priority() << endl;
2375 oldRepo->setPriority( it->priority() );
2376 oldRepoModified =
true;
2382 urlCredentialExtractor.extract( newUrls );
2383 if ( oldRepo->rawBaseUrls() != newUrls )
2385 DBG <<
"Service repo " << it->alias() <<
" gets new URLs " << newUrls << endl;
2386 oldRepo->setBaseUrls( std::move(newUrls) );
2387 oldRepoModified =
true;
2393 if ( service.type() == ServiceType::PLUGIN )
2397 oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
2398 it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
2399#define Z_CHKGPG(I,N) \
2400 if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
2402 DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
2403 oldRepo->set##N##Check( ngpg[I] ); \
2404 oldRepoModified = true; \
2413 if ( oldRepoModified )
2415 modifyRepository( oldRepo->alias(), *oldRepo );
2421 if ( ! service.reposToDisableEmpty() )
2423 service.clearReposToDisable();
2424 serviceModified =
true;
2428 if ( service.repoStates() != newRepoStates )
2430 service.setRepoStates( std::move(newRepoStates) );
2431 serviceModified =
true;
2436 if ( service.type() != ServiceType::PLUGIN )
2438 if ( service.ttl() )
2441 serviceModified =
true;
2444 if ( serviceModified )
2447 modifyService( service.alias(), service );
2451 if ( uglyHack.first )
2453 throw( uglyHack.second );
2459 void RepoManager::Impl::modifyService(
const std::string & oldAlias,
const ServiceInfo & newService )
2461 MIL <<
"Going to modify service " << oldAlias << endl;
2465 ServiceInfo service(newService);
2467 if ( service.type() == ServiceType::PLUGIN )
2472 const ServiceInfo & oldService = getService(oldAlias);
2474 Pathname location = oldService.filepath();
2475 if( location.empty() )
2482 parser::ServiceFileReader( location, ServiceCollector(tmpSet) );
2485 std::ofstream file(location.c_str());
2486 for_(it, tmpSet.begin(), tmpSet.end())
2488 if( *it != oldAlias )
2489 it->dumpAsIniOn(file);
2491 service.dumpAsIniOn(file);
2493 service.setFilepath(location);
2498 UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
2502 if ( oldAlias != service.alias()
2503 || oldService.enabled() != service.enabled() )
2505 std::vector<RepoInfo> toModify;
2506 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
2507 for_( it, toModify.begin(), toModify.end() )
2509 if ( oldService.enabled() != service.enabled() )
2511 if ( service.enabled() )
2514 const auto & last = service.repoStates().find( it->alias() );
2515 if ( last != service.repoStates().end() )
2516 it->setEnabled( last->second.enabled );
2519 it->setEnabled(
false );
2522 if ( oldAlias != service.alias() )
2523 it->setService(service.alias());
2525 modifyRepository(it->alias(), *it);
2534 repo::ServiceType RepoManager::Impl::probeService(
const Url & url )
const
2538 MediaSetAccess access(url);
2539 if ( access.doesFileExist(
"/repo/repoindex.xml") )
2542 catch (
const media::MediaException &e )
2550 catch (
const Exception &e )
2554 Exception enew(
str::form(
_(
"Unknown error reading from '%s'"), url.asString().c_str() ));
2567 MIL <<
"GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
2571 std::vector<std::string> hosts;
2572 for (
const auto &baseUrl : urls ) {
2573 const auto &host = baseUrl.getHost();
2575 hosts.push_back( host );
2580 if ( hosts.empty() ) {
2581 MIL <<
"No configured geoip URL found, not updating geoip data" << std::endl;
2588 MIL <<
"Unable to create cache directory for GeoIP." << std::endl;
2592 if ( !PathInfo(geoIPCache).userMayRWX() ) {
2593 MIL <<
"No access rights for the GeoIP cache directory." << std::endl;
2602 PathInfo pi( dir/entry.name );
2603 auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
2604 if ( age < std::chrono::hours(24) )
2607 MIL <<
"Removing GeoIP file for " << entry.name <<
" since it's older than 24hrs." << std::endl;
2613 std::for_each( hosts.begin(), hosts.end(), [ & ](
const std::string &hostname ) {
2616 if ( zypp::PathInfo( geoIPCache / hostname ).isExist() ) {
2617 MIL <<
"Skipping GeoIP request for " << hostname <<
" since a valid cache entry exists." << std::endl;
2621 MIL <<
"Query GeoIP for " << hostname << std::endl;
2626 url.setHost(hostname);
2627 url.setScheme(
"https");
2632 MIL <<
"Ignoring invalid GeoIP hostname: " << hostname << std::endl;
2636 MediaSetAccess acc( url );
2644 MIL <<
"Failed to query GeoIP from hostname: " << hostname << std::endl;
2647 if ( !file->
empty() ) {
2649 constexpr auto writeHostToFile = [](
const Pathname &fName,
const std::string &host ){
2651 out.open( fName.asString(), std::ios_base::trunc );
2652 if ( out.is_open() ) {
2653 out << host << std::endl;
2655 MIL <<
"Failed to create/open GeoIP cache file " << fName << std::endl;
2659 std::string geoipMirror;
2661 xml::Reader reader( *file );
2662 if ( reader.seekToNode( 1,
"host" ) ) {
2663 const auto &
str = reader.nodeText().asString();
2671 MIL <<
"Storing geoIP redirection: " << hostname <<
" -> " <<
str << std::endl;
2676 MIL <<
"No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
2680 MIL <<
"Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
2683 writeHostToFile( geoIPCache / hostname, geoipMirror );
2689 MIL <<
"Failed to query GeoIP data." << std::endl;
2700 : _pimpl( new
Impl(opt) )
2707 {
return _pimpl->repoEmpty(); }
2710 {
return _pimpl->repoSize(); }
2713 {
return _pimpl->repoBegin(); }
2716 {
return _pimpl->repoEnd(); }
2719 {
return _pimpl->getRepo( alias ); }
2722 {
return _pimpl->hasRepo( alias ); }
2732 std::string host( url_r.
getHost() );
2733 if ( ! host.empty() )
2745 {
return _pimpl->metadataStatus( info ); }
2748 {
return _pimpl->checkIfToRefreshMetadata( info, url, policy ); }
2751 {
return _pimpl->metadataPath( info ); }
2754 {
return _pimpl->packagesPath( info ); }
2757 {
return _pimpl->refreshMetadata( info, policy, progressrcv ); }
2760 {
return _pimpl->cleanMetadata( info, progressrcv ); }
2763 {
return _pimpl->cleanPackages( info, progressrcv ); }
2766 {
return _pimpl->cacheStatus( info ); }
2769 {
return _pimpl->buildCache( info, policy, progressrcv ); }
2772 {
return _pimpl->cleanCache( info, progressrcv ); }
2775 {
return _pimpl->isCached( info ); }
2778 {
return _pimpl->loadFromCache( info, progressrcv ); }
2781 {
return _pimpl->cleanCacheDirGarbage( progressrcv ); }
2784 {
return _pimpl->probe( url, path ); }
2787 {
return _pimpl->probe( url ); }
2790 {
return _pimpl->addRepository( info, progressrcv ); }
2793 {
return _pimpl->addRepositories( url, progressrcv ); }
2796 {
return _pimpl->removeRepository( info, progressrcv ); }
2799 {
return _pimpl->modifyRepository( alias, newinfo, progressrcv ); }
2802 {
return _pimpl->getRepositoryInfo( alias, progressrcv ); }
2805 {
return _pimpl->getRepositoryInfo( url, urlview, progressrcv ); }
2808 {
return _pimpl->serviceEmpty(); }
2811 {
return _pimpl->serviceSize(); }
2814 {
return _pimpl->serviceBegin(); }
2817 {
return _pimpl->serviceEnd(); }
2820 {
return _pimpl->getService( alias ); }
2823 {
return _pimpl->hasService( alias ); }
2826 {
return _pimpl->probeService( url ); }
2829 {
return _pimpl->addService( alias, url ); }
2832 {
return _pimpl->addService( service ); }
2835 {
return _pimpl->removeService( alias ); }
2838 {
return _pimpl->removeService( service ); }
2841 {
return _pimpl->refreshServices( options_r ); }
2844 {
return _pimpl->refreshService( alias, options_r ); }
2847 {
return _pimpl->refreshService( service, options_r ); }
2850 {
return _pimpl->modifyService( oldAlias, service ); }
2853 {
return _pimpl->refreshGeoIPData( urls ); }
media::MediaAccessId _mid
scoped_ptr< media::CredentialManager > _cmPtr
RepoManager implementation.
std::ostream & operator<<(std::ostream &str, const RepoManager::Impl &obj)
Stream output.
static const ValueType day
static Date now()
Return the current time.
std::string digest()
get hex string representation of the digest
static const std::string & sha1()
sha1
Base class for Exception.
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
What is known about a repository.
static const RepoInfo noRepo
Represents no Repository (one with an empty alias).
transform_iterator< repo::RepoVariablesUrlReplacer, url_set::const_iterator > urls_const_iterator
Track changing files or directories.
static RepoStatus fromCookieFile(const Pathname &path)
Reads the status from a cookie file.
void saveToCookieFile(const Pathname &path_r) const
Save the status information to a cookie file.
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
std::map< std::string, RepoState > RepoStates
static const ServiceInfo noService
Represents an empty service.
std::string targetDistribution() const
This is register.target attribute of the installed base product.
std::string getScheme() const
Returns the scheme name of the URL.
std::string asCompleteString() const
Returns a complete string representation of the Url object.
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
void setHost(const std::string &host)
Set the hostname or IP in the URL authority.
bool isValid() const
Verifies the Url.
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
unsigned repo_refresh_delay() const
Amount of time in minutes that must pass before another refresh.
Pathname builtinRepoSolvfilesPath() const
The builtin config file value.
bool repo_add_probe() const
Whether repository urls should be probed.
Pathname geoipCachePath() const
Path where the geoip caches are kept (/var/cache/zypp/geoip)
static ZConfig & instance()
Singleton ctor.
Pathname builtinRepoPackagesPath() const
The builtin config file value.
Pathname builtinRepoMetadataPath() const
The builtin config file value.
Wrapper class for ::stat/::lstat.
bool isExist() const
Return whether valid stat info exists.
const std::string & asString() const
Return current Pathname as String.
bool empty() const
Test for an empty path.
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r prefixed with root_r, unless it is already prefixed.
static TmpDir makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Repository already exists and some unique attribute can't be duplicated.
Exception for repository handling.
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.
thrown when it was impossible to determine one url for this repo.
The repository cache is not built yet so you can't create the repostories from the cache.
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 is immutable.
Retrieval of repository list for a service.
Downloader for YUM (rpm-nmd) repositories Encapsulates all the knowledge of which files have to be do...
RepoStatus status(MediaSetAccess &media_r) override
Status of the remote repository.
void reposErase(const std::string &alias_r)
Remove a Repository named alias_r.
Repository addRepoSolv(const Pathname &file_r, const std::string &name_r)
Load Solvables from a solv-file into a Repository named name_r.
static Pool instance()
Singleton ctor.
static const SolvAttr repositoryToolVersion
Repository metadata verification beyond GPG.
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
int unlink(const Pathname &path)
Like 'unlink'.
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
int touch(const Pathname &path)
Change file's modification and access times.
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
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).
std::string numstring(char n, int w=0)
bool regex_match(const std::string &s, smatch &matches, const regex ®ex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
std::string hexstring(char n, int w=4)
int compareCI(const C_Str &lhs, const C_Str &rhs)
Easy-to use interface to the ZYPP dependency resolver.
std::list< RepoInfo > readRepoFile(const Url &repo_file)
Parses repo_file and returns a list of RepoInfo objects corresponding to repositories found within th...
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
bool any_of(const Container &c, Fnc &&cb)
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
std::string asString(const Patch::Category &obj)
constexpr std::string_view Url("url")
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
static RepoManagerOptions makeTestSetup(const Pathname &root_r)
Test setup adjusting all paths to be located below one root_r directory.
Pathname repoSolvCachePath
Pathname rootDir
remembers root_r value for later use
Pathname knownServicesPath
Pathname repoRawCachePath
Pathname repoPackagesCachePath
RepoManagerOptions(const Pathname &root_r=Pathname())
Default ctor following ZConfig global settings.
Functor thats filter RepoInfo by service which it belongs to.
creates and provides information about known sources.
bool hasRepo(const std::string &alias) const
ServiceSet::const_iterator ServiceConstIterator
bool serviceEmpty() const
bool hasService(const std::string &alias) const
RefreshCheckStatus
Possibly return state of checkIfRefreshMEtadata function.
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy)
Impl * clone() const
clone for RWCOW_pointer
void refreshService(const ServiceInfo &service, const RefreshServiceOptions &options_r)
void addRepository(const RepoInfo &info, OPT_PROGRESS)
RepoSet::const_iterator RepoConstIterator
RepoInfo getRepositoryInfo(const Url &url, const url::ViewOption &urlview, OPT_PROGRESS)
void addService(const std::string &alias, const Url &url)
std::string generateFilename(const ServiceInfo &info) const
bool isCached(const RepoInfo &info) const
void cleanPackages(const RepoInfo &info, OPT_PROGRESS, bool isAutoClean=false)
void modifyRepository(const std::string &alias, const RepoInfo &newinfo_r, OPT_PROGRESS)
void loadFromCache(const RepoInfo &info, OPT_PROGRESS)
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy, OPT_PROGRESS)
void removeService(const std::string &alias)
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r)
void buildCache(const RepoInfo &info, CacheBuildPolicy policy, OPT_PROGRESS)
RepoManager(const RepoManagerOptions &options=RepoManagerOptions())
RepoInfo getRepo(const std::string &alias) const
repo::ServiceType probeService(const Url &url) const
RWCOW_pointer< Impl > _pimpl
Pointer to implementation.
RepoInfo getRepositoryInfo(const std::string &alias, OPT_PROGRESS)
void cleanCacheDirGarbage(OPT_PROGRESS)
void addService(const ServiceInfo &service)
void init_knownRepositories()
Pathname metadataPath(const RepoInfo &info) const
ServiceSet::size_type ServiceSizeType
std::set< RepoInfo > RepoSet
RepoInfo typedefs.
Pathname packagesPath(const RepoInfo &info) const
DefaultIntegral< bool, false > _reposDirty
RepoManagerOptions _options
RepoStatus cacheStatus(const RepoInfo &info) const
void touchIndexFile(const RepoInfo &info)
repo::RepoType probeCache(const Pathname &path_r) const
void refreshGeoIp(const RepoInfo::url_set &urls)
void modifyService(const std::string &oldAlias, const ServiceInfo &newService)
ServiceConstIterator serviceEnd() const
ServiceConstIterator serviceBegin() const
void cleanCache(const RepoInfo &info, OPT_PROGRESS)
repo::RepoType probe(const Url &url, const Pathname &path=Pathname()) const
void removeRepository(const RepoInfo &info, OPT_PROGRESS)
RepoSizeType repoSize() const
void removeService(const ServiceInfo &service)
ServiceSizeType serviceSize() const
RepoSet::size_type RepoSizeType
void saveService(ServiceInfo &service) const
void addRepositories(const Url &url, OPT_PROGRESS)
void cleanMetadata(const RepoInfo &info, OPT_PROGRESS)
ServiceInfo getService(const std::string &alias) const
Pathname generateNonExistingName(const Pathname &dir, const std::string &basefilename) const
void refreshServices(const RefreshServiceOptions &options_r)
RepoConstIterator repoBegin() const
const RepoSet & repos() const
Iterate the known repositories.
void init_knownServices()
Impl(const RepoManagerOptions &opt)
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
void getRepositoriesInService(const std::string &alias, OutputIterator out) const
std::set< ServiceInfo > ServiceSet
ServiceInfo typedefs.
RepoConstIterator repoEnd() const
void setCacheStatus(const RepoInfo &info, const RepoStatus &status)
RepoStatus metadataStatus(const RepoInfo &info) const
static std::string makeStupidAlias(const Url &url_r=Url())
Some stupid string but suitable as alias for your url if nothing better is available.
std::string generateFilename(const RepoInfo &info) const
PluginRepoverification _pluginRepoverification
void refreshGeoIPData(const RepoInfo::url_set &urls)
Repository type enumeration.
static const RepoType YAST2
static const RepoType RPMMD
static const RepoType NONE
static const RepoType RPMPLAINDIR
Service type enumeration.
static const ServiceType NONE
No service set.
static const ServiceType RIS
Repository Index Service (RIS) (formerly known as 'Novell Update' (NU) service)
Url::asString() view options.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
#define PL_(MSG1, MSG2, N)