libzypp 17.35.14
repomanagerwf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "repomanagerwf.h"
10
12
14#include <zypp-core/zyppng/io/Process>
15#include <zypp-core/zyppng/pipelines/MTry>
16#include <zypp-core/zyppng/pipelines/Algorithm>
17#include <zypp-media/MediaException>
18#include <zypp-media/ng/Provide>
19#include <zypp-media/ng/ProvideSpec>
20
22#include <zypp/HistoryLog.h>
23#include <zypp/base/Algorithm.h>
24#include <zypp/ng/Context>
28#include <zypp/ng/repomanager.h>
29
30#include <utility>
31#include <fstream>
32
33#undef ZYPP_BASE_LOGGER_LOGGROUP
34#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
35
37
38 using namespace zyppng::operators;
39
40 namespace {
41
42 template <class Executor, class OpType>
43 struct ProbeRepoLogic : public LogicBase<Executor, OpType>
44 {
45 protected:
46 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
47
48 public:
49 using ZyppContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, ContextRef, SyncContextRef >;
50 using ProvideType = typename remove_smart_ptr_t<ZyppContextRefType>::ProvideType;
51 using MediaHandle = typename ProvideType::MediaHandle;
52 using LazyMediaHandle = typename ProvideType::LazyMediaHandle;
53 using ProvideRes = typename ProvideType::Res;
54
55 ProbeRepoLogic(ZyppContextRefType zyppCtx, LazyMediaHandle &&medium, zypp::Pathname &&path, std::optional<zypp::Pathname> &&targetPath )
56 : _zyppContext(std::move(zyppCtx))
57 , _medium(std::move(medium))
58 , _path(std::move(path))
59 , _targetPath(std::move(targetPath))
60 {}
61
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;
65
66 if ( url.getScheme() == "dir" && ! zypp::PathInfo( url.getPathName()/_path ).isDir() ) {
67 // Handle non existing local directory in advance
68 MIL << "Probed type NONE (not exists) at " << url << " (" << _path << ")" << std::endl;
70 }
71
72 // prepare exception to be thrown if the type could not be determined
73 // due to a media exception. We can't throw right away, because of some
74 // problems with proxy servers returning an incorrect error
75 // on ftp file-not-found(bnc #335906). Instead we'll check another types
76 // before throwing.
77
78 std::shared_ptr<ProvideType> providerRef = _zyppContext->provider();
79
80 // TranslatorExplanation '%s' is an URL
81 _error = zypp::repo::RepoException (zypp::str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
82
83 return providerRef->attachMediaIfNeeded( _medium )
84 | and_then([this, providerRef]( MediaHandle medium )
85 {
86 // first try rpmmd
87 return providerRef->provide( medium, _path/"repodata/repomd.xml", ProvideFileSpec().setCheckExistsOnly( !_targetPath.has_value() ) )
88 | and_then( maybeCopyResultToDest("repodata/repomd.xml") )
90 // try susetags if rpmmd fails and remember the error
91 | or_else( [this, providerRef, medium]( std::exception_ptr err ) {
92 try {
93 std::rethrow_exception (err);
94 } catch ( const zypp::media::MediaFileNotFoundException &e ) {
95 // do nothing
96 ;
97 } catch( const zypp::media::MediaException &e ) {
98 DBG << "problem checking for repodata/repomd.xml file" << std::endl;
99 _error.remember ( err );
100 _gotMediaError = true;
101 } catch( ... ) {
102 // any other error, we give up
104 }
105 return providerRef->provide( medium, _path/"content", ProvideFileSpec().setCheckExistsOnly( !_targetPath.has_value() ) )
106 | and_then( maybeCopyResultToDest("content") )
108 })
109 // no rpmmd and no susetags!
110 | or_else( [this, medium]( std::exception_ptr err ) {
111
112 try {
113 std::rethrow_exception (err);
114 } catch ( const zypp::media::MediaFileNotFoundException &e ) {
115 // do nothing
116 ;
117 } catch( const zypp::media::MediaException &e ) {
118 DBG << "problem checking for content file" << std::endl;
119 _error.remember ( err );
120 _gotMediaError = true;
121 } catch( zypp::Exception &e ) {
122 _error.remember(e);
123 // any other error, we give up
125 } catch(...) {
126 // any other error, we give up
128 }
129
130 const auto &url = medium.baseUrl();
131
132 // if it is a non-downloading URL denoting a directory (bsc#1191286: and no plugin)
133 if ( ! ( url.schemeIsDownloading() || url.schemeIsPlugin() ) ) {
134
135 if ( medium.localPath() && zypp::PathInfo(medium.localPath().value()/_path).isDir() ) {
136 // allow empty dirs for now
137 MIL << "Probed type RPMPLAINDIR at " << url << " (" << _path << ")" << std::endl;
139 }
140 }
141
142 if( _gotMediaError )
144
145 MIL << "Probed type NONE at " << url << " (" << _path << ")" << std::endl;
147 })
148 ;
149 });
150 }
151
152 private:
157 auto maybeCopyResultToDest ( std::string &&subPath ) {
158 return [this, subPath = std::move(subPath)]( ProvideRes file ) -> MaybeAsyncRef<expected<void>> {
159 if ( _targetPath ) {
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)
163 | and_then([]( zypp::ManagedFile file ){ file.resetDispose(); return expected<void>::success(); } );
164 }
166 };
167 }
168
169 private:
170 ZyppContextRefType _zyppContext;
173 std::optional<zypp::Pathname> _targetPath;
174
176 bool _gotMediaError = false;
177 };
178
179 template <class RefreshContextRef>
180 auto probeRepoLogic( RefreshContextRef ctx, RepoInfo repo, std::optional<zypp::Pathname> targetPath)
181 {
182 using namespace zyppng::operators;
183 return ctx->provider()->prepareMedia( repo.url(), zyppng::ProvideMediaSpec() )
184 | and_then( [ctx, path = repo.path() ]( auto &&mediaHandle ) {
185 return probeRepoType( ctx, std::forward<decltype(mediaHandle)>(mediaHandle), path );
186 });
187 }
188 }
189
190 AsyncOpRef<expected<zypp::repo::RepoType> > probeRepoType(ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional<zypp::Pathname> targetPath)
191 {
192 return SimpleExecutor< ProbeRepoLogic, AsyncOp<expected<zypp::repo::RepoType>> >::run( std::move(ctx), std::move(medium), std::move(path), std::move(targetPath) );
193 }
194
195 expected<zypp::repo::RepoType> probeRepoType(SyncContextRef ctx, SyncLazyMediaHandle medium, zypp::Pathname path, std::optional<zypp::Pathname> targetPath )
196 {
197 return SimpleExecutor< ProbeRepoLogic, SyncOp<expected<zypp::repo::RepoType>> >::run( std::move(ctx), std::move(medium), std::move(path), std::move(targetPath) );
198 }
199
200 AsyncOpRef<expected<zypp::repo::RepoType> > probeRepoType( ContextRef ctx, RepoInfo repo, std::optional<zypp::Pathname> targetPath )
201 {
202 return probeRepoLogic( std::move(ctx), std::move(repo), std::move(targetPath) );
203 }
204
205 expected<zypp::repo::RepoType> probeRepoType ( SyncContextRef ctx, RepoInfo repo, std::optional<zypp::Pathname> targetPath )
206 {
207 return probeRepoLogic( std::move(ctx), std::move(repo), std::move(targetPath) );
208 }
209
210
211 namespace {
212 template <class ZyppContextRef>
213 auto readRepoFileLogic( ZyppContextRef ctx, zypp::Url repoFileUrl )
214 {
215 using namespace zyppng::operators;
216 return ctx->provider()->provide( repoFileUrl, ProvideFileSpec() )
217 | and_then([repoFileUrl]( auto local ){
218 DBG << "reading repo file " << repoFileUrl << ", local path: " << local.file() << std::endl;
219 return repositories_in_file( local.file() );
220 });
221 }
222 }
223
225 {
226 return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
227 }
228
229 expected<std::list<RepoInfo> > readRepoFile(SyncContextRef ctx, zypp::Url repoFileUrl)
230 {
231 return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
232 }
233
234 namespace {
235
236 template<typename Executor, class OpType>
237 struct CheckIfToRefreshMetadataLogic : public LogicBase<Executor, OpType> {
238
239 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
240 public:
241
242 using RefreshContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, repo::AsyncRefreshContextRef, repo::SyncRefreshContextRef>;
243 using ZyppContextRefType = typename RefreshContextRefType::element_type::ContextRefType;
244 using ZyppContextType = typename RefreshContextRefType::element_type::ContextType;
245 using ProvideType = typename ZyppContextType::ProvideType;
246 using LazyMediaHandle = typename ProvideType::LazyMediaHandle;
247 using MediaHandle = typename ProvideType::MediaHandle;
248 using ProvideRes = typename ProvideType::Res;
249
250 CheckIfToRefreshMetadataLogic( RefreshContextRefType refCtx, LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
251 : _refreshContext(std::move(refCtx))
252 , _progress(std::move( progressObserver ))
253 , _medium(std::move( medium ))
254 {}
255
256 MaybeAsyncRef<expected<repo::RefreshCheckStatus>> execute( ) {
257
258 MIL << "Going to CheckIfToRefreshMetadata" << std::endl;
259
260 return assert_alias( _refreshContext->repoInfo() )
261 | and_then( [this] {
262
263 const auto &info = _refreshContext->repoInfo();
264 MIL << "Check if to refresh repo " << _refreshContext->repoInfo().alias() << " at " << _medium.baseUrl() << " (" << info.type() << ")" << std::endl;
265
266 // first check old (cached) metadata
268 })
269 | and_then( [this](zypp::RepoStatus oldstatus) {
270
271 const auto &info = _refreshContext->repoInfo();
272
273 if ( oldstatus.empty() ) {
274 MIL << "No cached metadata, going to refresh" << std::endl;
276 }
277
278 if ( _medium.baseUrl().schemeIsVolatile() ) {
279 MIL << "Never refresh CD/DVD" << std::endl;
281 }
282
284 MIL << "Forced refresh!" << std::endl;
286 }
287
288 if ( _medium.baseUrl().schemeIsLocal() ) {
290 }
291
292 // Check whether repo.refresh.delay applies...
294 {
295 // bsc#1174016: Prerequisite to skipping the refresh is that metadata
296 // and solv cache status match. They will not, if the repos URL was
297 // changed e.g. due to changed repovars.
299 if ( !cachestatus ) return makeReadyResult( expected<repo::RefreshCheckStatus>::error(cachestatus.error()) );
300
301 if ( oldstatus == *cachestatus ) {
302 // difference in seconds
303 double diff = ::difftime( (zypp::Date::ValueType)zypp::Date::now(), (zypp::Date::ValueType)oldstatus.timestamp() ) / 60;
304 const auto refDelay = _refreshContext->zyppContext()->config().repo_refresh_delay();
305 if ( diff < refDelay ) {
306 if ( diff < 0 ) {
307 WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << std::endl;
308 }
309 else {
310 MIL << "Repository '" << info.alias()
311 << "' has been refreshed less than repo.refresh.delay ("
312 << refDelay
313 << ") minutes ago. Advising to skip refresh" << std::endl;
315 }
316 }
317 }
318 else {
319 MIL << "Metadata and solv cache don't match. Check data on server..." << std::endl;
320 }
321 }
322
323 return info.type() | [this]( zypp::repo::RepoType repokind ) {
324 // if unknown: probe it
325 if ( repokind == zypp::repo::RepoType::NONE )
326 return probeRepoType( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path()/*, _refreshContext->targetDir()*/ );
328 } | and_then([this, oldstatus]( zypp::repo::RepoType repokind ) {
329
330 // make sure to remember the repo type
331 _refreshContext->repoInfo().setProbedType( repokind );
332
333 auto dlContext = std::make_shared<repo::DownloadContext<ZyppContextRefType>>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
334 return RepoDownloaderWorkflow::repoStatus ( dlContext, _medium )
335 | and_then( [this, dlContext, oldstatus]( zypp::RepoStatus newstatus ){
336 // check status
337 if ( oldstatus == newstatus ) {
338 MIL << "repo has not changed" << std::endl;
341 }
342 else { // includes newstatus.empty() if e.g. repo format changed
343 MIL << "repo has changed, going to refresh" << std::endl;
344 MIL << "Old status: " << oldstatus << " New Status: " << newstatus << std::endl;
346 }
347 });
348 });
349 });
350 }
351
352 protected:
353 RefreshContextRefType _refreshContext;
354 ProgressObserverRef _progress;
356 };
357 }
358
359 AsyncOpRef<expected<repo::RefreshCheckStatus> > checkIfToRefreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle<Provide> medium, ProgressObserverRef progressObserver)
360 {
361 return SimpleExecutor< CheckIfToRefreshMetadataLogic , AsyncOp<expected<repo::RefreshCheckStatus>> >::run( std::move(refCtx), std::move(medium), std::move(progressObserver) );
362 }
363
364 expected<repo::RefreshCheckStatus> checkIfToRefreshMetadata(repo::SyncRefreshContextRef refCtx, LazyMediaHandle<MediaSyncFacade> medium, ProgressObserverRef progressObserver)
365 {
366 return SimpleExecutor< CheckIfToRefreshMetadataLogic , SyncOp<expected<repo::RefreshCheckStatus>> >::run( std::move(refCtx), std::move(medium), std::move(progressObserver) );
367 }
368
369
370 namespace {
371
372 template<typename Executor, class OpType>
373 struct RefreshMetadataLogic : public LogicBase<Executor, OpType>{
374
375 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
376
377 public:
378
379 using RefreshContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, repo::AsyncRefreshContextRef, repo::SyncRefreshContextRef>;
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;
384 using LazyMediaHandle = typename ProvideType::LazyMediaHandle;
385 using ProvideRes = typename ProvideType::Res;
386
387 using DlContextType = repo::DownloadContext<ZyppContextRefType>;
388 using DlContextRefType = std::shared_ptr<DlContextType>;
389
390 RefreshMetadataLogic( RefreshContextRefType refCtx, LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
391 : _refreshContext(std::move(refCtx))
392 , _progress ( std::move( progressObserver ) )
393 , _medium ( std::move( medium ) )
394 { }
395
396 MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
397
398 return assert_alias( _refreshContext->repoInfo() )
399 | and_then( [this](){ return assert_urls( _refreshContext->repoInfo() ); })
400 | and_then( [this](){ return checkIfToRefreshMetadata ( _refreshContext, _medium, _progress ); })
401 | and_then( [this]( repo::RefreshCheckStatus status ){
402
403 MIL << "RefreshCheckStatus returned: " << status << std::endl;
404
405 // check whether to refresh metadata
406 // if the check fails for this url, it throws, so another url will be checked
408 return makeReadyResult ( expected<RefreshContextRefType>::success( std::move(_refreshContext) ) );
409
410 // if REFRESH_NEEDED but we don't have the permission to write the cache, stop here.
411 if ( not zypp::PathInfo(_refreshContext->rawCachePath().dirname()).userMayWX() ) {
412 WAR << "No permision to write cache " << zypp::PathInfo(_refreshContext->rawCachePath().dirname()) << std::endl;
414 return makeReadyResult( expected<RefreshContextRefType>::error( std::move(exception) ) );
415 }
416
417 MIL << "Going to refresh metadata from " << _medium.baseUrl() << std::endl;
418
419 // bsc#1048315: Always re-probe in case of repo format change.
420 // TODO: Would be sufficient to verify the type and re-probe
421 // if verification failed (or type is RepoType::NONE)
422 return probeRepoType ( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path() /*, _refreshContext->targetDir()*/ )
423 | and_then([this]( zypp::repo::RepoType repokind ) {
424
425 auto &info = _refreshContext->repoInfo();
426
427 if ( info.type() != repokind ) {
428 _refreshContext->setProbedType( repokind );
429 // Adjust the probed type in RepoInfo
430 info.setProbedType( repokind ); // lazy init!
431 }
432
433 // no need to continue with an unknown type
434 if ( repokind.toEnum() == zypp::repo::RepoType::NONE_e )
436
437 const zypp::Pathname &mediarootpath = _refreshContext->rawCachePath();
438 if( zypp::filesystem::assert_dir(mediarootpath) ) {
439 auto exception = ZYPP_EXCPT_PTR (zypp::Exception(zypp::str::form( _("Can't create %s"), mediarootpath.c_str() )));
440 return makeReadyResult( expected<DlContextRefType>::error( std::move(exception) ));
441 }
442
443 auto dlContext = std::make_shared<DlContextType>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
444 dlContext->setPluginRepoverification( _refreshContext->pluginRepoverification() );
445
446 return RepoDownloaderWorkflow::download ( dlContext, _medium, _progress );
447
448 })
449 | and_then([this]( DlContextRefType && ) {
450
451 // ok we have the metadata, now exchange
452 // the contents
453 _refreshContext->saveToRawCache();
454 // if ( ! isTmpRepo( info ) )
455 // reposManip(); // remember to trigger appdata refresh
456
457 // we are done.
458 return expected<RefreshContextRefType>::success( std::move(_refreshContext) );
459 });
460 });
461 }
462
463 RefreshContextRefType _refreshContext;
464 ProgressObserverRef _progress;
467
468 };
469 }
470
471 AsyncOpRef<expected<repo::AsyncRefreshContextRef> > refreshMetadata( repo::AsyncRefreshContextRef refCtx, LazyMediaHandle<Provide> medium, ProgressObserverRef progressObserver )
472 {
473 return SimpleExecutor<RefreshMetadataLogic, AsyncOp<expected<repo::AsyncRefreshContextRef>>>::run( std::move(refCtx), std::move(medium), std::move(progressObserver));
474 }
475
476 expected<repo::SyncRefreshContextRef> refreshMetadata( repo::SyncRefreshContextRef refCtx, LazyMediaHandle<MediaSyncFacade> medium, ProgressObserverRef progressObserver )
477 {
478 return SimpleExecutor<RefreshMetadataLogic, SyncOp<expected<repo::SyncRefreshContextRef>>>::run( std::move(refCtx), std::move(medium), std::move(progressObserver));
479 }
480
481 namespace {
482 template <class RefreshContextRef>
483 auto refreshMetadataLogic( RefreshContextRef refCtx, ProgressObserverRef progressObserver)
484 {
485 // small shared helper struct to pass around the exception and to remember that we tried the first URL
486 struct ExHelper
487 {
488 // We will throw this later if no URL checks out fine.
489 // The first exception will be remembered, further exceptions just added to the history.
490 ExHelper( const RepoInfo & info_r )
491 : rexception { info_r, _("Failed to retrieve new repository metadata.") }
492 {}
493 void remember( const zypp::Exception & old_r )
494 {
495 if ( rexception.historyEmpty() ) {
496 rexception.remember( old_r );
497 } else {
498 rexception.addHistory( old_r.asUserString() );
499 }
500 }
501 zypp::repo::RepoException rexception;
502 };
503
504 auto helper = std::make_shared<ExHelper>( ExHelper{ refCtx->repoInfo() } );
505
506 // the actual logic pipeline, attaches the medium and tries to refresh from it
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 ); } );
510 };
511
512 // predicate that accepts only valid results, and in addition collects all errors in rexception
513 auto predicate = [ info = refCtx->repoInfo(), helper ]( const expected<RefreshContextRef> &res ) -> bool{
514 if ( !res ) {
515 try {
516 ZYPP_RETHROW( res.error() );
517 } catch ( const zypp::repo::RepoNoPermissionException &e ) {
518 // We deliver the Exception caught here (no permission to write chache) and give up.
519 ERR << "Giving up..." << std::endl;
520 helper->remember( e );
521 return true; // stop processing
522 } catch ( const zypp::Exception &e ) {
523 ERR << "Trying another url..." << std::endl;
524 helper->remember( e );
525 }
526 return false;
527 }
528 return true;
529 };
530
531 // now go over the urls until we find one that works
532 return refCtx->repoInfo().baseUrls()
533 | firstOf( std::move(refreshPipeline), expected<RefreshContextRef>::error( std::make_exception_ptr(NotFoundException()) ), std::move(predicate) )
534 | [helper]( expected<RefreshContextRef> result ) {
535 if ( !result ) {
536 // none of the URLs worked
537 ERR << "No more urls..." << std::endl;
538 return expected<RefreshContextRef>::error( ZYPP_EXCPT_PTR(helper->rexception) );
539 }
540 // we are done.
541 return result;
542 };
543 }
544 }
545
546 AsyncOpRef<expected<repo::AsyncRefreshContextRef> > refreshMetadata( repo::AsyncRefreshContextRef refCtx, ProgressObserverRef progressObserver) {
547 return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
548 }
549
550 expected<repo::SyncRefreshContextRef> refreshMetadata( repo::SyncRefreshContextRef refCtx, ProgressObserverRef progressObserver) {
551 return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
552 }
553
554
555 namespace {
556
557 template <typename ZyppCtxRef> struct Repo2SolvOp;
558
559 template <>
560 struct Repo2SolvOp<ContextRef> : public AsyncOp<expected<void>>
561 {
562 Repo2SolvOp() { }
563
565 MIL << "Starting repo2solv for repo " << repo.alias () << std::endl;
566 auto me = std::make_shared<Repo2SolvOp<ContextRef>>();
567 me->_repo = std::move(repo);
568 me->_proc = Process::create();
569 me->_proc->connect( &Process::sigFinished, *me, &Repo2SolvOp<ContextRef>::procFinished );
570 me->_proc->connect( &Process::sigReadyRead, *me, &Repo2SolvOp<ContextRef>::readyRead );
571
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);
576 me->_proc->setOutputChannelMode ( Process::Merged );
577 if (!me->_proc->start( argsIn.data() )) {
578 return makeReadyResult( expected<void>::error(ZYPP_EXCPT_PTR(zypp::repo::RepoException ( me->_repo, _("Failed to cache repo ( unable to start repo2solv ).") ))) );
579 }
580 return me;
581 }
582
583 void readyRead (){
584 const ByteArray &data = _proc->readLine();
585 const std::string &line = data.asString();
586 WAR << " " << line;
587 _errdetail += line;
588 }
589
590 void procFinished( int ret ) {
591
592 while ( _proc->canReadLine() )
593 readyRead();
594
595 if ( ret != 0 ) {
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() ); // errdetail lines are NL-terminaled!
598 setReady( expected<void>::error(ZYPP_EXCPT_PTR(ex)) );
599 return;
600 }
601 setReady( expected<void>::success() );
602 }
603
604 private:
605 ProcessRef _proc;
607 std::string _errdetail;
608 };
609
610 template <>
611 struct Repo2SolvOp<SyncContextRef>
612 {
615 std::string errdetail;
616
617 for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
618 WAR << " " << output;
619 errdetail += output;
620 }
621
622 int ret = prog.close();
623 if ( ret != 0 )
624 {
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() ); // errdetail lines are NL-terminaled!
628 }
630 }
631 };
632
633 template<typename Executor, class OpType>
634 struct BuildCacheLogic : public LogicBase<Executor, OpType>{
635
636 using RefreshContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, repo::AsyncRefreshContextRef, repo::SyncRefreshContextRef>;
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;
642
643 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
644
645 BuildCacheLogic( RefreshContextRefType &&refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef &&progressObserver )
646 : _refCtx( std::move(refCtx) )
647 , _policy( policy )
648 , _progressObserver( std::move(progressObserver) )
649 {}
650
651 MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
652
653 ProgressObserver::setup ( _progressObserver, zypp::str::form(_("Building repository '%s' cache"), _refCtx->repoInfo().label().c_str()), 100 );
654
655 return assert_alias(_refCtx->repoInfo() )
656 | and_then( mtry( [this] {
657 _mediarootpath = rawcache_path_for_repoinfo( _refCtx->repoManagerOptions(), _refCtx->repoInfo() ).unwrap();
658 _productdatapath = rawproductdata_path_for_repoinfo( _refCtx->repoManagerOptions(), _refCtx->repoInfo() ).unwrap();
659 }))
660 | and_then( [this] {
661
662 const auto &options = _refCtx->repoManagerOptions();
663
664 if( zypp::filesystem::assert_dir( options.repoCachePath ) ) {
665 auto ex = ZYPP_EXCPT_PTR( zypp::Exception (zypp::str::form( _("Can't create %s"), options.repoCachePath.c_str()) ) );
666 return expected<RepoStatus>::error( std::move(ex) );
667 }
668
669 return RepoManager<ZyppContextRefType>::metadataStatus( _refCtx->repoInfo(), options );
670
671 }) | and_then( [this](RepoStatus raw_metadata_status ) {
672
673 if ( raw_metadata_status.empty() )
674 {
675 // If there is no raw cache at this point, we refresh the raw metadata.
676 // This may happen if no autorefresh is configured and no explicit
677 // refresh was called.
678 //
679 zypp::Pathname mediarootParent { _mediarootpath.dirname() };
680
681 if ( zypp::filesystem::assert_dir( mediarootParent ) == 0
682 && zypp::PathInfo(mediarootParent).userMayWX() ) {
683
684 return refreshMetadata( _refCtx, ProgressObserver::makeSubTask( _progressObserver ) )
685 | and_then([this]( auto /*refCtx*/) { return RepoManager<ZyppContextRefType>::metadataStatus( _refCtx->repoInfo(), _refCtx->repoManagerOptions() ); } );
686
687 } else {
688 // Non-root user is not allowed to write the raw cache.
689 WAR << "No permission to write raw cache " << mediarootParent << std::endl;
690 auto exception = ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refCtx->repoInfo() ) );
691 return makeReadyResult( expected<zypp::RepoStatus>::error( std::move(exception) ) );
692 }
693 }
694 return makeReadyResult( make_expected_success (raw_metadata_status) );
695
696 }) | and_then( [this]( RepoStatus raw_metadata_status ) {
697
698 bool needs_cleaning = false;
699 const auto &info = _refCtx->repoInfo();
700 if ( _refCtx->repoManager()->isCached( info ) )
701 {
702 MIL << info.alias() << " is already cached." << std::endl;
703 expected<RepoStatus> cache_status = RepoManager<ZyppContextRefType>::cacheStatus( info, _refCtx->repoManagerOptions() );
704 if ( !cache_status )
705 return makeReadyResult( expected<void>::error(cache_status.error()) );
706
707 if ( *cache_status == raw_metadata_status )
708 {
709 MIL << info.alias() << " cache is up to date with metadata." << std::endl;
711 {
712 // On the fly add missing solv.idx files for bash completion.
713 return makeReadyResult(
714 solv_path_for_repoinfo( _refCtx->repoManagerOptions(), info)
715 | and_then([this]( zypp::Pathname base ){
716 if ( ! zypp::PathInfo(base/"solv.idx").isExist() )
717 return mtry( zypp::sat::updateSolvFileIndex, base/"solv" );
718 return expected<void>::success ();
719 })
720 );
721 }
722 else {
723 MIL << info.alias() << " cache rebuild is forced" << std::endl;
724 }
725 }
726
727 needs_cleaning = true;
728 }
729
730 ProgressObserver::start( _progressObserver );
731
732 if (needs_cleaning)
733 {
734 auto r = _refCtx->repoManager()->cleanCache(info);
735 if ( !r )
736 return makeReadyResult( expected<void>::error(r.error()) );
737 }
738
739 MIL << info.alias() << " building cache..." << info.type() << std::endl;
740
741 expected<zypp::Pathname> base = solv_path_for_repoinfo( _refCtx->repoManagerOptions(), info);
742 if ( !base )
744
746 {
747 zypp::Exception ex(zypp::str::form( _("Can't create %s"), base->c_str()) );
749 }
750
751 if( ! zypp::PathInfo(*base).userMayW() )
752 {
753 zypp::Exception ex(zypp::str::form( _("Can't create cache at %s - no writing permissions."), base->c_str()) );
755 }
756
757 zypp::Pathname solvfile = *base / "solv";
758
759 // do we have type?
760 zypp::repo::RepoType repokind = info.type();
761
762 // if the type is unknown, try probing.
763 switch ( repokind.toEnum() )
764 {
766 // unknown, probe the local metadata
767 repokind = RepoManager<ZyppContextRefType>::probeCache( _productdatapath );
768 break;
769 default:
770 break;
771 }
772
773 MIL << "repo type is " << repokind << std::endl;
774
775 return mountIfRequired( repokind, info )
776 | and_then([this, repokind, solvfile = std::move(solvfile) ]( std::optional<MediaHandle> forPlainDirs ) mutable {
777
778 const auto &info = _refCtx->repoInfo();
779
780 switch ( repokind.toEnum() )
781 {
785 {
786 // Take care we unlink the solvfile on error
788
790#ifdef ZYPP_REPO2SOLV_PATH
791 cmd.push_back( ZYPP_REPO2SOLV_PATH );
792#else
793 cmd.push_back( zypp::PathInfo( "/usr/bin/repo2solv" ).isFile() ? "repo2solv" : "repo2solv.sh" );
794#endif
795 // repo2solv expects -o as 1st arg!
796 cmd.push_back( "-o" );
797 cmd.push_back( solvfile.asString() );
798 cmd.push_back( "-X" ); // autogenerate pattern from pattern-package
799 // bsc#1104415: no more application support // cmd.push_back( "-A" ); // autogenerate application pseudo packages
800
801 if ( repokind == zypp::repo::RepoType::RPMPLAINDIR )
802 {
803 // recusive for plaindir as 2nd arg!
804 cmd.push_back( "-R" );
805
806 std::optional<zypp::Pathname> localPath = forPlainDirs.has_value() ? forPlainDirs->localPath() : zypp::Pathname();
807 if ( !localPath )
808 return makeReadyResult( expected<void>::error( ZYPP_EXCPT_PTR( zypp::repo::RepoException( zypp::str::Format(_("Failed to cache repo %1%")) % _refCtx->repoInfo() ))) );
809
810 // FIXME this does only work for dir: URLs
811 cmd.push_back( (*localPath / info.path().absolutename()).c_str() );
812 }
813 else
814 cmd.push_back( _productdatapath.asString() );
815
816 return Repo2SolvOp<ZyppContextRefType>::run( info, std::move(cmd) )
817 | and_then( [this, guard = std::move(guard), solvfile = std::move(solvfile) ]() mutable {
818 // We keep it.
819 guard.resetDispose();
820 return mtry( zypp::sat::updateSolvFileIndex, solvfile ); // content digest for zypper bash completion
821 });
822 }
823 break;
824 default:
825 return makeReadyResult( expected<void>::error( ZYPP_EXCPT_PTR(zypp::repo::RepoUnknownTypeException( info, _("Unhandled repository type") )) ) );
826 break;
827 }
828 })
829 | and_then([this, raw_metadata_status](){
830 // update timestamp and checksum
831 return _refCtx->repoManager()->setCacheStatus( _refCtx->repoInfo(), raw_metadata_status );
832 });
833 })
834 | and_then( [this](){
835 MIL << "Commit cache.." << std::endl;
837 return make_expected_success ( _refCtx );
838
839 })
840 | or_else ( [this]( std::exception_ptr e ) {
843 });
844 }
845
846 private:
847 MaybeAsyncRef<expected<std::optional<MediaHandle>>> mountIfRequired ( zypp::repo::RepoType repokind, zypp::RepoInfo info ) {
848 if ( repokind != zypp::repo::RepoType::RPMPLAINDIR )
849 return makeReadyResult( make_expected_success( std::optional<MediaHandle>() ));
850
851 return _refCtx->zyppContext()->provider()->attachMedia( info.url(), ProvideMediaSpec() )
852 | and_then( [this]( MediaHandle handle ) {
853 return makeReadyResult( make_expected_success( std::optional<MediaHandle>( std::move(handle)) ));
854 });
855 }
856
857 private:
858 RefreshContextRefType _refCtx;
860 ProgressObserverRef _progressObserver;
861
864 };
865 }
866
867 AsyncOpRef<expected<repo::AsyncRefreshContextRef> > buildCache(repo::AsyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
868 {
869 return SimpleExecutor<BuildCacheLogic, AsyncOp<expected<repo::AsyncRefreshContextRef>>>::run( std::move(refCtx), policy, std::move(progressObserver));
870 }
871
872 expected<repo::SyncRefreshContextRef> buildCache(repo::SyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
873 {
874 return SimpleExecutor<BuildCacheLogic, SyncOp<expected<repo::SyncRefreshContextRef>>>::run( std::move(refCtx), policy, std::move(progressObserver));
875 }
876
877
878 // Add repository logic
879 namespace {
880
881 template<typename Executor, class OpType>
882 struct AddRepoLogic : public LogicBase<Executor, OpType>{
883
885
886 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
887
888 AddRepoLogic( RepoManagerPtrType &&repoMgrRef, RepoInfo &&info, ProgressObserverRef &&myProgress )
889 : _repoMgrRef( std::move(repoMgrRef) )
890 , _info( std::move(info) )
891 , _myProgress ( std::move(myProgress) )
892 {}
893
894 MaybeAsyncRef<expected<RepoInfo> > execute() {
895 using namespace zyppng::operators;
896
897 return assert_alias(_info)
898 | and_then([this]( ) {
899
900 MIL << "Try adding repo " << _info << std::endl;
901 ProgressObserver::setup( _myProgress, zypp::str::form(_("Adding repository '%s'"), _info.label().c_str()) );
902 ProgressObserver::start( _myProgress );
903
904 if ( _repoMgrRef->repos().find(_info) != _repoMgrRef->repos().end() )
906
907 // check the first url for now
908 if ( _repoMgrRef->options().probe )
909 {
910 DBG << "unknown repository type, probing" << std::endl;
911 return assert_urls(_info)
912 | and_then([this]{ return probeRepoType( _repoMgrRef->zyppContext(), _info ); })
913 | and_then([this]( zypp::repo::RepoType probedtype ) {
914
915 if ( probedtype == zypp::repo::RepoType::NONE )
917
918 RepoInfo tosave = _info;
919 tosave.setType(probedtype);
920 return make_expected_success(tosave);
921 });
922 }
923 return makeReadyResult( make_expected_success(_info) );
924 })
925 | inspect( operators::setProgress( _myProgress, 50 ) )
926 | and_then( [this]( RepoInfo tosave ){ return _repoMgrRef->addProbedRepository( tosave, tosave.type() ); })
927 | and_then( [this]( RepoInfo updated ) {
928 ProgressObserver::finish( _myProgress );
929 MIL << "done" << std::endl;
930 return expected<RepoInfo>::success( updated );
931 })
932 | or_else( [this]( std::exception_ptr e) {
934 MIL << "done" << std::endl;
936 })
937 ;
938 }
939
940 RepoManagerPtrType _repoMgrRef;
942 ProgressObserverRef _myProgress;
943 };
944 };
945
946 AsyncOpRef<expected<RepoInfo> > addRepository( AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress )
947 {
948 return SimpleExecutor<AddRepoLogic, AsyncOp<expected<RepoInfo>>>::run( std::move(mgr), std::move(info), std::move(myProgress) );
949 }
950
951 expected<RepoInfo> addRepository( SyncRepoManagerRef mgr, const RepoInfo &info, ProgressObserverRef myProgress )
952 {
953 return SimpleExecutor<AddRepoLogic, SyncOp<expected<RepoInfo>>>::run( std::move(mgr), RepoInfo(info), std::move(myProgress) );
954 }
955
956 namespace {
957
958 template<typename Executor, class OpType>
959 struct AddReposLogic : public LogicBase<Executor, OpType>{
960
962 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
963
964 AddReposLogic( RepoManagerPtrType &&repoMgrRef, zypp::Url &&url, ProgressObserverRef &&myProgress )
965 : _repoMgrRef( std::move(repoMgrRef) )
966 , _url( std::move(url) )
967 , _myProgress ( std::move(myProgress) )
968 {}
969
970 MaybeAsyncRef<expected<void>> execute() {
971 using namespace zyppng::operators;
972
974 | and_then([this]( zypp::Url repoFileUrl ) { return readRepoFile( _repoMgrRef->zyppContext(), std::move(repoFileUrl) ); } )
975 | and_then([this]( std::list<RepoInfo> repos ) {
976
977 for ( std::list<RepoInfo>::const_iterator it = repos.begin();
978 it != repos.end();
979 ++it )
980 {
981 // look if the alias is in the known repos.
982 for_ ( kit, _repoMgrRef->repoBegin(), _repoMgrRef->repoEnd() )
983 {
984 if ( (*it).alias() == (*kit).alias() )
985 {
986 ERR << "To be added repo " << (*it).alias() << " conflicts with existing repo " << (*kit).alias() << std::endl;
988 }
989 }
990 }
991
992 std::string filename = zypp::Pathname(_url.getPathName()).basename();
993 if ( filename == zypp::Pathname() )
994 {
995 // TranslatorExplanation '%s' is an URL
996 return expected<void>::error(ZYPP_EXCPT_PTR(zypp::repo::RepoException(zypp::str::form( _("Invalid repo file name at '%s'"), _url.asString().c_str() ))));
997 }
998
999 const auto &options = _repoMgrRef->options();
1000
1001 // assert the directory exists
1002 zypp::filesystem::assert_dir( options.knownReposPath );
1003
1004 zypp::Pathname repofile = _repoMgrRef->generateNonExistingName( options.knownReposPath, filename );
1005 // now we have a filename that does not exists
1006 MIL << "Saving " << repos.size() << " repo" << ( repos.size() ? "s" : "" ) << " in " << repofile << std::endl;
1007
1008 std::ofstream file(repofile.c_str());
1009 if (!file)
1010 {
1011 // TranslatorExplanation '%s' is a filename
1012 return expected<void>::error(ZYPP_EXCPT_PTR( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), repofile.c_str() ))));
1013 }
1014
1015 for ( std::list<RepoInfo>::iterator it = repos.begin();
1016 it != repos.end();
1017 ++it )
1018 {
1019 MIL << "Saving " << (*it).alias() << std::endl;
1020
1021 const auto &rawCachePath = rawcache_path_for_repoinfo( options, *it );
1022 if ( !rawCachePath ) return expected<void>::error(rawCachePath.error());
1023
1024 const auto &pckCachePath = packagescache_path_for_repoinfo( options, *it ) ;
1025 if ( !pckCachePath ) return expected<void>::error(pckCachePath.error());
1026
1027 it->dumpAsIniOn(file);
1028 it->setFilepath(repofile);
1029 it->setMetadataPath( *rawCachePath );
1030 it->setPackagesPath( *pckCachePath );
1031 _repoMgrRef->reposManip().insert(*it);
1032
1033 zypp::HistoryLog( _repoMgrRef->options().rootDir).addRepository(*it);
1034 }
1035
1036 MIL << "done" << std::endl;
1037 return expected<void>::success();
1038 });
1039 }
1040
1041 private:
1042 RepoManagerPtrType _repoMgrRef;
1044 ProgressObserverRef _myProgress;
1045 };
1046
1047 }
1048
1049 AsyncOpRef<expected<void>> addRepositories( AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress )
1050 {
1051 return SimpleExecutor<AddReposLogic, AsyncOp<expected<void>>>::run( std::move(mgr), std::move(url), std::move(myProgress) );
1052 }
1053
1054 expected<void> addRepositories( SyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress)
1055 {
1056 return SimpleExecutor<AddReposLogic, SyncOp<expected<void>>>::run( std::move(mgr), std::move(url), std::move(myProgress) );
1057 }
1058
1059
1060 namespace {
1061
1062 template<typename Executor, class OpType>
1063 struct RefreshGeoIpLogic : public LogicBase<Executor, OpType>{
1064 protected:
1065 ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
1066
1067 public:
1068 using ZyppContextRefType = std::conditional_t<zyppng::detail::is_async_op_v<OpType>, ContextRef, SyncContextRef >;
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;
1073
1074
1075 RefreshGeoIpLogic( ZyppContextRefType &&zyppCtx, RepoInfo::url_set &&urls )
1076 : _zyppCtx( std::move(zyppCtx) )
1077 , _urls( std::move(urls) )
1078 { }
1079
1080 MaybeAsyncRef<expected<void>> execute() {
1081
1082 using namespace zyppng::operators;
1083
1084 if ( !_zyppCtx->config().geoipEnabled() ) {
1085 MIL << "GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
1087 }
1088
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 );
1094 break;
1095 }
1096 }
1097
1098 if ( hosts.empty() ) {
1099 MIL << "No configured geoip URL found, not updating geoip data" << std::endl;
1101 }
1102
1103 _geoIPCache = _zyppCtx->config().geoipCachePath();
1104
1105 if ( zypp::filesystem::assert_dir( _geoIPCache ) != 0 ) {
1106 MIL << "Unable to create cache directory for GeoIP." << std::endl;
1108 }
1109
1110 if ( !zypp::PathInfo(_geoIPCache).userMayRWX() ) {
1111 MIL << "No access rights for the GeoIP cache directory." << std::endl;
1113 }
1114
1115 // remove all older cache entries
1116 zypp::filesystem::dirForEachExt( _geoIPCache, []( const zypp::Pathname &dir, const zypp::filesystem::DirEntry &entry ) {
1117 if ( entry.type != zypp::filesystem::FT_FILE )
1118 return true;
1119
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) )
1123 return true;
1124
1125 MIL << "Removing GeoIP file for " << entry.name << " since it's older than 24hrs." << std::endl;
1126 zypp::filesystem::unlink( dir/entry.name );
1127 return true;
1128 });
1129
1130 auto firstOfCb = [this]( std::string hostname ) {
1131
1132 // do not query files that are still there
1133 if ( zypp::PathInfo( _geoIPCache / hostname ).isExist() ) {
1134 MIL << "Skipping GeoIP request for " << hostname << " since a valid cache entry exists." << std::endl;
1135 return makeReadyResult(false);
1136 }
1137
1138 MIL << "Query GeoIP for " << hostname << std::endl;
1139
1140 zypp::Url url;
1141 try {
1142 url.setHost(hostname);
1143 url.setScheme("https");
1144
1145 } catch(const zypp::Exception &e ) {
1146 ZYPP_CAUGHT(e);
1147 MIL << "Ignoring invalid GeoIP hostname: " << hostname << std::endl;
1148 return makeReadyResult(false);
1149 }
1150
1151 // always https ,but attaching makes things easier
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 ) {
1156
1157 // here we got something from the server, we will stop after this hostname and mark the process as success()
1158
1159 constexpr auto writeHostToFile = []( const zypp::Pathname &fName, const std::string &host ){
1160 std::ofstream out;
1161 out.open( fName.asString(), std::ios_base::trunc );
1162 if ( out.is_open() ) {
1163 out << host << std::endl;
1164 } else {
1165 MIL << "Failed to create/open GeoIP cache file " << fName << std::endl;
1166 }
1167 };
1168
1169 std::string geoipMirror;
1170 try {
1171 zypp::xml::Reader reader( provideRes.file() );
1172 if ( reader.seekToNode( 1, "host" ) ) {
1173 const auto &str = reader.nodeText().asString();
1174
1175 // make a dummy URL to ensure the hostname is valid
1176 zypp::Url testUrl;
1177 testUrl.setHost(str);
1178 testUrl.setScheme("https");
1179
1180 if ( testUrl.isValid() ) {
1181 MIL << "Storing geoIP redirection: " << hostname << " -> " << str << std::endl;
1182 geoipMirror = str;
1183 }
1184
1185 } else {
1186 MIL << "No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
1187 }
1188 } catch ( const zypp::Exception &e ) {
1189 ZYPP_CAUGHT(e);
1190 MIL << "Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
1191 }
1192
1193 writeHostToFile( _geoIPCache / hostname, geoipMirror );
1194 return expected<void>::success(); // need to return a expected<> due to and_then requirements
1195 })
1196 | []( expected<void> res ) { return res.is_valid(); };
1197 };
1198
1199 return std::move(hosts)
1200 | firstOf( std::move(firstOfCb), false, zyppng::detail::ContinueUntilValidPredicate() )
1201 | []( bool foundGeoIP ){
1202
1203 if ( foundGeoIP ) {
1204 MIL << "Successfully queried GeoIP data." << std::endl;
1205 return expected<void>::success ();
1206 }
1207
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" )) );
1210
1211 };
1212 }
1213
1214 private:
1215 ZyppContextRefType _zyppCtx;
1218
1219 };
1220 }
1221
1223 {
1224 return SimpleExecutor<RefreshGeoIpLogic, AsyncOp<expected<void>>>::run( std::move(ctx), std::move(urls) );
1225 }
1226
1228 {
1229 return SimpleExecutor<RefreshGeoIpLogic, SyncOp<expected<void>>>::run( std::move(ctx), std::move(urls) );
1230 }
1231
1232
1233
1234}
Predicate predicate
Definition PoolQuery.cc:314
void resetDispose()
Set no dispose function.
std::string asString() const
Definition ByteArray.h:24
time_t ValueType
Definition Date.h:38
static Date now()
Return the current time.
Definition Date.h:78
Base class for Exception.
Definition Exception.h:147
std::string asUserString() const
Translated error message as string suitable for the user.
Definition Exception.cc:118
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition Exception.cc:176
void remember(const Exception &old_r)
Store an other Exception as history.
Definition Exception.cc:141
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
int close() override
Wait for the progamm to complete.
const std::string & command() const
The command we're executing.
std::vector< std::string > Arguments
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
Writing the zypp history file.
Definition HistoryLog.h:57
void addRepository(const RepoInfo &repo)
Log a newly added repository.
What is known about a repository.
Definition RepoInfo.h:72
repo::RepoType type() const
Type of repository,.
Definition RepoInfo.cc:602
Url url() const
Pars pro toto: The first repository url.
Definition RepoInfo.h:136
Pathname path() const
Repository path.
Definition RepoInfo.cc:635
void setType(const repo::RepoType &t)
set the repository type
Definition RepoInfo.cc:568
std::list< Url > url_set
Definition RepoInfo.h:108
Track changing files or directories.
Definition RepoStatus.h:41
Date timestamp() const
The time the data were changed the last time.
bool empty() const
Whether the status is empty (empty checksum)
Url manipulation class.
Definition Url.h:92
std::string asString() const
Returns a default string representation of the Url object.
Definition Url.cc:501
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition Url.cc:608
void setHost(const std::string &host)
Set the hostname or IP in the URL authority.
Definition Url.cc:752
bool isValid() const
Verifies the Url.
Definition Url.cc:493
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition Url.cc:672
std::string receiveLine()
Read one line from the input stream.
Wrapper class for stat/lstat.
Definition PathInfo.h:222
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:126
const char * c_str() const
String representation.
Definition Pathname.h:112
const std::string & asString() const
String representation.
Definition Pathname.h:93
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
Just inherits Exception to separate media exceptions.
Repository already exists and some unique attribute can't be duplicated.
Exception for repository handling.
std::string alias() const
unique identifier for this source.
thrown if the user has no permission to update(write) the caches.
thrown when it was impossible to determine this repo type.
xmlTextReader based interface to iterate xml streams.
Definition Reader.h:96
SignalProxy< void()> sigReadyRead()
Definition iodevice.cc:368
static Ptr create()
Definition process.cpp:49
SignalProxy< void(int)> sigFinished()
Definition process.cpp:294
static ProgressObserverRef makeSubTask(ProgressObserverRef parentProgress, float weight=1.0, const std::string &label=std::string(), int steps=100)
static void setup(ProgressObserverRef progress, const std::string &label=std::string(), int steps=100)
static void finish(ProgressObserverRef progress, ProgressObserver::FinishResult result=ProgressObserver::Success)
A ProvideRes object is a reference counted ownership of a resource in the cache provided by a Provide...
Definition provideres.h:36
const zypp::Pathname file() const
Definition provideres.cc:21
expected< RepoStatus > cacheStatus(const RepoInfo &info) const
static expected< void > touchIndexFile(const RepoInfo &info, const RepoManagerOptions &options)
static zypp::repo::RepoType probeCache(const zypp::Pathname &path_r)
Probe Metadata in a local cache directory.
static expected< RepoStatus > metadataStatus(const RepoInfo &info, const RepoManagerOptions &options)
static expected success(ConsParams &&...params)
Definition expected.h:115
static expected error(ConsParams &&...params)
Definition expected.h:126
bool is_valid() const
Definition expected.h:141
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition Arch.h:364
typename conditional< B, T, F >::type conditional_t
Definition TypeTraits.h:39
String related utilities and Regular expression matching.
RefreshCheckStatus
Possibly return state of RepoManager::checkIfToRefreshMetadata function.
@ REFRESH_NEEDED
refresh is needed
@ REPO_UP_TO_DATE
repository not changed
@ REPO_CHECK_DELAYED
refresh is delayed due to settings
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:324
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition PathInfo.cc:598
void updateSolvFileIndex(const Pathname &solvfile_r)
Create solv file content digest for zypper bash completion.
Definition Pool.cc:286
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:37
bool any_of(const Container &c, Fnc &&cb)
Definition Algorithm.h:76
AsyncOpRef< expected< repo::AsyncDownloadContextRef > > download(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver=nullptr)
AsyncOpRef< expected< zypp::RepoStatus > > repoStatus(repo::AsyncDownloadContextRef dl, ProvideMediaHandle mediaHandle)
AsyncOpRef< expected< zypp::repo::RepoType > > probeRepoType(ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional< zypp::Pathname > targetPath)
AsyncOpRef< expected< RepoInfo > > addRepository(AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress)
AsyncOpRef< expected< repo::RefreshCheckStatus > > checkIfToRefreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
AsyncOpRef< expected< std::list< RepoInfo > > > readRepoFile(ContextRef ctx, zypp::Url repoFileUrl)
AsyncOpRef< expected< void > > refreshGeoIPData(ContextRef ctx, RepoInfo::url_set urls)
AsyncOpRef< expected< void > > addRepositories(AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress)
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > refreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > buildCache(repo::AsyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
auto or_else(Fun &&function)
Definition expected.h:630
auto and_then(Fun &&function)
Definition expected.h:623
auto setProgress(ProgressObserverRef progressObserver, double progrValue, std::optional< std::string > newStr={})
auto inspect_err(Fun &&function)
Definition expected.h:644
auto inspect(Fun &&function)
Definition expected.h:637
auto mtry(Fun &&function)
Definition mtry.h:58
expected< void > assert_urls(const RepoInfo &info)
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition asyncop.h:297
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition asyncop.h:255
typename remove_smart_ptr< T >::type remove_smart_ptr_t
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:397
expected< zypp::Pathname > rawcache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw cache path for a repository, this is usually /var/cache/zypp/alias.
expected< void > assert_alias(const RepoInfo &info)
Definition repomanager.h:57
auto firstOf(Transformation &&transformFunc, DefaultType &&def, Predicate &&predicate=detail::ContinueUntilValidPredicate())
Definition algorithm.h:149
RepoManagerRef< SyncContextRef > SyncRepoManagerRef
Definition repomanager.h:48
expected< zypp::Pathname > solv_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the solv cache path for a repository.
zypp::RepoInfo RepoInfo
Definition repomanager.h:36
expected< std::list< RepoInfo > > repositories_in_file(const zypp::Pathname &file)
Reads RepoInfo's from a repo file.
RepoManagerRef< ContextRef > AsyncRepoManagerRef
Definition repomanager.h:51
expected< zypp::Pathname > packagescache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the packages cache path for a repository.
expected< zypp::Pathname > rawproductdata_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw product metadata path for a repository, this is inside the raw cache dir,...
RepoManagerPtrType _repoMgrRef
std::string _errdetail
zypp::Pathname _path
ZyppContextRefType _zyppContext
zypp::Url _url
RepoInfo _info
RepoInfo::url_set _urls
std::optional< zypp::Pathname > _targetPath
zypp::RepoInfo _repo
zypp::Pathname _productdatapath
RefreshContextRefType _refreshContext
zypp::Pathname _geoIPCache
zypp::repo::RepoException _error
zypp::RepoManagerFlags::CacheBuildPolicy _policy
ProgressObserverRef _progress
ProcessRef _proc
RefreshContextRefType _refCtx
ZyppContextRefType _zyppCtx
bool _gotMediaError
ProgressObserverRef _myProgress
LazyMediaHandle _medium
zypp::Pathname _mediarootpath
ProgressObserverRef _progressObserver
Listentry returned by readdir.
Definition PathInfo.h:502
Repository type enumeration.
Definition RepoType.h:29
static const RepoType YAST2
Definition RepoType.h:31
Type toEnum() const
Definition RepoType.h:49
static const RepoType RPMMD
Definition RepoType.h:30
static const RepoType NONE
Definition RepoType.h:33
static const RepoType RPMPLAINDIR
Definition RepoType.h:32
Functor replacing repository variables.
Convenient building of std::string with boost::format.
Definition String.h:253
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:212
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:28
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition Exception.h:444
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:440
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:428
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:436
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101