57 using namespace zypp::repo;
72 MediaMounter(
const Url & url_r )
74 media::MediaManager mediamanager;
75 _mid = mediamanager.open( url_r );
76 mediamanager.attach(
_mid );
82 media::MediaManager mediamanager;
83 mediamanager.release(
_mid );
84 mediamanager.close(
_mid );
91 Pathname getPathName(
const Pathname & path_r = Pathname() )
const
93 media::MediaManager mediamanager;
94 return mediamanager.localPath(
_mid, path_r );
102 template <
class Iterator>
103 inline bool foundAliasIn(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
105 for_( it, begin_r, end_r )
106 if ( it->alias() == alias_r )
111 template <
class Container>
112 inline bool foundAliasIn(
const std::string & alias_r,
const Container & cont_r )
113 {
return foundAliasIn( alias_r, cont_r.begin(), cont_r.end() ); }
116 template <
class Iterator>
117 inline Iterator findAlias(
const std::string & alias_r, Iterator begin_r, Iterator end_r )
119 for_( it, begin_r, end_r )
120 if ( it->alias() == alias_r )
125 template <class Container>
126 inline typename Container::iterator findAlias( const std::
string & alias_r, Container & cont_r )
127 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
129 template <
class Container>
130 inline typename Container::const_iterator findAlias(
const std::string & alias_r,
const Container & cont_r )
131 {
return findAlias( alias_r, cont_r.begin(), cont_r.end() ); }
142 repoCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoCachePath() );
143 repoRawCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoMetadataPath() );
144 repoSolvCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoSolvfilesPath() );
145 repoPackagesCachePath = Pathname::assertprefix( root_r,
ZConfig::instance().repoPackagesPath() );
146 knownReposPath = Pathname::assertprefix( root_r,
ZConfig::instance().knownReposPath() );
147 knownServicesPath = Pathname::assertprefix( root_r,
ZConfig::instance().knownServicesPath() );
148 pluginsPath = Pathname::assertprefix( root_r,
ZConfig::instance().pluginsPath() );
191 : targetDistro(targetDistro_)
197 if (!targetDistro.empty()
202 <<
"Skipping repository meant for '" << targetDistro
203 <<
"' distribution (current distro is '"
209 repos.push_back(repo);
226 MIL <<
"repo file: " << file << endl;
229 return collector.
repos;
244 MIL <<
"directory " << dir << endl;
245 std::list<RepoInfo> repos;
246 std::list<Pathname> entries;
253 str::regex allowedRepoExt(
"^\\.repo(_[0-9]+)?$");
254 for ( std::list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
259 repos.insert( repos.end(), tmp.begin(), tmp.end() );
280 DBG <<
"reading repo file " << repo_file <<
", local path: " << local << endl;
289 if ( info.
alias().empty() )
293 if ( info.
alias()[0] ==
'.')
295 info,
_(
"Repository alias cannot start with dot.")));
300 if ( info.
alias().empty() )
304 if ( info.
alias()[0] ==
'.')
306 info,
_(
"Service alias cannot start with dot.")));
377 : _services( services_r )
382 _services.insert( service_r );
406 init_knownServices();
407 init_knownRepositories();
421 Pathname generateNonExistingName(
const Pathname &dir,
422 const std::string &basefilename )
const;
424 std::string generateFilename(
const RepoInfo & info )
const;
425 std::string generateFilename(
const ServiceInfo & info )
const;
429 void init_knownServices();
430 void init_knownRepositories();
433 friend Impl * rwcowClone<Impl>(
const Impl * rhs );
436 {
return new Impl( *
this ); }
444 return str <<
"RepoManager::Impl";
452 Pathname servfile = generateNonExistingName( options.knownServicesPath,
453 generateFilename( service ) );
456 MIL <<
"saving service in " << servfile << endl;
458 std::ofstream file( servfile.c_str() );
465 MIL <<
"done" << endl;
484 const std::string & basefilename )
const
486 std::string final_filename = basefilename;
488 while ( PathInfo(dir + final_filename).isExist() )
493 return dir + Pathname(final_filename);
507 std::string filename = info.
alias();
511 filename = Pathname(filename).extend(
".repo").asString();
512 MIL <<
"generating filename for repo [" << info.
alias() <<
"] : '" << filename <<
"'" << endl;
518 std::string filename = info.
alias();
522 filename = Pathname(filename).extend(
".service").asString();
523 MIL <<
"generating filename for service [" << info.
alias() <<
"] : '" << filename <<
"'" << endl;
530 Pathname dir = options.knownServicesPath;
531 std::list<Pathname> entries;
532 if (PathInfo(dir).isExist())
541 for_(it, entries.begin(), entries.end() )
552 MIL <<
"start construct known repos" << endl;
554 if ( PathInfo(options.knownReposPath).isExist() )
557 std::list<string> repo_esc_aliases;
558 std::list<string> entries;
559 for ( RepoInfoList::iterator it = repol.begin();
565 (*it).setMetadataPath(metadata_path);
569 (*it).setPackagesPath(packages_path);
572 repo_esc_aliases.push_back(it->escaped_alias());
578 std::set<string> oldfiles;
579 repo_esc_aliases.sort();
581 set_difference(entries.begin(), entries.end(), repo_esc_aliases.begin(), repo_esc_aliases.end(), std::inserter(oldfiles, oldfiles.end()));
582 for_(it, oldfiles.begin(), oldfiles.end())
589 MIL <<
"end construct known repos" << endl;
599 : _pimpl( new
Impl(opt) )
624 if ( it->alias() == alias )
632 if ( it->alias() == alias )
645 std::string host( url_r.
getHost() );
646 if ( ! host.empty() )
678 switch ( repokind.
toEnum() )
680 case RepoType::NONE_e:
682 repokind =
probe( productdatapath.asUrl() );
688 switch ( repokind.
toEnum() )
690 case RepoType::RPMMD_e :
692 status =
RepoStatus( productdatapath +
"/repodata/repomd.xml");
696 case RepoType::YAST2_e :
698 status =
RepoStatus( productdatapath +
"/content") && (
RepoStatus( mediarootpath +
"/media.1/media"));
702 case RepoType::RPMPLAINDIR_e :
704 if ( PathInfo(Pathname(productdatapath +
"/cookie")).isExist() )
705 status =
RepoStatus( productdatapath +
"/cookie");
709 case RepoType::NONE_e :
723 if ( repokind.
toEnum() == RepoType::NONE_e )
725 repokind =
probe( productdatapath.asUrl() );
727 if (repokind == RepoType::NONE_e)
731 switch ( repokind.
toEnum() )
733 case RepoType::RPMMD_e :
734 p = Pathname(productdatapath +
"/repodata/repomd.xml");
737 case RepoType::YAST2_e :
738 p = Pathname(productdatapath +
"/content");
741 case RepoType::RPMPLAINDIR_e :
742 p = Pathname(productdatapath +
"/cookie");
745 case RepoType::NONE_e :
766 MIL <<
"Going to try to check whether refresh is needed for " << url << endl;
773 if ( oldstatus.
empty() )
775 MIL <<
"No cached metadata, going to refresh" << endl;
781 if ( scheme ==
"cd" || scheme ==
"dvd" )
783 MIL <<
"never refresh CD/DVD" << endl;
792 double diff = difftime(
798 DBG <<
"last refresh = " << diff <<
" minutes ago" << endl;
804 WAR <<
"Repository '" << info.
alias() <<
"' was refreshed in the future!" << endl;
808 MIL <<
"Repository '" << info.
alias()
809 <<
"' has been refreshed less than repo.refresh.delay ("
811 <<
") minutes ago. Advising to skip refresh" << endl;
822 switch ( repokind.
toEnum() )
824 case RepoType::NONE_e:
832 if ( ( repokind.
toEnum() == RepoType::RPMMD_e ) ||
833 ( repokind.
toEnum() == RepoType::YAST2_e ) )
836 shared_ptr<repo::Downloader> downloader_ptr;
838 if ( repokind.
toEnum() == RepoType::RPMMD_e )
843 RepoStatus newstatus = downloader_ptr->status(media);
844 bool refresh =
false;
847 MIL <<
"repo has not changed" << endl;
850 MIL <<
"refresh set to forced" << endl;
856 MIL <<
"repo has changed, going to refresh" << endl;
865 else if ( repokind.
toEnum() == RepoType::RPMPLAINDIR_e )
867 MediaMounter media( url );
869 bool refresh =
false;
872 MIL <<
"repo has not changed" << endl;
875 MIL <<
"refresh set to forced" << endl;
881 MIL <<
"repo has changed, going to refresh" << endl;
898 ERR <<
"refresh check failed for " << url << endl;
913 RepoException rexception(
_(
"Valid metadata not found at specified URL(s)"));
927 MIL <<
"Going to refresh metadata from " << url << endl;
932 switch ( repokind.
toEnum() )
934 case RepoType::NONE_e:
938 if (repokind.
toEnum() != RepoType::NONE_e)
945 if ( info.
alias() == (*it).alias() )
948 modifiedrepo.
setType( repokind );
970 Exception ex(
_(
"Can't create metadata cache directory."));
974 if ( ( repokind.
toEnum() == RepoType::RPMMD_e ) ||
975 ( repokind.
toEnum() == RepoType::YAST2_e ) )
978 shared_ptr<repo::Downloader> downloader_ptr;
980 MIL <<
"Creating downloader for [ " << info.
alias() <<
" ]" << endl;
982 if ( repokind.
toEnum() == RepoType::RPMMD_e )
996 if ( PathInfo(cachepath).isExist() )
997 downloader_ptr->addCachePath(cachepath);
1000 downloader_ptr->download( media, tmpdir.
path() );
1002 else if ( repokind.
toEnum() == RepoType::RPMPLAINDIR_e )
1004 MediaMounter media( url );
1007 Pathname productpath( tmpdir.
path() / info.
path() );
1009 std::ofstream file( (productpath/
"cookie").c_str() );
1016 if ( ! info.
path().empty() && info.
path() !=
"/" )
1017 file <<
" (" << info.
path() <<
")";
1019 file << newstatus.
checksum() << endl;
1038 ERR <<
"Trying another url..." << endl;
1047 ERR <<
"No more urls..." << endl;
1057 progress.
sendTo(progressfnc);
1067 progress.
sendTo(progressfnc);
1087 if ( raw_metadata_status.
empty() )
1096 bool needs_cleaning =
false;
1099 MIL << info.
alias() <<
" is already cached." << endl;
1104 MIL << info.
alias() <<
" cache is up to date with metadata." << endl;
1109 MIL << info.
alias() <<
" cache rebuild is forced" << endl;
1113 needs_cleaning =
true;
1127 MIL << info.
alias() <<
" building cache..." << info.
type() << endl;
1137 if( ! PathInfo(base).userMayW() )
1139 Exception ex(
str::form(
_(
"Can't create cache at %s - no writing permissions."), base.c_str()) );
1142 Pathname solvfile = base /
"solv";
1148 switch ( repokind.
toEnum() )
1150 case RepoType::NONE_e:
1152 repokind =
probe( productdatapath.asUrl() );
1158 MIL <<
"repo type is " << repokind << endl;
1160 switch ( repokind.
toEnum() )
1162 case RepoType::RPMMD_e :
1163 case RepoType::YAST2_e :
1164 case RepoType::RPMPLAINDIR_e :
1168 scoped_ptr<MediaMounter> forPlainDirs;
1171 cmd.push_back(
"repo2solv.sh" );
1174 cmd.push_back(
"-o" );
1175 cmd.push_back( solvfile.asString() );
1177 if ( repokind == RepoType::RPMPLAINDIR )
1179 forPlainDirs.reset(
new MediaMounter( *info.
baseUrlsBegin() ) );
1181 cmd.push_back(
"-R" );
1183 cmd.push_back( forPlainDirs->getPathName( info.
path() ).c_str() );
1186 cmd.push_back( productdatapath.asString() );
1189 std::string errdetail;
1192 WAR <<
" " << output;
1193 if ( errdetail.empty() ) {
1197 errdetail += output;
1200 int ret = prog.
close();
1218 MIL <<
"Commit cache.." << endl;
1225 {
return probe( url, Pathname() ); }
1229 MIL <<
"going to probe the repo type at " << url <<
" (" << path <<
")" << endl;
1235 MIL <<
"Probed type NONE (not exists) at " << url <<
" (" << path <<
")" << endl;
1247 bool gotMediaException =
false;
1255 MIL <<
"Probed type RPMMD at " << url <<
" (" << path <<
")" << endl;
1262 DBG <<
"problem checking for repodata/repomd.xml file" << endl;
1264 gotMediaException =
true;
1271 MIL <<
"Probed type YAST2 at " << url <<
" (" << path <<
")" << endl;
1278 DBG <<
"problem checking for content file" << endl;
1280 gotMediaException =
true;
1286 MediaMounter media( url );
1287 if ( PathInfo(media.getPathName()/path).isDir() )
1290 MIL <<
"Probed type RPMPLAINDIR at " << url <<
" (" << path <<
")" << endl;
1304 if (gotMediaException)
1307 MIL <<
"Probed type NONE at " << url <<
" (" << path <<
")" << endl;
1315 MIL <<
"Going to clean up garbage in cache dirs" << endl;
1318 progress.
sendTo(progressrcv);
1321 std::list<Pathname> cachedirs;
1326 for_( dir, cachedirs.begin(), cachedirs.end() )
1328 if ( PathInfo(*dir).isExist() )
1330 std::list<Pathname> entries;
1335 unsigned sdircount = entries.size();
1336 unsigned sdircurrent = 1;
1337 for_( subdir, entries.begin(), entries.end() )
1342 if ( subdir->basename() == r->escaped_alias() )
1343 { found =
true;
break; }
1348 progress.
set( progress.
val() + sdircurrent * 100 / sdircount );
1353 progress.
set( progress.
val() + 100 );
1364 progress.
sendTo(progressrcv);
1367 MIL <<
"Removing raw metadata cache for " << info.
alias() << endl;
1392 Pathname cookiefile = base /
"cookie";
1403 if ( ! PathInfo(solvfile).isExist() )
1428 MIL <<
"Try to handle exception by rebuilding the solv-file" << endl;
1449 MIL <<
"Try adding repo " << info << endl;
1458 DBG <<
"unknown repository type, probing" << endl;
1464 if ( probedtype == RepoType::NONE )
1479 MIL <<
"Saving repo in " << repofile << endl;
1481 std::ofstream file(repofile.c_str());
1495 RepoInfo & oinfo( const_cast<RepoInfo &>(info) );
1504 bool havePasswords =
false;
1506 if ( urlit->hasCredentialsInAuthority() )
1508 havePasswords =
true;
1512 if ( havePasswords )
1518 if (urlit->hasCredentialsInAuthority())
1526 MIL <<
"done" << endl;
1533 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
1540 if ( (*it).alias() == (*kit).alias() )
1542 ERR <<
"To be added repo " << (*it).alias() <<
" conflicts with existing repo " << (*kit).alias() << endl;
1548 std::string filename = Pathname(url.
getPathName()).basename();
1550 if ( filename == Pathname() )
1561 MIL <<
"Saving " << repos.size() <<
" repo" << ( repos.size() ?
"s" :
"" ) <<
" in " << repofile << endl;
1563 std::ofstream file(repofile.c_str());
1570 for ( std::list<RepoInfo>::iterator it = repos.begin();
1574 MIL <<
"Saving " << (*it).alias() << endl;
1575 it->setFilepath(repofile.asString());
1576 it->dumpAsIniOn(file);
1582 MIL <<
"done" << endl;
1595 MIL <<
"Going to delete repo " << info.
alias() << endl;
1602 if ( (!info.
alias().empty()) && ( info.
alias() != (*it).alias() ) )
1618 if ( (filerepos.size() == 1) && ( filerepos.front().alias() == todelete.
alias() ) )
1626 MIL << todelete.
alias() <<
" sucessfully deleted." << endl;
1638 std::ofstream file(todelete.
filepath().c_str());
1644 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1645 fit != filerepos.end();
1648 if ( (*fit).alias() != todelete.
alias() )
1649 (*fit).dumpAsIniOn(file);
1661 MIL << todelete.
alias() <<
" sucessfully deleted." << endl;
1703 std::ofstream file(toedit.
filepath().c_str());
1709 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
1710 fit != filerepos.end();
1715 if ( (*fit).alias() != toedit.
alias() )
1716 (*fit).dumpAsIniOn(file);
1725 MIL <<
"repo " << alias <<
" modified" << endl;
1752 urlit != (*it).baseUrlsEnd();
1755 if ((*urlit).asString(urlview) == url.
asString(urlview))
1785 if ( it->alias() == alias )
1793 if ( it->alias() == alias )
1829 MIL <<
"added service " << toSave.
alias() << endl;
1836 MIL <<
"Going to delete repo " << alias << endl;
1840 Pathname location = service.
filepath();
1841 if( location.empty() )
1850 if ( tmpSet.size() == 1 )
1857 MIL << alias <<
" sucessfully deleted." << endl;
1863 std::ofstream file(location.c_str());
1870 for_(it, tmpSet.begin(), tmpSet.end())
1872 if( it->alias() != alias )
1873 it->dumpAsIniOn(file);
1876 MIL << alias <<
" sucessfully deleted from file " << location << endl;
1882 boost::make_function_output_iterator(
1899 for_( it, services.begin(), services.end() )
1901 if ( !it->enabled() )
1923 bool serviceModified =
false;
1924 MIL <<
"Going to refresh service '" << service.
alias() <<
"', url: "<< service.
url() << endl;
1932 if ( type != ServiceType::NONE )
1935 serviceModified =
true;
1941 if ( servicesTargetDistro.empty() )
1945 DBG <<
"ServicesTargetDistro: " << servicesTargetDistro << endl;
1960 uglyHack.first =
true;
1961 uglyHack.second = e;
1970 if ( it->baseUrlsEmpty() )
1971 url = service.
url();
1975 url = *it->baseUrlsBegin();
1980 if ( !it->path().empty() )
1989 it->setAlias(
str::form(
"%s:%s", service.
alias().c_str(), it->alias().c_str() ) );
1992 it->setBaseUrl( url );
1994 it->setService( service.
alias() );
2000 RepoInfoList oldRepos;
2004 for_( it, oldRepos.begin(), oldRepos.end() )
2006 if ( ! foundAliasIn( it->alias(), collector.
repos ) )
2010 DBG <<
"Service removes enabled repo " << it->alias() << endl;
2012 serviceModified =
true;
2016 DBG <<
"Service removes disabled repo " << it->alias() << endl;
2034 if ( beEnabled ) it->setEnabled(
true);
2035 if ( beDisabled ) it->setEnabled(
false);
2043 serviceModified =
true;
2046 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
2047 if ( oldRepo == oldRepos.end() )
2054 DBG <<
"Service adds repo " << it->alias() <<
" " << (it->enabled()?
"enabled":
"disabled") << endl;
2063 bool oldRepoModified =
false;
2068 if ( ! oldRepo->enabled() )
2070 DBG <<
"Service repo " << it->alias() <<
" gets enabled" << endl;
2071 oldRepo->setEnabled(
true );
2072 oldRepoModified =
true;
2076 DBG <<
"Service repo " << it->alias() <<
" stays enabled" << endl;
2079 else if ( beDisabled )
2081 if ( oldRepo->enabled() )
2083 DBG <<
"Service repo " << it->alias() <<
" gets disabled" << endl;
2084 oldRepo->setEnabled(
false );
2085 oldRepoModified =
true;
2089 DBG <<
"Service repo " << it->alias() <<
" stays disabled" << endl;
2094 DBG <<
"Service repo " << it->alias() <<
" stays " << (oldRepo->enabled()?
"enabled":
"disabled") << endl;
2099 if ( oldRepo->url() != it->url() )
2101 DBG <<
"Service repo " << it->alias() <<
" gets new URL " << it->url() << endl;
2102 oldRepo->setBaseUrl( it->url() );
2103 oldRepoModified =
true;
2107 if ( oldRepoModified )
2118 serviceModified =
true;
2123 if ( serviceModified )
2129 if ( uglyHack.first )
2131 throw( uglyHack.second );
2139 MIL <<
"Going to modify service " << oldAlias << endl;
2145 if ( service.
type() == ServiceType::PLUGIN )
2147 MIL <<
"Not modifying plugin service '" << oldAlias <<
"'" << endl;
2153 Pathname location = oldService.
filepath();
2154 if( location.empty() )
2164 std::ofstream file(location.c_str());
2165 for_(it, tmpSet.begin(), tmpSet.end())
2167 if( *it != oldAlias )
2168 it->dumpAsIniOn(file);
2178 if( oldAlias != service.
alias()
2182 std::vector<RepoInfo> toModify;
2184 for_( it, toModify.begin(), toModify.end() )
2187 it->setEnabled(
false);
2194 it->setService(service.
alias());
2236 return str << *obj.
_pimpl;