42 template <
class Executor,
class OpType>
43 struct ProbeRepoLogic :
public LogicBase<Executor, OpType>
51 using MediaHandle =
typename ProvideType::MediaHandle;
56 : _zyppContext(std::move(zyppCtx))
57 , _medium(std::move(medium))
58 , _path(std::move(path))
59 , _targetPath(std::move(targetPath))
62 MaybeAsyncRef<expected<zypp::repo::RepoType>> execute( ) {
63 const auto &
url = _medium.baseUrl();
64 MIL <<
"going to probe the repo type at " <<
url <<
" (" << _path <<
")" << std::endl;
68 MIL <<
"Probed type NONE (not exists) at " <<
url <<
" (" << _path <<
")" << std::endl;
78 std::shared_ptr<ProvideType> providerRef = _zyppContext->provider();
83 return providerRef->attachMediaIfNeeded( _medium )
84 |
and_then([
this, providerRef]( MediaHandle medium )
87 return providerRef->provide( medium, _path/
"repodata/repomd.xml",
ProvideFileSpec().setCheckExistsOnly( !_targetPath.has_value() ) )
88 |
and_then( maybeCopyResultToDest(
"repodata/repomd.xml") )
91 |
or_else( [
this, providerRef, medium]( std::exception_ptr err ) {
93 std::rethrow_exception (err);
98 DBG <<
"problem checking for repodata/repomd.xml file" << std::endl;
99 _error.remember ( err );
100 _gotMediaError =
true;
105 return providerRef->provide( medium, _path/
"content",
ProvideFileSpec().setCheckExistsOnly( !_targetPath.has_value() ) )
106 |
and_then( maybeCopyResultToDest(
"content") )
110 |
or_else( [
this, medium]( std::exception_ptr err ) {
113 std::rethrow_exception (err);
118 DBG <<
"problem checking for content file" << std::endl;
119 _error.remember ( err );
120 _gotMediaError =
true;
130 const auto &
url = medium.baseUrl();
133 if ( ! (
url.schemeIsDownloading() ||
url.schemeIsPlugin() ) ) {
137 MIL <<
"Probed type RPMPLAINDIR at " <<
url <<
" (" << _path <<
")" << std::endl;
145 MIL <<
"Probed type NONE at " <<
url <<
" (" << _path <<
")" << std::endl;
157 auto maybeCopyResultToDest ( std::string &&subPath ) {
160 MIL <<
"Target path is set, copying " << file.file() <<
" to " << *_targetPath/subPath << std::endl;
161 return std::move(file)
162 | ProvideType::copyResultToDest( _zyppContext->provider(), *_targetPath/subPath)
170 ZyppContextRefType _zyppContext;
173 std::optional<zypp::Pathname> _targetPath;
176 bool _gotMediaError =
false;
179 template <
class RefreshContextRef>
180 auto probeRepoLogic( RefreshContextRef ctx,
RepoInfo repo, std::optional<zypp::Pathname> targetPath)
184 |
and_then( [ctx, path =
repo.path() ](
auto &&mediaHandle ) {
185 return probeRepoType( ctx, std::forward<decltype(mediaHandle)>(mediaHandle), path );
202 return probeRepoLogic( std::move(ctx), std::move(
repo), std::move(targetPath) );
207 return probeRepoLogic( std::move(ctx), std::move(
repo), std::move(targetPath) );
212 template <
class ZyppContextRef>
213 auto readRepoFileLogic( ZyppContextRef ctx,
zypp::Url repoFileUrl )
217 |
and_then([repoFileUrl](
auto local ){
218 DBG <<
"reading repo file " << repoFileUrl <<
", local path: " << local.file() << std::endl;
226 return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
231 return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
236 template<
typename Executor,
class OpType>
237 struct CheckIfToRefreshMetadataLogic :
public LogicBase<Executor, OpType> {
243 using ZyppContextRefType =
typename RefreshContextRefType::element_type::ContextRefType;
244 using ZyppContextType =
typename RefreshContextRefType::element_type::ContextType;
245 using ProvideType =
typename ZyppContextType::ProvideType;
247 using MediaHandle =
typename ProvideType::MediaHandle;
250 CheckIfToRefreshMetadataLogic( RefreshContextRefType refCtx,
LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
251 : _refreshContext(
std::move(refCtx))
252 , _progress(
std::move( progressObserver ))
253 , _medium(
std::move( medium ))
256 MaybeAsyncRef<expected<repo::RefreshCheckStatus>> execute( ) {
258 MIL <<
"Going to CheckIfToRefreshMetadata" << std::endl;
263 const auto &info = _refreshContext->repoInfo();
264 MIL <<
"Check if to refresh repo " << _refreshContext->repoInfo().alias() <<
" at " << _medium.baseUrl() <<
" (" << info.type() <<
")" << std::endl;
269 |
and_then( [
this](zypp::RepoStatus oldstatus) {
271 const auto &info = _refreshContext->repoInfo();
273 if ( oldstatus.
empty() ) {
274 MIL <<
"No cached metadata, going to refresh" << std::endl;
278 if ( _medium.baseUrl().schemeIsVolatile() ) {
279 MIL <<
"Never refresh CD/DVD" << std::endl;
284 MIL <<
"Forced refresh!" << std::endl;
288 if ( _medium.baseUrl().schemeIsLocal() ) {
301 if ( oldstatus == *cachestatus ) {
304 const auto refDelay = _refreshContext->zyppContext()->config().repo_refresh_delay();
305 if ( diff < refDelay ) {
307 WAR <<
"Repository '" << info.alias() <<
"' was refreshed in the future!" << std::endl;
310 MIL <<
"Repository '" << info.alias()
311 <<
"' has been refreshed less than repo.refresh.delay ("
313 <<
") minutes ago. Advising to skip refresh" << std::endl;
319 MIL <<
"Metadata and solv cache don't match. Check data on server..." << std::endl;
323 return info.type() | [
this]( zypp::repo::RepoType repokind ) {
326 return probeRepoType( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path() );
328 } |
and_then([
this, oldstatus]( zypp::repo::RepoType repokind ) {
331 _refreshContext->repoInfo().setProbedType( repokind );
333 auto dlContext = std::make_shared<repo::DownloadContext<ZyppContextRefType>>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
335 |
and_then( [
this, dlContext, oldstatus]( zypp::RepoStatus newstatus ){
337 if ( oldstatus == newstatus ) {
338 MIL <<
"repo has not changed" << std::endl;
343 MIL <<
"repo has changed, going to refresh" << std::endl;
344 MIL <<
"Old status: " << oldstatus <<
" New Status: " << newstatus << std::endl;
353 RefreshContextRefType _refreshContext;
354 ProgressObserverRef _progress;
355 LazyMediaHandle _medium;
372 template<
typename Executor,
class OpType>
373 struct RefreshMetadataLogic :
public LogicBase<Executor, OpType>{
380 using ZyppContextRefType =
typename RefreshContextRefType::element_type::ContextRefType;
381 using ZyppContextType =
typename RefreshContextRefType::element_type::ContextType;
382 using ProvideType =
typename ZyppContextType::ProvideType;
383 using MediaHandle =
typename ProvideType::MediaHandle;
388 using DlContextRefType = std::shared_ptr<DlContextType>;
390 RefreshMetadataLogic( RefreshContextRefType refCtx,
LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
391 : _refreshContext(
std::move(refCtx))
392 , _progress (
std::move( progressObserver ) )
393 , _medium (
std::move( medium ) )
396 MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
403 MIL <<
"RefreshCheckStatus returned: " << status << std::endl;
411 if (
zypp::IamNotRoot() && not zypp::PathInfo(_refreshContext->rawCachePath().dirname()).userMayWX() ) {
412 WAR <<
"No permision to write cache " << zypp::PathInfo(_refreshContext->rawCachePath().dirname()) << std::endl;
413 auto exception =
ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refreshContext->repoInfo() ) );
417 MIL <<
"Going to refresh metadata from " << _medium.baseUrl() << std::endl;
422 return probeRepoType ( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path() )
423 |
and_then([
this]( zypp::repo::RepoType repokind ) {
425 auto &info = _refreshContext->repoInfo();
427 if ( info.type() != repokind ) {
428 _refreshContext->setProbedType( repokind );
430 info.setProbedType( repokind );
437 const zypp::Pathname &mediarootpath = _refreshContext->rawCachePath();
443 auto dlContext = std::make_shared<DlContextType>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
444 dlContext->setPluginRepoverification( _refreshContext->pluginRepoverification() );
449 |
and_then([
this]( DlContextRefType && ) {
453 _refreshContext->saveToRawCache();
463 RefreshContextRefType _refreshContext;
464 ProgressObserverRef _progress;
465 LazyMediaHandle _medium;
466 zypp::Pathname _mediarootpath;
482 template <
class RefreshContextRef>
483 auto refreshMetadataLogic( RefreshContextRef refCtx, ProgressObserverRef progressObserver)
491 : rexception { info_r,
_(
"Failed to retrieve new repository metadata.") }
495 if ( rexception.historyEmpty() ) {
496 rexception.remember( old_r );
501 zypp::repo::RepoException rexception;
504 auto helper = std::make_shared<ExHelper>( ExHelper{ refCtx->repoInfo() } );
507 auto refreshPipeline = [ refCtx, progressObserver ]( std::vector<zypp::Url> urls ){
508 return refCtx->zyppContext()->provider()->prepareMedia( urls, zyppng::ProvideMediaSpec() )
509 |
and_then( [ refCtx , progressObserver](
auto mediaHandle )
mutable {
return refreshMetadata ( std::move(refCtx), std::move(mediaHandle), progressObserver ); } );
513 auto predicate = [ info = refCtx->repoInfo(), helper ](
const expected<RefreshContextRef> &res ) ->
bool{
517 }
catch (
const zypp::repo::RepoNoPermissionException &e ) {
519 ERR <<
"Giving up..." << std::endl;
520 helper->remember( e );
522 }
catch (
const zypp::Exception &e ) {
523 ERR <<
"Trying another url..." << std::endl;
524 helper->remember( e );
533 return refCtx->repoInfo().groupedBaseUrls()
535 | [helper]( expected<RefreshContextRef> result ) {
538 ERR <<
"No more urls..." << std::endl;
548 return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
552 return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
558 template <
typename ZyppCtxRef>
struct Repo2SolvOp;
561 struct Repo2SolvOp<ContextRef> :
public AsyncOp<expected<void>>
566 MIL <<
"Starting repo2solv for repo " <<
repo.alias () << std::endl;
567 auto me = std::make_shared<Repo2SolvOp<ContextRef>>();
568 me->_repo = std::move(
repo);
573 std::vector<const char *> argsIn;
574 argsIn.reserve ( args.size() );
575 std::for_each( args.begin (), args.end(), [&](
const std::string &s ) { argsIn.push_back(s.data()); });
576 argsIn.push_back (
nullptr);
578 if (!me->_proc->start( argsIn.data() )) {
585 const ByteArray &data = _proc->readLine();
586 const std::string &line = data.
asString();
591 void procFinished(
int ret ) {
593 while ( _proc->canReadLine() )
597 zypp::repo::RepoException ex( _repo,
zypp::str::form(
_(
"Failed to cache repo (%d)."), ret ));
598 ex.addHistory( zypp::str::Str() << _proc->executedCommand() << std::endl << _errdetail << _proc->execError() );
607 zypp::RepoInfo _repo;
608 std::string _errdetail;
612 struct Repo2SolvOp<SyncContextRef>
616 std::string errdetail;
618 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
619 WAR <<
" " << output;
623 int ret = prog.close();
626 zypp::repo::RepoException ex(repo,
zypp::str::form(
_(
"Failed to cache repo (%d)."), ret ));
627 ex.addHistory( zypp::str::Str() << prog.command() << std::endl << errdetail << prog.execError() );
634 template<
typename Executor,
class OpType>
635 struct BuildCacheLogic :
public LogicBase<Executor, OpType>{
638 using ZyppContextRefType =
typename RefreshContextRefType::element_type::ContextRefType;
639 using ZyppContextType =
typename RefreshContextRefType::element_type::ContextType;
640 using ProvideType =
typename ZyppContextType::ProvideType;
641 using MediaHandle =
typename ProvideType::MediaHandle;
642 using ProvideRes =
typename ProvideType::Res;
647 : _refCtx( std::move(refCtx) )
649 , _progressObserver( std::move(progressObserver) )
652 MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
663 const auto &options = _refCtx->repoManagerOptions();
674 if ( raw_metadata_status.
empty() )
680 zypp::Pathname mediarootParent { _mediarootpath.dirname() };
683 && (
zypp::IamRoot() || zypp::PathInfo(mediarootParent).userMayWX() ) ) {
690 WAR <<
"No permission to write raw cache " << mediarootParent << std::endl;
691 auto exception =
ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refCtx->repoInfo() ) );
699 bool needs_cleaning =
false;
700 const auto &info = _refCtx->repoInfo();
701 if ( _refCtx->repoManager()->isCached( info ) )
703 MIL << info.alias() <<
" is already cached." << std::endl;
708 if ( *cache_status == raw_metadata_status )
710 MIL << info.alias() <<
" cache is up to date with metadata." << std::endl;
716 |
and_then([
this]( zypp::Pathname base ){
717 if ( ! zypp::PathInfo(base/
"solv.idx").isExist() )
724 MIL << info.alias() <<
" cache rebuild is forced" << std::endl;
728 needs_cleaning =
true;
735 auto r = _refCtx->repoManager()->cleanCache(info);
740 MIL << info.alias() <<
" building cache..." << info.type() << std::endl;
754 zypp::Exception ex(
zypp::str::form(
_(
"Can't create cache at %s - no writing permissions."), base->c_str()) );
758 zypp::Pathname solvfile = *base /
"solv";
761 zypp::repo::RepoType repokind = info.type();
764 switch ( repokind.
toEnum() )
774 MIL <<
"repo type is " << repokind << std::endl;
776 return mountIfRequired( repokind, info )
777 |
and_then([
this, repokind, solvfile = std::move(solvfile) ]( std::optional<MediaHandle> forPlainDirs )
mutable {
779 const auto &info = _refCtx->repoInfo();
781 switch ( repokind.
toEnum() )
791#ifdef ZYPP_REPO2SOLV_PATH
792 cmd.push_back( ZYPP_REPO2SOLV_PATH );
794 cmd.push_back( zypp::PathInfo(
"/usr/bin/repo2solv" ).isFile() ?
"repo2solv" :
"repo2solv.sh" );
797 cmd.push_back(
"-o" );
798 cmd.push_back( solvfile.
asString() );
799 cmd.push_back(
"-X" );
805 cmd.push_back(
"-R" );
807 std::optional<zypp::Pathname> localPath = forPlainDirs.has_value() ? forPlainDirs->localPath() : zypp::Pathname();
812 cmd.push_back( (*localPath / info.path().absolutename()).c_str() );
815 cmd.push_back( _productdatapath.asString() );
817 return Repo2SolvOp<ZyppContextRefType>::run( info, std::move(cmd) )
818 |
and_then( [
this, guard = std::move(guard), solvfile = std::move(solvfile) ]()
mutable {
820 guard.resetDispose();
830 |
and_then([
this, raw_metadata_status](){
832 return _refCtx->repoManager()->setCacheStatus( _refCtx->repoInfo(), raw_metadata_status );
836 MIL <<
"Commit cache.." << std::endl;
841 |
or_else ( [
this]( std::exception_ptr e ) {
848 MaybeAsyncRef<expected<std::optional<MediaHandle>>> mountIfRequired ( zypp::repo::RepoType repokind, zypp::RepoInfo info ) {
852 return _refCtx->zyppContext()->provider()->attachMedia( info.
url(), ProvideMediaSpec() )
853 |
and_then( [
this]( MediaHandle handle ) {
859 RefreshContextRefType _refCtx;
861 ProgressObserverRef _progressObserver;
863 zypp::Pathname _mediarootpath;
864 zypp::Pathname _productdatapath;
882 template<
typename Executor,
class OpType>
883 struct AddRepoLogic :
public LogicBase<Executor, OpType>{
889 AddRepoLogic( RepoManagerPtrType &&repoMgrRef,
RepoInfo &&info, ProgressObserverRef &&myProgress )
890 : _repoMgrRef(
std::move(repoMgrRef) )
891 , _info(
std::move(info) )
892 , _myProgress (
std::move(myProgress) )
895 MaybeAsyncRef<expected<RepoInfo> > execute() {
901 MIL <<
"Try adding repo " << _info << std::endl;
905 if ( _repoMgrRef->repos().find(_info) != _repoMgrRef->repos().end() )
909 if ( _repoMgrRef->options().probe )
911 DBG <<
"unknown repository type, probing" << std::endl;
914 |
and_then([
this]( zypp::repo::RepoType probedtype ) {
927 |
and_then( [
this](
RepoInfo tosave ){
return _repoMgrRef->addProbedRepository( tosave, tosave.
type() ); })
930 MIL <<
"done" << std::endl;
933 |
or_else( [
this]( std::exception_ptr e) {
935 MIL <<
"done" << std::endl;
941 RepoManagerPtrType _repoMgrRef;
943 ProgressObserverRef _myProgress;
959 template<
typename Executor,
class OpType>
960 struct AddReposLogic :
public LogicBase<Executor, OpType>{
965 AddReposLogic( RepoManagerPtrType &&repoMgrRef,
zypp::Url &&
url, ProgressObserverRef &&myProgress )
966 : _repoMgrRef(
std::move(repoMgrRef) )
968 , _myProgress (
std::move(myProgress) )
971 MaybeAsyncRef<expected<void>> execute() {
976 |
and_then([
this]( std::list<RepoInfo> repos ) {
978 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
983 for_ ( kit, _repoMgrRef->repoBegin(), _repoMgrRef->repoEnd() )
985 if ( (*it).alias() == (*kit).alias() )
987 ERR <<
"To be added repo " << (*it).alias() <<
" conflicts with existing repo " << (*kit).alias() << std::endl;
993 std::string filename = zypp::Pathname(_url.getPathName()).basename();
994 if ( filename == zypp::Pathname() )
1000 const auto &options = _repoMgrRef->options();
1005 zypp::Pathname repofile = _repoMgrRef->generateNonExistingName( options.knownReposPath, filename );
1007 MIL <<
"Saving " << repos.size() <<
" repo" << ( repos.size() ?
"s" :
"" ) <<
" in " << repofile << std::endl;
1009 std::ofstream file(repofile.
c_str());
1016 for ( std::list<RepoInfo>::iterator it = repos.begin();
1020 MIL <<
"Saving " << (*it).alias() << std::endl;
1028 it->dumpAsIniOn(file);
1029 it->setFilepath(repofile);
1030 it->setMetadataPath( *rawCachePath );
1031 it->setPackagesPath( *pckCachePath );
1032 _repoMgrRef->reposManip().insert(*it);
1034 zypp::HistoryLog( _repoMgrRef->options().rootDir).addRepository(*it);
1037 MIL <<
"done" << std::endl;
1043 RepoManagerPtrType _repoMgrRef;
1045 ProgressObserverRef _myProgress;
1063 template<
typename Executor,
class OpType>
1064 struct RefreshGeoIpLogic :
public LogicBase<Executor, OpType>{
1070 using ZyppContextType =
typename ZyppContextRefType::element_type;
1071 using ProvideType =
typename ZyppContextType::ProvideType;
1072 using MediaHandle =
typename ProvideType::MediaHandle;
1073 using ProvideRes =
typename ProvideType::Res;
1077 : _zyppCtx(
std::move(zyppCtx) )
1078 , _urls(
std::move(urls) )
1081 MaybeAsyncRef<expected<void>> execute() {
1085 if ( !_zyppCtx->config().geoipEnabled() ) {
1086 MIL <<
"GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
1090 std::vector<std::string> hosts;
1091 for (
const auto &baseUrl : _urls ) {
1092 const auto &host = baseUrl.getHost();
1093 if (
zypp::any_of( _zyppCtx->config().geoipHostnames(), [&host](
const auto &elem ){ return ( zypp::str::compareCI( host, elem ) == 0 ); } ) ) {
1094 hosts.push_back( host );
1099 if ( hosts.empty() ) {
1100 MIL <<
"No configured geoip URL found, not updating geoip data" << std::endl;
1104 _geoIPCache = _zyppCtx->config().geoipCachePath();
1107 MIL <<
"Unable to create cache directory for GeoIP." << std::endl;
1111 if (
zypp::IamNotRoot() && not zypp::PathInfo(_geoIPCache).userMayRWX() ) {
1112 MIL <<
"No access rights for the GeoIP cache directory." << std::endl;
1121 zypp::PathInfo pi( dir/entry.
name );
1122 auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
1123 if ( age < std::chrono::hours(24) )
1126 MIL <<
"Removing GeoIP file for " << entry.
name <<
" since it's older than 24hrs." << std::endl;
1131 auto firstOfCb = [
this]( std::string hostname ) {
1134 if ( zypp::PathInfo( _geoIPCache / hostname ).isExist() ) {
1135 MIL <<
"Skipping GeoIP request for " << hostname <<
" since a valid cache entry exists." << std::endl;
1139 MIL <<
"Query GeoIP for " << hostname << std::endl;
1146 }
catch(
const zypp::Exception &e ) {
1148 MIL <<
"Ignoring invalid GeoIP hostname: " << hostname << std::endl;
1153 return _zyppCtx->provider()->attachMedia( url, ProvideMediaSpec() )
1154 |
and_then( [
this]( MediaHandle provideHdl ) {
return _zyppCtx->provider()->provide( provideHdl,
"/geoip", ProvideFileSpec() ); })
1155 |
inspect_err( [hostname](
const std::exception_ptr& ){
MIL <<
"Failed to query GeoIP from hostname: " << hostname << std::endl; } )
1156 |
and_then( [hostname,
this]( ProvideRes provideRes ) {
1160 constexpr auto writeHostToFile = [](
const zypp::Pathname &fName,
const std::string &host ){
1162 out.open( fName.
asString(), std::ios_base::trunc );
1163 if ( out.is_open() ) {
1164 out << host << std::endl;
1166 MIL <<
"Failed to create/open GeoIP cache file " << fName << std::endl;
1170 std::string geoipMirror;
1172 zypp::xml::Reader reader( provideRes.
file() );
1173 if ( reader.seekToNode( 1,
"host" ) ) {
1174 const auto &str = reader.nodeText().asString();
1182 MIL <<
"Storing geoIP redirection: " << hostname <<
" -> " << str << std::endl;
1187 MIL <<
"No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
1189 }
catch (
const zypp::Exception &e ) {
1191 MIL <<
"Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
1194 writeHostToFile( _geoIPCache / hostname, geoipMirror );
1197 | []( expected<void> res ) {
return res.
is_valid(); };
1200 return std::move(hosts)
1201 |
firstOf( std::move(firstOfCb),
false, zyppng::detail::ContinueUntilValidPredicate() )
1202 | [](
bool foundGeoIP ){
1205 MIL <<
"Successfully queried GeoIP data." << std::endl;
1209 MIL <<
"Failed to query GeoIP data." << std::endl;
1210 return expected<void>::error( std::make_exception_ptr( zypp::Exception(
"No valid geoIP url found" )) );
1216 ZyppContextRefType _zyppCtx;
1218 zypp::Pathname _geoIPCache;