21 #include <solv/solvversion.h>
59 using namespace zypp::repo;
61 #define OPT_PROGRESS const ProgressData::ReceiverFnc & = ProgressData::ReceiverFnc()
73 const char * env = getenv(
"ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
103 class UrlCredentialExtractor
106 UrlCredentialExtractor( Pathname & root_r )
110 ~UrlCredentialExtractor()
114 bool collect(
const Url & url_r )
116 bool ret = url_r.hasCredentialsInAuthority();
120 _cmPtr->addUserCred( url_r );
125 template<
class TContainer>
126 bool collect(
const TContainer & urls_r )
127 {
bool ret =
false;
for (
const Url &
url : urls_r ) {
if ( collect(
url ) && !ret ) ret =
true; }
return ret; }
130 bool extract( Url & url_r )
132 bool ret = collect( url_r );
134 url_r.setPassword( std::string() );
138 template<
class TContainer>
139 bool extract( TContainer & urls_r )
140 {
bool ret =
false;
for ( Url &
url : urls_r ) {
if ( extract(
url ) && !ret ) ret =
true; }
return ret; }
144 scoped_ptr<media::CredentialManager>
_cmPtr;
159 MediaMounter(
const Url & url_r )
161 media::MediaManager mediamanager;
162 _mid = mediamanager.open( url_r );
163 mediamanager.attach(
_mid );
169 media::MediaManager mediamanager;
170 mediamanager.release(
_mid );
171 mediamanager.close(
_mid );
178 Pathname getPathName(
const Pathname & path_r = Pathname() )
const
180 media::MediaManager mediamanager;
181 return mediamanager.localPath(
_mid, path_r );
190 template <
class Iterator>
191 inline bool foundAliasIn(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
193 for_( it, begin_r, end_r )
194 if ( it->alias() == alias_r )
199 template <
class Container>
200 inline bool foundAliasIn(
const std::string & alias_r,
const Container & cont_r )
201 {
return foundAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
204 template <
class Iterator>
205 inline Iterator findAlias(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
207 for_( it, begin_r, end_r )
208 if ( it->alias() == alias_r )
213 template <class Container>
214 inline typename Container::iterator findAlias( const std::
string & alias_r, Container & cont_r )
215 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
217 template <
class Container>
218 inline typename Container::const_iterator findAlias(
const std::string & alias_r,
const Container & cont_r )
219 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
223 inline std::string filenameFromAlias(
const std::string & alias_r,
const std::string & stem_r )
225 std::string filename( alias_r );
229 filename = Pathname(filename).extend(
"."+stem_r).asString();
230 MIL <<
"generating filename for " << stem_r <<
" [" << alias_r <<
"] : '" << filename <<
"'" << endl;
254 RepoCollector(
const std::string & targetDistro_)
258 bool collect(
const RepoInfo &repo )
262 && !repo.targetDistribution().empty()
266 <<
"Skipping repository meant for '" << repo.targetDistribution()
267 <<
"' distribution (current distro is '"
273 repos.push_back(repo);
287 std::list<RepoInfo> repositories_in_file(
const Pathname & file )
289 MIL <<
"repo file: " << file << endl;
290 RepoCollector collector;
291 parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) );
292 return std::move(collector.repos);
305 std::list<RepoInfo> repositories_in_dir(
const Pathname &dir )
307 MIL <<
"directory " << dir << endl;
308 std::list<RepoInfo>
repos;
309 bool nonroot( geteuid() != 0 );
310 if ( nonroot && ! PathInfo(dir).userMayRX() )
312 JobReport::warning( str::Format(
_(
"Cannot read repo directory '%1%': Permission denied")) % dir );
316 std::list<Pathname> entries;
323 str::regex allowedRepoExt(
"^\\.repo(_[0-9]+)?$");
324 for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
328 if ( nonroot && ! PathInfo(*it).userMayR() )
330 JobReport::warning( str::Format(
_(
"Cannot read repo file '%1%': Permission denied")) % *it );
334 const std::list<RepoInfo> & tmp( repositories_in_file( *it ) );
335 repos.insert( repos.end(), tmp.begin(), tmp.end() );
345 inline void assert_alias(
const RepoInfo & info )
347 if ( info.alias().empty() )
351 if ( info.alias()[0] ==
'.')
353 info,
_(
"Repository alias cannot start with dot.")));
356 inline void assert_alias(
const ServiceInfo & info )
358 if ( info.alias().empty() )
362 if ( info.alias()[0] ==
'.')
364 info,
_(
"Service alias cannot start with dot.")));
369 inline void assert_urls(
const RepoInfo & info )
371 if ( info.baseUrlsEmpty() )
375 inline void assert_url(
const ServiceInfo & info )
377 if ( ! info.url().isValid() )
387 inline bool isTmpRepo(
const RepoInfo & info_r )
388 {
return( info_r.filepath().empty() && info_r.usesAutoMethadataPaths() ); }
396 inline Pathname rawcache_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
399 return isTmpRepo( info ) ? info.metadataPath() : opt.repoRawCachePath / info.escaped_alias();
410 inline Pathname rawproductdata_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
411 {
return rawcache_path_for_repoinfo( opt, info ) / info.path(); }
416 inline Pathname packagescache_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
419 return isTmpRepo( info ) ? info.packagesPath() : opt.repoPackagesCachePath / info.escaped_alias();
425 inline Pathname solv_path_for_repoinfo(
const RepoManagerOptions &opt,
const RepoInfo &info )
428 return isTmpRepo( info ) ? info.metadataPath().dirname() /
"%SLV%" : opt.repoSolvCachePath / info.escaped_alias();
434 class ServiceCollector
437 typedef std::set<ServiceInfo> ServiceSet;
439 ServiceCollector( ServiceSet & services_r )
443 bool operator()(
const ServiceInfo & service_r )
const
461 DBG <<
"reading repo file " << repo_file <<
", local path: " << local << endl;
463 return repositories_in_file(local);
474 repoCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoCachePath() );
475 repoRawCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoMetadataPath() );
476 repoSolvCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoSolvfilesPath() );
477 repoPackagesCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoPackagesPath() );
478 knownReposPath = Pathname::assertprefix( root_r,
ZConfig::instance().knownReposPath() );
479 knownServicesPath = Pathname::assertprefix( root_r,
ZConfig::instance().knownServicesPath() );
480 pluginsPath = Pathname::assertprefix( root_r,
ZConfig::instance().pluginsPath() );
502 #define OUTS(X) str << " " #X "\t" << obj.X << endl
503 str <<
"RepoManagerOptions (" << obj.
rootDir <<
") {" << endl;
504 OUTS( repoRawCachePath );
505 OUTS( repoSolvCachePath );
506 OUTS( repoPackagesCachePath );
507 OUTS( knownReposPath );
508 OUTS( knownServicesPath );
526 init_knownServices();
527 init_knownRepositories();
534 && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir ==
"/" ) )
537 std::list<Pathname> entries;
539 if ( ! entries.empty() )
542 cmd.push_back(
"<" );
543 cmd.push_back(
">" );
544 cmd.push_back(
"PROGRAM" );
545 for (
const auto & rinfo :
repos() )
547 if ( ! rinfo.enabled() )
549 cmd.push_back(
"-R" );
550 cmd.push_back( rinfo.alias() );
551 cmd.push_back(
"-t" );
552 cmd.push_back( rinfo.type().asString() );
553 cmd.push_back(
"-p" );
554 cmd.push_back( rinfo.metadataPath().asString() );
557 for_( it, entries.begin(), entries.end() )
561 if ( pi.isFile() && pi.userMayRX() )
564 cmd[2] = pi.asString();
580 bool hasRepo(
const std::string & alias )
const
581 {
return foundAliasIn( alias,
repos() ); }
583 RepoInfo getRepo(
const std::string & alias )
const
590 Pathname metadataPath(
const RepoInfo & info )
const
591 {
return rawcache_path_for_repoinfo( _options, info ); }
593 Pathname packagesPath(
const RepoInfo & info )
const
594 {
return packagescache_path_for_repoinfo( _options, info ); }
616 {
return PathInfo(solv_path_for_repoinfo( _options, info ) /
"solv").isExist(); }
640 bool hasService(
const std::string & alias )
const
641 {
return foundAliasIn( alias,
_services ); }
651 void addService(
const std::string & alias,
const Url & url )
654 void removeService(
const std::string & alias );
664 void modifyService(
const std::string & oldAlias,
const ServiceInfo & newService );
671 Pathname generateNonExistingName(
const Pathname & dir,
const std::string & basefilename )
const;
673 std::string generateFilename(
const RepoInfo & info )
const
674 {
return filenameFromAlias( info.
alias(),
"repo" ); }
677 {
return filenameFromAlias( info.
alias(),
"service" ); }
681 Pathname base = solv_path_for_repoinfo( _options, info );
686 void touchIndexFile(
const RepoInfo & info );
688 template<
typename OutputIterator>
689 void getRepositoriesInService(
const std::string & alias, OutputIterator out )
const
693 boost::make_filter_iterator( filter,
repos().end(),
repos().end() ),
698 void init_knownServices();
699 void init_knownRepositories();
712 friend Impl * rwcowClone<Impl>(
const Impl * rhs );
715 {
return new Impl( *
this ); }
721 {
return str <<
"RepoManager::Impl"; }
728 Pathname servfile = generateNonExistingName( _options.knownServicesPath,
729 generateFilename( service ) );
732 MIL <<
"saving service in " << servfile << endl;
734 std::ofstream file( servfile.c_str() );
741 MIL <<
"done" << endl;
760 const std::string & basefilename )
const
762 std::string final_filename = basefilename;
764 while ( PathInfo(dir + final_filename).isExist() )
769 return dir + Pathname(final_filename);
776 Pathname dir = _options.knownServicesPath;
777 std::list<Pathname> entries;
778 if (PathInfo(dir).isExist())
787 for_(it, entries.begin(), entries.end() )
803 inline void cleanupNonRepoMetadtaFolders(
const Pathname & cachePath_r,
804 const Pathname & defaultCachePath_r,
805 const std::list<std::string> & repoEscAliases_r )
807 if ( cachePath_r != defaultCachePath_r )
810 std::list<std::string> entries;
814 std::set<std::string> oldfiles;
815 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
816 std::inserter( oldfiles, oldfiles.end() ) );
817 for (
const std::string & old : oldfiles )
829 MIL <<
"start construct known repos" << endl;
831 if ( PathInfo(_options.knownReposPath).isExist() )
833 std::list<std::string> repoEscAliases;
834 std::list<RepoInfo> orphanedRepos;
835 for (
RepoInfo & repoInfo : repositories_in_dir(_options.knownReposPath) )
838 repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo) );
840 repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo) );
842 _reposX.insert( repoInfo );
845 const std::string & serviceAlias( repoInfo.service() );
846 if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
848 WAR <<
"Schedule orphaned service repo for deletion: " << repoInfo << endl;
849 orphanedRepos.push_back( repoInfo );
853 repoEscAliases.push_back(repoInfo.escaped_alias());
857 if ( ! orphanedRepos.empty() )
859 for (
const auto & repoInfo : orphanedRepos )
861 MIL <<
"Delete orphaned service repo " << repoInfo.alias() << endl;
867 % repoInfo.alias() );
869 removeRepository( repoInfo );
883 repoEscAliases.sort();
885 cleanupNonRepoMetadtaFolders( _options.repoRawCachePath, defaultCache.
repoRawCachePath, repoEscAliases );
886 cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath, defaultCache.
repoSolvCachePath, repoEscAliases );
887 cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath, defaultCache.
repoPackagesCachePath, repoEscAliases );
889 MIL <<
"end construct known repos" << endl;
896 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
897 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
902 repokind = probeCache( productdatapath );
905 switch ( repokind.
toEnum() )
908 status =
RepoStatus( productdatapath/
"repodata/repomd.xml") &&
RepoStatus( mediarootpath/
"media.1/media" );
912 status =
RepoStatus( productdatapath/
"content" ) &&
RepoStatus( mediarootpath/
"media.1/media" );
931 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
936 repokind = probeCache( productdatapath );
942 switch ( repokind.
toEnum() )
945 p = Pathname(productdatapath +
"/repodata/repomd.xml");
949 p = Pathname(productdatapath +
"/content");
953 p = Pathname(productdatapath +
"/cookie");
971 MIL <<
"Going to try to check whether refresh is needed for " << url <<
" (" << info.
type() <<
")" << endl;
974 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
976 RepoStatus oldstatus = metadataStatus( info );
977 if ( oldstatus.
empty() )
979 MIL <<
"No cached metadata, going to refresh" << endl;
980 return REFRESH_NEEDED;
985 MIL <<
"Never refresh CD/DVD" << endl;
986 return REPO_UP_TO_DATE;
989 if ( policy == RefreshForced )
991 MIL <<
"Forced refresh!" << endl;
992 return REFRESH_NEEDED;
997 policy = RefreshIfNeededIgnoreDelay;
1001 if ( policy != RefreshIfNeededIgnoreDelay )
1004 double diff = difftime(
1010 DBG <<
"last refresh = " << diff <<
" minutes ago" << endl;
1016 WAR <<
"Repository '" << info.
alias() <<
"' was refreshed in the future!" << endl;
1020 MIL <<
"Repository '" << info.
alias()
1021 <<
"' has been refreshed less than repo.refresh.delay ("
1023 <<
") minutes ago. Advising to skip refresh" << endl;
1024 return REPO_CHECK_DELAYED;
1032 repokind = probe( url, info.
path() );
1036 switch ( repokind.
toEnum() )
1053 newstatus =
RepoStatus( MediaMounter(url).getPathName(info.
path()) );
1063 if ( oldstatus == newstatus )
1065 MIL <<
"repo has not changed" << endl;
1066 touchIndexFile( info );
1067 return REPO_UP_TO_DATE;
1071 MIL <<
"repo has changed, going to refresh" << endl;
1072 return REFRESH_NEEDED;
1078 ERR <<
"refresh check failed for " << url << endl;
1082 return REFRESH_NEEDED;
1092 RepoException rexception( info,
PL_(
"Valid metadata not found at specified URL",
1093 "Valid metadata not found at specified URLs",
1107 if (checkIfToRefreshMetadata(info, url, policy)!=REFRESH_NEEDED)
1110 MIL <<
"Going to refresh metadata from " << url << endl;
1118 if ( repokind != probed )
1124 for_( it, repoBegin(), repoEnd() )
1126 if ( info.
alias() == (*it).alias() )
1129 modifiedrepo.
setType( repokind );
1130 modifyRepository( info.
alias(), modifiedrepo );
1137 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1148 Exception ex(
_(
"Can't create metadata cache directory."));
1156 shared_ptr<repo::Downloader> downloader_ptr;
1158 MIL <<
"Creating downloader for [ " << info.
alias() <<
" ]" << endl;
1171 for_( it, repoBegin(), repoEnd() )
1173 Pathname cachepath(rawcache_path_for_repoinfo( _options, *it ));
1174 if ( PathInfo(cachepath).isExist() )
1175 downloader_ptr->addCachePath(cachepath);
1178 downloader_ptr->download( media, tmpdir.
path() );
1182 MediaMounter media( url );
1185 Pathname productpath( tmpdir.
path() / info.
path() );
1197 if ( ! isTmpRepo( info ) )
1206 ERR <<
"Trying another url..." << endl;
1218 ERR <<
"No more urls..." << endl;
1227 progress.
sendTo(progressfnc);
1237 progress.
sendTo(progressfnc);
1247 Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
1248 Pathname productdatapath = rawproductdata_path_for_repoinfo( _options, info );
1255 RepoStatus raw_metadata_status = metadataStatus(info);
1256 if ( raw_metadata_status.
empty() )
1261 refreshMetadata(info, RefreshIfNeeded, progressrcv );
1262 raw_metadata_status = metadataStatus(info);
1265 bool needs_cleaning =
false;
1266 if ( isCached( info ) )
1268 MIL << info.
alias() <<
" is already cached." << endl;
1271 if ( cache_status == raw_metadata_status )
1273 MIL << info.
alias() <<
" cache is up to date with metadata." << endl;
1274 if ( policy == BuildIfNeeded )
1277 const Pathname & base = solv_path_for_repoinfo( _options, info);
1278 if ( ! PathInfo(base/
"solv.idx").isExist() )
1284 MIL << info.
alias() <<
" cache rebuild is forced" << endl;
1288 needs_cleaning =
true;
1302 MIL << info.
alias() <<
" building cache..." << info.
type() << endl;
1304 Pathname base = solv_path_for_repoinfo( _options, info);
1312 if( ! PathInfo(base).userMayW() )
1314 Exception ex(
str::form(
_(
"Can't create cache at %s - no writing permissions."), base.c_str()) );
1317 Pathname solvfile = base /
"solv";
1323 switch ( repokind.
toEnum() )
1327 repokind = probeCache( productdatapath );
1333 MIL <<
"repo type is " << repokind << endl;
1335 switch ( repokind.
toEnum() )
1343 scoped_ptr<MediaMounter> forPlainDirs;
1346 cmd.push_back( PathInfo(
"/usr/bin/repo2solv" ).isFile() ?
"repo2solv" :
"repo2solv.sh" );
1348 cmd.push_back(
"-o" );
1349 cmd.push_back( solvfile.asString() );
1350 cmd.push_back(
"-X" );
1355 forPlainDirs.reset(
new MediaMounter( info.
url() ) );
1357 cmd.push_back(
"-R" );
1359 cmd.push_back( forPlainDirs->getPathName( info.
path() ).c_str() );
1362 cmd.push_back( productdatapath.asString() );
1365 std::string errdetail;
1368 WAR <<
" " << output;
1369 if ( errdetail.empty() ) {
1373 errdetail += output;
1376 int ret = prog.
close();
1394 setCacheStatus(info, raw_metadata_status);
1395 MIL <<
"Commit cache.." << endl;
1410 MIL <<
"going to probe the repo type at " << url <<
" (" << path <<
")" << endl;
1416 MIL <<
"Probed type NONE (not exists) at " << url <<
" (" << path <<
")" << endl;
1428 bool gotMediaException =
false;
1436 MIL <<
"Probed type RPMMD at " << url <<
" (" << path <<
")" << endl;
1443 DBG <<
"problem checking for repodata/repomd.xml file" << endl;
1445 gotMediaException =
true;
1452 MIL <<
"Probed type YAST2 at " << url <<
" (" << path <<
")" << endl;
1459 DBG <<
"problem checking for content file" << endl;
1461 gotMediaException =
true;
1467 MediaMounter media( url );
1468 if ( PathInfo(media.getPathName()/path).isDir() )
1471 MIL <<
"Probed type RPMPLAINDIR at " << url <<
" (" << path <<
")" << endl;
1485 if (gotMediaException)
1488 MIL <<
"Probed type NONE at " << url <<
" (" << path <<
")" << endl;
1499 MIL <<
"going to probe the cached repo at " << path_r << endl;
1503 if ( PathInfo(path_r/
"/repodata/repomd.xml").isFile() )
1505 else if ( PathInfo(path_r/
"/content").isFile() )
1507 else if ( PathInfo(path_r).isDir() )
1510 MIL <<
"Probed cached type " << ret <<
" at " << path_r << endl;
1518 MIL <<
"Going to clean up garbage in cache dirs" << endl;
1521 progress.
sendTo(progressrcv);
1524 std::list<Pathname> cachedirs;
1525 cachedirs.push_back(_options.repoRawCachePath);
1526 cachedirs.push_back(_options.repoPackagesCachePath);
1527 cachedirs.push_back(_options.repoSolvCachePath);
1529 for_( dir, cachedirs.begin(), cachedirs.end() )
1531 if ( PathInfo(*dir).isExist() )
1533 std::list<Pathname> entries;
1538 unsigned sdircount = entries.size();
1539 unsigned sdircurrent = 1;
1540 for_( subdir, entries.begin(), entries.end() )
1544 for_( r, repoBegin(), repoEnd() )
1545 if ( subdir->basename() == r->escaped_alias() )
1546 { found =
true;
break; }
1551 progress.
set( progress.
val() + sdircurrent * 100 / sdircount );
1556 progress.
set( progress.
val() + 100 );
1566 progress.
sendTo(progressrcv);
1569 MIL <<
"Removing raw metadata cache for " << info.
alias() << endl;
1580 Pathname solvfile = solv_path_for_repoinfo(_options, info) /
"solv";
1582 if ( ! PathInfo(solvfile).isExist() )
1592 if ( toolversion != LIBSOLV_TOOLVERSION )
1601 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1602 cleanCache( info, progressrcv );
1603 buildCache( info, BuildIfNeeded, progressrcv );
1621 MIL <<
"Try adding repo " << info << endl;
1628 if ( _options.probe )
1630 DBG <<
"unknown repository type, probing" << endl;
1631 assert_urls(tosave);
1645 Pathname repofile = generateNonExistingName(
1646 _options.knownReposPath, generateFilename(tosave));
1648 MIL <<
"Saving repo in " << repofile << endl;
1650 std::ofstream file(repofile.c_str());
1659 tosave.
setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1660 tosave.
setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1664 RepoInfo & oinfo( const_cast<RepoInfo &>(info) );
1666 oinfo.
setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ) );
1667 oinfo.
setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ) );
1669 reposManip().insert(tosave);
1674 UrlCredentialExtractor( _options.rootDir ).collect( tosave.
baseUrls() );
1679 MIL <<
"done" << endl;
1686 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
1691 for_ ( kit, repoBegin(), repoEnd() )
1693 if ( (*it).alias() == (*kit).alias() )
1695 ERR <<
"To be added repo " << (*it).alias() <<
" conflicts with existing repo " << (*kit).alias() << endl;
1701 std::string filename = Pathname(url.
getPathName()).basename();
1703 if ( filename == Pathname() )
1712 Pathname repofile = generateNonExistingName(_options.knownReposPath, filename);
1714 MIL <<
"Saving " << repos.size() <<
" repo" << ( repos.size() ?
"s" :
"" ) <<
" in " << repofile << endl;
1716 std::ofstream file(repofile.c_str());
1723 for ( std::list<RepoInfo>::iterator it = repos.begin();
1727 MIL <<
"Saving " << (*it).alias() << endl;
1728 it->dumpAsIniOn(file);
1729 it->setFilepath(repofile);
1730 it->setMetadataPath( rawcache_path_for_repoinfo( _options, *it ) );
1731 it->setPackagesPath( packagescache_path_for_repoinfo( _options, *it ) );
1732 reposManip().insert(*it);
1737 MIL <<
"done" << endl;
1749 MIL <<
"Going to delete repo " << info.
alias() << endl;
1751 for_( it, repoBegin(), repoEnd() )
1756 if ( (!info.
alias().empty()) && ( info.
alias() != (*it).alias() ) )
1771 std::list<RepoInfo> filerepos = repositories_in_file(todelete.
filepath());
1772 if ( filerepos.size() == 0
1773 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.
alias() ) )
1777 if ( ! ( ret == 0 || ret == ENOENT ) )
1782 MIL << todelete.
alias() <<
" successfully deleted." << endl;
1794 std::ofstream file(todelete.
filepath().c_str());
1800 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1801 fit != filerepos.end();
1804 if ( (*fit).alias() != todelete.
alias() )
1805 (*fit).dumpAsIniOn(file);
1813 if ( isCached(todelete) )
1814 cleanCache( todelete, cSubprogrcv);
1816 cleanMetadata( todelete, mSubprogrcv );
1817 cleanPackages( todelete, pSubprogrcv );
1818 reposManip().erase(todelete);
1819 MIL << todelete.
alias() <<
" successfully deleted." << endl;
1833 RepoInfo toedit = getRepositoryInfo(alias);
1837 if ( alias != newinfo.
alias() && hasRepo( newinfo.
alias() ) )
1849 std::list<RepoInfo> filerepos = repositories_in_file(toedit.
filepath());
1859 std::ofstream file(toedit.
filepath().c_str());
1865 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1866 fit != filerepos.end();
1871 if ( (*fit).alias() != toedit.
alias() )
1872 (*fit).dumpAsIniOn(file);
1880 const Pathname & solvidx = solv_path_for_repoinfo(_options, newinfo)/
"solv.idx";
1881 if ( PathInfo(solvidx).isExist() )
1886 newinfo.
setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1887 newinfo.
setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1891 RepoInfo & oinfo( const_cast<RepoInfo &>(newinfo_r) );
1893 oinfo.
setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ) );
1894 oinfo.
setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ) );
1896 reposManip().erase(toedit);
1897 reposManip().insert(newinfo);
1899 UrlCredentialExtractor( _options.rootDir ).collect( newinfo.
baseUrls() );
1901 MIL <<
"repo " << alias <<
" modified" << endl;
1910 if ( it !=
repos().end() )
1920 for_( it, repoBegin(), repoEnd() )
1922 for_( urlit, (*it).baseUrlsBegin(), (*it).baseUrlsEnd() )
1924 if ( (*urlit).asString(urlview) == url.
asString(urlview) )
1941 assert_alias( service );
1944 if ( hasService( service.
alias() ) )
1950 saveService( toSave );
1954 UrlCredentialExtractor( _options.rootDir ).collect( toSave.
url() );
1956 MIL <<
"added service " << toSave.
alias() << endl;
1963 MIL <<
"Going to delete service " << alias << endl;
1965 const ServiceInfo & service = getService( alias );
1967 Pathname location = service.
filepath();
1968 if( location.empty() )
1977 if ( tmpSet.size() == 1 )
1984 MIL << alias <<
" successfully deleted." << endl;
1990 std::ofstream file(location.c_str());
1997 for_(it, tmpSet.begin(), tmpSet.end())
1999 if( it->alias() != alias )
2000 it->dumpAsIniOn(file);
2003 MIL << alias <<
" successfully deleted from file " << location << endl;
2007 RepoCollector rcollector;
2008 getRepositoriesInService( alias,
2009 boost::make_function_output_iterator( bind( &RepoCollector::collect, &rcollector, _1 ) ) );
2011 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
2012 removeRepository(*rit);
2021 ServiceSet services( serviceBegin(), serviceEnd() );
2022 for_( it, services.begin(), services.end() )
2024 if ( !it->enabled() )
2028 refreshService(*it, options_r);
2038 assert_alias( service );
2039 assert_url( service );
2040 MIL <<
"Going to refresh service '" << service.
alias() <<
"', url: " << service.
url() <<
", opts: " << options_r << endl;
2042 if ( service.
ttl() && !( options_r.testFlag( RefreshService_forceRefresh) || options_r.testFlag( RefreshService_restoreStatus ) ) )
2051 if ( (lrf+=service.
ttl()) > now )
2053 MIL <<
"Skip: '" << service.
alias() <<
"' metadata valid until " << lrf << endl;
2058 WAR <<
"Force: '" << service.
alias() <<
"' metadata last refresh in the future: " << lrf << endl;
2065 bool serviceModified =
false;
2076 serviceModified =
true;
2081 std::string servicesTargetDistro = _options.servicesTargetDistro;
2082 if ( servicesTargetDistro.empty() )
2086 DBG <<
"ServicesTargetDistro: " << servicesTargetDistro << endl;
2090 RepoCollector collector(servicesTargetDistro);
2103 ServiceRepos( _options.rootDir, service, bind( &RepoCollector::collect, &collector, _1 ) );
2108 uglyHack.first =
true;
2109 uglyHack.second = e;
2111 if ( service.
ttl() != origTtl )
2113 if ( !service.
ttl() )
2115 serviceModified =
true;
2123 for_( it, collector.repos.begin(), collector.repos.end() )
2126 it->setAlias(
str::form(
"%s:%s", service.
alias().c_str(), it->alias().c_str() ) );
2128 it->setService( service.
alias() );
2131 newRepoStates[it->alias()] = *it;
2139 if ( !it->path().empty() )
2141 if ( it->path() !=
"/" )
2146 if ( it->baseUrlsEmpty() )
2149 if ( !path.empty() )
2151 it->setBaseUrl( std::move(url) );
2153 else if ( !path.empty() )
2156 for (
Url & url : urls )
2160 it->setBaseUrls( std::move(urls) );
2167 RepoInfoList oldRepos;
2168 getRepositoriesInService( service.
alias(), std::back_inserter( oldRepos ) );
2172 for_( oldRepo, oldRepos.begin(), oldRepos.end() )
2174 if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
2176 if ( oldRepo->enabled() )
2179 const auto & last = service.
repoStates().find( oldRepo->alias() );
2180 if ( last != service.
repoStates().end() && ! last->second.enabled )
2182 DBG <<
"Service removes user enabled repo " << oldRepo->alias() << endl;
2184 serviceModified =
true;
2187 DBG <<
"Service removes enabled repo " << oldRepo->alias() << endl;
2190 DBG <<
"Service removes disabled repo " << oldRepo->alias() << endl;
2192 removeRepository( *oldRepo );
2198 UrlCredentialExtractor urlCredentialExtractor( _options.rootDir );
2199 for_( it, collector.repos.begin(), collector.repos.end() )
2205 TriBool toBeEnabled( indeterminate );
2206 DBG <<
"Service request to " << (it->enabled()?
"enable":
"disable") <<
" service repo " << it->alias() << endl;
2208 if ( options_r.testFlag( RefreshService_restoreStatus ) )
2210 DBG <<
"Opt RefreshService_restoreStatus " << it->alias() << endl;
2222 DBG <<
"User request to enable service repo " << it->alias() << endl;
2228 serviceModified =
true;
2232 DBG <<
"User request to disable service repo " << it->alias() << endl;
2233 toBeEnabled =
false;
2237 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2238 if ( oldRepo == oldRepos.end() )
2243 if ( ! indeterminate(toBeEnabled) )
2244 it->setEnabled( (
bool ) toBeEnabled );
2246 DBG <<
"Service adds repo " << it->alias() <<
" " << (it->enabled()?
"enabled":
"disabled") << endl;
2247 addRepository( *it );
2252 bool oldRepoModified =
false;
2254 if ( indeterminate(toBeEnabled) )
2258 if ( oldRepo->enabled() == it->enabled() )
2259 toBeEnabled = it->enabled();
2260 else if (options_r.testFlag( RefreshService_restoreStatus ) )
2262 toBeEnabled = it->enabled();
2263 DBG <<
"Opt RefreshService_restoreStatus " << it->alias() <<
" forces " << (toBeEnabled?
"enabled":
"disabled") << endl;
2267 const auto & last = service.
repoStates().find( oldRepo->alias() );
2268 if ( last == service.
repoStates().end() || last->second.enabled != it->enabled() )
2269 toBeEnabled = it->enabled();
2272 toBeEnabled = oldRepo->enabled();
2273 DBG <<
"User modified service repo " << it->alias() <<
" may stay " << (toBeEnabled?
"enabled":
"disabled") << endl;
2279 if ( toBeEnabled == oldRepo->enabled() )
2281 DBG <<
"Service repo " << it->alias() <<
" stays " << (oldRepo->enabled()?
"enabled":
"disabled") << endl;
2283 else if ( toBeEnabled )
2285 DBG <<
"Service repo " << it->alias() <<
" gets enabled" << endl;
2286 oldRepo->setEnabled(
true );
2287 oldRepoModified =
true;
2291 DBG <<
"Service repo " << it->alias() <<
" gets disabled" << endl;
2292 oldRepo->setEnabled(
false );
2293 oldRepoModified =
true;
2299 if ( oldRepo->rawName() != it->rawName() )
2301 DBG <<
"Service repo " << it->alias() <<
" gets new NAME " << it->rawName() << endl;
2302 oldRepo->setName( it->rawName() );
2303 oldRepoModified =
true;
2307 if ( oldRepo->autorefresh() != it->autorefresh() )
2309 DBG <<
"Service repo " << it->alias() <<
" gets new AUTOREFRESH " << it->autorefresh() << endl;
2310 oldRepo->setAutorefresh( it->autorefresh() );
2311 oldRepoModified =
true;
2315 if ( oldRepo->priority() != it->priority() )
2317 DBG <<
"Service repo " << it->alias() <<
" gets new PRIORITY " << it->priority() << endl;
2318 oldRepo->setPriority( it->priority() );
2319 oldRepoModified =
true;
2325 urlCredentialExtractor.extract( newUrls );
2326 if ( oldRepo->rawBaseUrls() != newUrls )
2328 DBG <<
"Service repo " << it->alias() <<
" gets new URLs " << newUrls << endl;
2329 oldRepo->setBaseUrls( std::move(newUrls) );
2330 oldRepoModified =
true;
2340 oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
2341 it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
2342 #define Z_CHKGPG(I,N) \
2343 if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
2345 DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << endl; \
2346 oldRepo->set##N##Check( ngpg[I] ); \
2347 oldRepoModified = true; \
2356 if ( oldRepoModified )
2358 modifyRepository( oldRepo->alias(), *oldRepo );
2367 serviceModified =
true;
2374 serviceModified =
true;
2381 if ( service.
ttl() )
2384 serviceModified =
true;
2387 if ( serviceModified )
2390 modifyService( service.
alias(), service );
2394 if ( uglyHack.first )
2396 throw( uglyHack.second );
2404 MIL <<
"Going to modify service " << oldAlias << endl;
2415 const ServiceInfo & oldService = getService(oldAlias);
2417 Pathname location = oldService.
filepath();
2418 if( location.empty() )
2428 std::ofstream file(location.c_str());
2429 for_(it, tmpSet.begin(), tmpSet.end())
2431 if( *it != oldAlias )
2432 it->dumpAsIniOn(file);
2441 UrlCredentialExtractor( _options.rootDir ).collect( service.
url() );
2445 if ( oldAlias != service.
alias()
2448 std::vector<RepoInfo> toModify;
2449 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
2450 for_( it, toModify.begin(), toModify.end() )
2457 const auto & last = service.
repoStates().find( it->alias() );
2459 it->setEnabled( last->second.enabled );
2462 it->setEnabled(
false );
2465 if ( oldAlias != service.
alias() )
2466 it->setService(service.
alias());
2468 modifyRepository(it->alias(), *it);
2512 : _pimpl( new
Impl(opt) )
2544 std::string host( url_r.
getHost() );
2545 if ( ! host.empty() )
2667 {
return str << *obj.
_pimpl; }