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 ]( zypp::Url url ){
 
  508        return refCtx->zyppContext()->provider()->prepareMedia( url, 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 );
 
  532      return refCtx->repoInfo().baseUrls()
 
  534        | [helper]( expected<RefreshContextRef> result ) {
 
  537            ERR << 
"No more urls..." << std::endl;
 
  547    return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
 
 
  551    return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
 
 
  557    template <
typename ZyppCtxRef> 
struct Repo2SolvOp;
 
  560    struct Repo2SolvOp<ContextRef> : 
public AsyncOp<expected<void>>
 
  565        MIL << 
"Starting repo2solv for repo " << 
repo.alias () << std::endl;
 
  566        auto me = std::make_shared<Repo2SolvOp<ContextRef>>();
 
  567        me->_repo = std::move(
repo);
 
  572        std::vector<const char *> argsIn;
 
  573        argsIn.reserve ( args.size() );
 
  574        std::for_each( args.begin (), args.end(), [&]( 
const std::string &s ) { argsIn.push_back(s.data()); });
 
  575        argsIn.push_back (
nullptr);
 
  577        if (!me->_proc->start( argsIn.data() )) {
 
  584        const ByteArray &data = _proc->readLine();
 
  585        const std::string &line = data.
asString();
 
  590      void procFinished( 
int ret ) {
 
  592        while ( _proc->canReadLine() )
 
  596          zypp::repo::RepoException ex( _repo, 
zypp::str::form( 
_(
"Failed to cache repo (%d)."), ret ));
 
  597          ex.addHistory( zypp::str::Str() << _proc->executedCommand() << std::endl << _errdetail << _proc->execError() ); 
 
  606      zypp::RepoInfo _repo;
 
  607      std::string _errdetail;
 
  611    struct Repo2SolvOp<SyncContextRef>
 
  615        std::string errdetail;
 
  617        for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
 
  618          WAR << 
"  " << output;
 
  622        int ret = prog.close();
 
  625          zypp::repo::RepoException ex(repo, 
zypp::str::form( 
_(
"Failed to cache repo (%d)."), ret ));
 
  626          ex.addHistory( zypp::str::Str() << prog.command() << std::endl << errdetail << prog.execError() ); 
 
  633    template<
typename Executor, 
class OpType>
 
  634    struct BuildCacheLogic : 
public LogicBase<Executor, OpType>{
 
  637      using ZyppContextRefType    = 
typename RefreshContextRefType::element_type::ContextRefType;
 
  638      using ZyppContextType       = 
typename RefreshContextRefType::element_type::ContextType;
 
  639      using ProvideType           = 
typename ZyppContextType::ProvideType;
 
  640      using MediaHandle           = 
typename ProvideType::MediaHandle;
 
  641      using ProvideRes            = 
typename ProvideType::Res;
 
  646        : _refCtx( std::move(refCtx) )
 
  648        , _progressObserver( std::move(progressObserver) )
 
  651      MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
 
  662          const auto &options = _refCtx->repoManagerOptions();
 
  673          if ( raw_metadata_status.
empty() )
 
  679            zypp::Pathname mediarootParent { _mediarootpath.dirname() };
 
  682              && ( 
zypp::IamRoot() || zypp::PathInfo(mediarootParent).userMayWX() ) ) {
 
  689              WAR << 
"No permission to write raw cache " << mediarootParent << std::endl;
 
  690              auto exception = 
ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refCtx->repoInfo() ) );
 
  698          bool needs_cleaning = 
false;
 
  699          const auto &info = _refCtx->repoInfo();
 
  700          if ( _refCtx->repoManager()->isCached( info ) )
 
  702            MIL << info.alias() << 
" is already cached." << std::endl;
 
  707            if ( *cache_status == raw_metadata_status )
 
  709              MIL << info.alias() << 
" cache is up to date with metadata." << std::endl;
 
  715                  | 
and_then([
this]( zypp::Pathname base ){
 
  716                    if ( ! zypp::PathInfo(base/
"solv.idx").isExist() )
 
  723                MIL << info.alias() << 
" cache rebuild is forced" << std::endl;
 
  727            needs_cleaning = 
true;
 
  734            auto r = _refCtx->repoManager()->cleanCache(info);
 
  739          MIL << info.alias() << 
" building cache..." << info.type() << std::endl;
 
  753            zypp::Exception ex(
zypp::str::form( 
_(
"Can't create cache at %s - no writing permissions."), base->c_str()) );
 
  757          zypp::Pathname solvfile = *base / 
"solv";
 
  760          zypp::repo::RepoType repokind = info.type();
 
  763          switch ( repokind.
toEnum() )
 
  773          MIL << 
"repo type is " << repokind << std::endl;
 
  775          return mountIfRequired( repokind, info )
 
  776          | 
and_then([
this, repokind, solvfile = std::move(solvfile) ]( std::optional<MediaHandle> forPlainDirs ) 
mutable {
 
  778            const auto &info = _refCtx->repoInfo();
 
  780            switch ( repokind.
toEnum() )
 
  790#ifdef ZYPP_REPO2SOLV_PATH 
  791                cmd.push_back( ZYPP_REPO2SOLV_PATH );
 
  793                cmd.push_back( zypp::PathInfo( 
"/usr/bin/repo2solv" ).isFile() ? 
"repo2solv" : 
"repo2solv.sh" );
 
  796                cmd.push_back( 
"-o" );
 
  797                cmd.push_back( solvfile.
asString() );
 
  798                cmd.push_back( 
"-X" );  
 
  804                  cmd.push_back( 
"-R" );
 
  806                  std::optional<zypp::Pathname> localPath = forPlainDirs.has_value() ? forPlainDirs->localPath() : zypp::Pathname();
 
  811                  cmd.push_back( (*localPath / info.path().absolutename()).c_str() );
 
  814                  cmd.push_back( _productdatapath.asString() );
 
  816                return Repo2SolvOp<ZyppContextRefType>::run( info, std::move(cmd) )
 
  817                | 
and_then( [
this, guard = std::move(guard), solvfile = std::move(solvfile) ]() 
mutable {
 
  819                  guard.resetDispose();
 
  829          | 
and_then([
this, raw_metadata_status](){
 
  831            return _refCtx->repoManager()->setCacheStatus( _refCtx->repoInfo(), raw_metadata_status );
 
  835          MIL << 
"Commit cache.." << std::endl;
 
  840        | 
or_else ( [
this]( std::exception_ptr e ) {
 
  847      MaybeAsyncRef<expected<std::optional<MediaHandle>>> mountIfRequired ( zypp::repo::RepoType repokind, zypp::RepoInfo info  ) {
 
  851        return _refCtx->zyppContext()->provider()->attachMedia( info.
url(), ProvideMediaSpec() )
 
  852        | 
and_then( [
this]( MediaHandle handle ) {
 
  858      RefreshContextRefType _refCtx;
 
  860      ProgressObserverRef   _progressObserver;
 
  862      zypp::Pathname _mediarootpath;
 
  863      zypp::Pathname _productdatapath;
 
  881    template<
typename Executor, 
class OpType>
 
  882    struct AddRepoLogic : 
public LogicBase<Executor, OpType>{
 
  888      AddRepoLogic( RepoManagerPtrType &&repoMgrRef, 
RepoInfo &&info, ProgressObserverRef &&myProgress )
 
  889        : _repoMgrRef( 
std::move(repoMgrRef) )
 
  890        , _info( 
std::move(info) )
 
  891        , _myProgress ( 
std::move(myProgress) )
 
  894      MaybeAsyncRef<expected<RepoInfo> > execute() {
 
  900          MIL << 
"Try adding repo " << _info << std::endl;
 
  904          if ( _repoMgrRef->repos().find(_info) != _repoMgrRef->repos().end() )
 
  908          if ( _repoMgrRef->options().probe )
 
  910            DBG << 
"unknown repository type, probing" << std::endl;
 
  913            | 
and_then([
this]( zypp::repo::RepoType probedtype ) {
 
  926        | 
and_then( [
this]( 
RepoInfo tosave ){ 
return _repoMgrRef->addProbedRepository( tosave, tosave.
type() ); })
 
  929          MIL << 
"done" << std::endl;
 
  932        | 
or_else( [
this]( std::exception_ptr e) {
 
  934          MIL << 
"done" << std::endl;
 
  940      RepoManagerPtrType _repoMgrRef;
 
  942      ProgressObserverRef _myProgress;
 
  958    template<
typename Executor, 
class OpType>
 
  959    struct AddReposLogic : 
public LogicBase<Executor, OpType>{
 
  964      AddReposLogic( RepoManagerPtrType &&repoMgrRef, 
zypp::Url &&
url, ProgressObserverRef &&myProgress )
 
  965        : _repoMgrRef( 
std::move(repoMgrRef) )
 
  967        , _myProgress ( 
std::move(myProgress) )
 
  970      MaybeAsyncRef<expected<void>> execute() {
 
  975        | 
and_then([
this]( std::list<RepoInfo> repos ) {
 
  977          for ( std::list<RepoInfo>::const_iterator it = repos.begin();
 
  982            for_ ( kit, _repoMgrRef->repoBegin(), _repoMgrRef->repoEnd() )
 
  984              if ( (*it).alias() == (*kit).alias() )
 
  986                ERR << 
"To be added repo " << (*it).alias() << 
" conflicts with existing repo " << (*kit).alias() << std::endl;
 
  992          std::string filename = zypp::Pathname(_url.getPathName()).basename();
 
  993          if ( filename == zypp::Pathname() )
 
  999          const auto &options = _repoMgrRef->options();
 
 1004          zypp::Pathname repofile = _repoMgrRef->generateNonExistingName( options.knownReposPath, filename );
 
 1006          MIL << 
"Saving " << repos.size() << 
" repo" << ( repos.size() ? 
"s" : 
"" ) << 
" in " << repofile << std::endl;
 
 1008          std::ofstream file(repofile.
c_str());
 
 1015          for ( std::list<RepoInfo>::iterator it = repos.begin();
 
 1019            MIL << 
"Saving " << (*it).alias() << std::endl;
 
 1027            it->dumpAsIniOn(file);
 
 1028            it->setFilepath(repofile);
 
 1029            it->setMetadataPath( *rawCachePath );
 
 1030            it->setPackagesPath( *pckCachePath );
 
 1031            _repoMgrRef->reposManip().insert(*it);
 
 1033            zypp::HistoryLog( _repoMgrRef->options().rootDir).addRepository(*it);
 
 1036          MIL << 
"done" << std::endl;
 
 1042      RepoManagerPtrType _repoMgrRef;
 
 1044      ProgressObserverRef _myProgress;
 
 1062    template<
typename Executor, 
class OpType>
 
 1063    struct RefreshGeoIpLogic : 
public LogicBase<Executor, OpType>{
 
 1069        using ZyppContextType    = 
typename ZyppContextRefType::element_type;
 
 1070        using ProvideType        = 
typename ZyppContextType::ProvideType;
 
 1071        using MediaHandle        = 
typename ProvideType::MediaHandle;
 
 1072        using ProvideRes         = 
typename ProvideType::Res;
 
 1076          : _zyppCtx( 
std::move(zyppCtx) )
 
 1077          , _urls( 
std::move(urls) )
 
 1080        MaybeAsyncRef<expected<void>> execute() {
 
 1084          if ( !_zyppCtx->config().geoipEnabled() ) {
 
 1085            MIL << 
"GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
 
 1089          std::vector<std::string> hosts;
 
 1090          for ( 
const auto &baseUrl : _urls ) {
 
 1091            const auto &host = baseUrl.getHost();
 
 1092            if ( 
zypp::any_of( _zyppCtx->config().geoipHostnames(), [&host]( 
const auto &elem ){ return ( zypp::str::compareCI( host, elem ) == 0 ); } ) ) {
 
 1093              hosts.push_back( host );
 
 1098          if ( hosts.empty() ) {
 
 1099            MIL << 
"No configured geoip URL found, not updating geoip data" << std::endl;
 
 1103          _geoIPCache = _zyppCtx->config().geoipCachePath();
 
 1106            MIL << 
"Unable to create cache directory for GeoIP." << std::endl;
 
 1110          if ( 
zypp::IamNotRoot() && not zypp::PathInfo(_geoIPCache).userMayRWX() ) {
 
 1111            MIL << 
"No access rights for the GeoIP cache directory." << std::endl;
 
 1120            zypp::PathInfo pi( dir/entry.
name );
 
 1121            auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
 
 1122            if ( age < std::chrono::hours(24) )
 
 1125            MIL << 
"Removing GeoIP file for " << entry.
name << 
" since it's older than 24hrs." << std::endl;
 
 1130          auto firstOfCb = [
this]( std::string hostname ) {
 
 1133            if ( zypp::PathInfo( _geoIPCache / hostname ).isExist() )  {
 
 1134              MIL << 
"Skipping GeoIP request for " << hostname << 
" since a valid cache entry exists." << std::endl;
 
 1138            MIL << 
"Query GeoIP for " << hostname << std::endl;
 
 1145            } 
catch(
const zypp::Exception &e ) {
 
 1147              MIL << 
"Ignoring invalid GeoIP hostname: " << hostname << std::endl;
 
 1152            return _zyppCtx->provider()->attachMedia( url, ProvideMediaSpec() )
 
 1153            | 
and_then( [
this]( MediaHandle provideHdl ) { 
return _zyppCtx->provider()->provide( provideHdl, 
"/geoip", ProvideFileSpec() ); })
 
 1154            | 
inspect_err( [hostname]( 
const std::exception_ptr& ){ 
MIL << 
"Failed to query GeoIP from hostname: " << hostname << std::endl; } )
 
 1155            | 
and_then( [hostname, 
this]( ProvideRes provideRes ) {
 
 1159              constexpr auto writeHostToFile = []( 
const zypp::Pathname &fName, 
const std::string &host ){
 
 1161                out.open( fName.
asString(), std::ios_base::trunc );
 
 1162                if ( out.is_open() ) {
 
 1163                  out << host << std::endl;
 
 1165                  MIL << 
"Failed to create/open GeoIP cache file " << fName << std::endl;
 
 1169              std::string geoipMirror;
 
 1171                zypp::xml::Reader reader( provideRes.
file() );
 
 1172                if ( reader.seekToNode( 1, 
"host" ) ) {
 
 1173                  const auto &str = reader.nodeText().asString();
 
 1181                    MIL << 
"Storing geoIP redirection: " << hostname << 
" -> " << str << std::endl;
 
 1186                  MIL << 
"No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
 
 1188              } 
catch ( 
const zypp::Exception &e ) {
 
 1190                MIL << 
"Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
 
 1193              writeHostToFile( _geoIPCache / hostname, geoipMirror );
 
 1196            | []( expected<void> res ) { 
return res.
is_valid(); };
 
 1199          return std::move(hosts)
 
 1200          | 
firstOf( std::move(firstOfCb), 
false, zyppng::detail::ContinueUntilValidPredicate() )
 
 1201          | []( 
bool foundGeoIP ){
 
 1204              MIL << 
"Successfully queried GeoIP data." << std::endl;
 
 1208            MIL << 
"Failed to query GeoIP data." << std::endl;
 
 1209            return expected<void>::error( std::make_exception_ptr( zypp::Exception(
"No valid geoIP url found" )) );
 
 1215        ZyppContextRefType _zyppCtx;
 
 1217        zypp::Pathname     _geoIPCache;