libzypp 17.38.3
serviceswf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "serviceswf.h"
10
11
15#include <zypp-core/ng/pipelines/MTry>
16#include <zypp-core/ng/io/Process>
21#include <zypp/Target.h>
23
24#include <zypp/ng/Context>
26
27
28#undef ZYPP_BASE_LOGGER_LOGGROUP
29#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
30
32
33 using namespace zyppng::operators;
34
35
36 namespace {
37
38 zypp::Url adaptServiceUrlToChroot( zypp::Url serviceUrl, zypp::Pathname root ) {
39 // if file:// or dir:// path we must prefix with the root_r
40 const auto &scheme = serviceUrl.getScheme();
41 if ( !root.empty() && (scheme == "dir" || scheme == "file") ) {
42 serviceUrl.setPathName ( root / zypp::Pathname(serviceUrl.getPathName()) );
43 }
44 return serviceUrl;
45 }
46
47 struct FetchRIMServiceLogic
48 {
49 public:
50 FetchRIMServiceLogic( ContextRef &&ctx, zypp::Pathname &&root_r, ServiceInfo &&service, ProgressObserverRef &&myProgress )
51 : _ctx( std::move(ctx) )
52 , _root_r( std::move(root_r) )
53 , _service( std::move(service) )
54 , _myProgress( std::move(myProgress) )
55 {}
56
57
58 MaybeAwaitable<expected< std::pair<zypp::ServiceInfo, RepoInfoList> >> execute() {
59
60 using namespace zyppng::operators;
61
62 return zyppng::mtry( [this]{
63 // repoindex.xml must be fetched always without using cookies (bnc #573897)
64 zypp::Url serviceUrl = _service.url();
65 serviceUrl.setQueryParam( "cookies", "0" );
66 return adaptServiceUrlToChroot( serviceUrl, _root_r );
67 })
68 | and_then( [this]( zypp::Url serviceUrl ){ return _ctx->provider()->attachMedia( serviceUrl, ProvideMediaSpec() ); })
69 | and_then( [this]( auto mediaHandle ) { return _ctx->provider()->provide( mediaHandle, "repo/repoindex.xml", ProvideFileSpec() ); } )
70 | and_then( [this]( auto provideResult ) {
71 try {
72
73 zypp::RepoInfoList repos;
74 auto callback = [&]( const zypp::RepoInfo &r) { repos.push_back(r); return true; };
75
76 zypp::parser::RepoindexFileReader reader( provideResult.file(), callback);
77 _service.setProbedTtl( reader.ttl() ); // hack! Modifying the const Service to set parsed TTL
78
79 return make_expected_success( std::make_pair( _service, std::move(repos) ) );
80
81 } catch ( const zypp::Exception &e ) {
82 //Reader throws a bare exception, we need to translate it into something our calling
83 //code expects and handles (bnc#1116840)
84 ZYPP_CAUGHT ( e );
86 ex.remember( e );
88 }
89 });
90 }
91
92 private:
93 ContextRef _ctx;
94 zypp::Pathname _root_r;
95 ServiceInfo _service;
96 ProgressObserverRef _myProgress;
97 };
98
99 struct FetchPluginServiceLogic
100 {
101 public:
103
104 FetchPluginServiceLogic( ContextRef &&ctx, zypp::Pathname &&root_r, ServiceInfo &&service, ProgressObserverRef &&myProgress )
105 : _ctx( std::move(ctx) )
106 , _root_r( std::move(root_r) )
107 , _service( std::move(service) )
108 , _myProgress( std::move(myProgress) )
109 {}
110
111
112 MaybeAwaitable<Ret> execute() {
113 using namespace zyppng::operators;
114
115 // bsc#1080693: Service script needs to be executed chrooted to the RepoManagers rootDir.
116 // The service is not aware of the rootDir, so it's explicitly passed and needs to be
117 // stripped from the URLs path.
118 auto stripped = zypp::Pathname::stripprefix( _root_r, _service.url().getPathName() ).asString();
119
120 return runPlugin( std::move(stripped) )
121 | and_then( [this]( int exitCode ) {
122
123 if ( exitCode != 0 ) {
124 // ServicePluginInformalException:
125 // Ignore this error but we'd like to report it somehow...
126 ERR << "Capture plugin error:[" << std::endl << _stderrBuf << std::endl << ']' << std::endl;
127 return Ret::error( ZYPP_EXCPT_PTR( zypp::repo::ServicePluginInformalException( _service, _stderrBuf ) ) );
128 }
129
130 try {
131 zypp::RepoInfoList repos;
132 auto callback = [&]( const zypp::RepoInfo &r) { repos.push_back(r); return true; };
133
134 std::stringstream buffer( _stdoutBuf );
136 return make_expected_success( std::make_pair( _service, std::move(repos) ) );
137
138 } catch (...) {
139 return Ret::error( std::current_exception () );
140 }
141 });
142 }
143 private:
144
145#ifdef ZYPP_ENABLE_ASYNC
146 AsyncOpRef<expected<int>> runPlugin( std::string command ) {
147 using namespace zyppng::operators;
148
149 const char *args[] = {
150 "/bin/sh",
151 "-c",
152 command.c_str(),
153 nullptr
154 };
155
156 auto pluginProcess = Process::create();
157 pluginProcess->setChroot ( _root_r );
158
159 // make sure our process is actually running, if not finalize right away
160 if ( !pluginProcess->start( args ) || !pluginProcess->isRunning () ) {
161 return makeReadyTask ( finalize( std::move(pluginProcess) ) );
162 }
163
164 co_return co_await ( std::move(pluginProcess)
165 | await<Process>( &Process::sigFinished ) // wait for finished sig
166 | [this]( ProcessRef proc ) { return finalize( std::move(proc) ); } );
167 }
168
169 expected<int> finalize( ProcessRef proc ) {
170 if ( proc->isRunning () ) {
171 proc->stop ( SIGKILL );
172 return expected<int>::error( ZYPP_EXCPT_PTR( zypp::Exception("Bug, plugin process was still running after receiving sigFinished")) );
173 }
174
175 _stdoutBuf = proc->readAll( Process::StdOut ).asString();
176 if ( proc->exitStatus() != 0 ) {
177 _stderrBuf = proc->readAll( Process::StdErr ).asString();
178 }
179
180 return make_expected_success ( proc->exitStatus () );
181 }
182#else
183 expected<int> runPlugin( std::string command ) {
184 try {
185 std::stringstream buffer;
186
188 args.reserve( 3 );
189 args.push_back( "/bin/sh" );
190 args.push_back( "-c" );
191 args.push_back( command );
192
193 zypp::ExternalProgramWithStderr prog( args, _root_r );
194 prog >> buffer;
195 _stdoutBuf = buffer.str();
196
197 int retCode = prog.close();
198 if ( retCode != 0 ) {
199 // ServicePluginInformalException:
200 // Ignore this error but we'd like to report it somehow...
201 prog.stderrGetUpTo( _stderrBuf, '\0' );
202 }
203 return make_expected_success(retCode);
204 } catch ( ... ) {
206 }
207 }
208#endif
209
210
211 ContextRef _ctx;
212 zypp::Pathname _root_r;
213 ServiceInfo _service;
214 ProgressObserverRef _myProgress;
215 std::string _stdoutBuf;
216 std::string _stderrBuf;
217 };
218 }
219
220 MaybeAwaitable<expected<std::pair<zypp::ServiceInfo, RepoInfoList>>> fetchRepoListfromService( ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress )
221 {
222 if ( service.type() == zypp::repo::ServiceType::PLUGIN ) {
223 FetchPluginServiceLogic impl( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) );
224 zypp_co_return zypp_co_await( impl.execute() );
225 } else {
226 FetchRIMServiceLogic impl( std::move(ctx), std::move(root_r), std::move(service), std::move(myProgress) );
227 zypp_co_return zypp_co_await( impl.execute() );
228 }
229 }
230
231 MaybeAwaitable<expected<zypp::repo::ServiceType> > probeServiceType(ContextRef ctx, const zypp::Url &url)
232 {
233 using MediaHandle = ProvideMediaHandle;
235
236 return ctx->provider()->attachMedia( url, ProvideMediaSpec() )
237 | and_then( [ctx]( MediaHandle medium ) { return ctx->provider()->provide( medium, "/repo/repoindex.xml", ProvideFileSpec().setCheckExistsOnly()); } )
238 | [url]( expected<ProvideRes> result ) {
239 if ( result )
240 return expected<zypp::repo::ServiceType>::success( zypp::repo::ServiceType::RIS );
241
242 try{
243 std::rethrow_exception( result.error() );
244 } catch ( const zypp::media::MediaFileNotFoundException &e ) {
245 // fall through
246 } catch ( const zypp::media::MediaException &e ) {
247 ZYPP_CAUGHT(e);
248 // TranslatorExplanation '%s' is an URL
249 zypp::repo::RepoException enew(zypp::str::form( _("Error trying to read from '%s'"), url.asString().c_str() ));
250 enew.remember(e);
252 }
253 catch ( const zypp::Exception &e ) {
254 ZYPP_CAUGHT(e);
255 // TranslatorExplanation '%s' is an URL
256 zypp::Exception enew(zypp::str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
257 enew.remember(e);
259 }
260 catch ( ... ) {
261 // TranslatorExplanation '%s' is an URL
262 zypp::Exception enew(zypp::str::form( _("Unknown error reading from '%s'"), url.asString().c_str() ));
263 enew.remember( std::current_exception() );
265 }
266
267 return expected<zypp::repo::ServiceType>::success( zypp::repo::ServiceType::NONE );
268 };
269 }
270
271 namespace {
272
273 struct RefreshServiceLogic
274 {
275 public:
276 using Ret = expected<void>;
277
278 RefreshServiceLogic( RepoManagerRef &&repoMgr, zypp::ServiceInfo &&info, RepoManager::RefreshServiceOptions options )
279 : _repoMgr( std::move(repoMgr) )
280 , _service( std::move(info) )
281 , _options(options)
282 { }
283
284 MaybeAwaitable<expected<void>> probeServiceIfNeeded() {
285 // if the type is unknown, try probing.
286 if ( _service.type() == zypp::repo::ServiceType::NONE ) {
287
288 return probeServiceType( _repoMgr->zyppContext(), adaptServiceUrlToChroot( _service.url(), _repoMgr->options().rootDir ) )
289 | and_then( [this]( zypp::repo::ServiceType type ){
290 _service.setProbedType( type ); // lazy init!
291 _serviceModified = true;
293 } );
294
295 }
296 return makeReadyTask( expected<void>::success() );
297 }
298
299 MaybeAwaitable<Ret> execute() {
300
301 try {
302 assert_alias( _service ).unwrap();
303 assert_url( _service ).unwrap();
304 } catch (...) {
305 return makeReadyTask(Ret::error(ZYPP_FWD_CURRENT_EXCPT()));
306 }
307
308 MIL << "Going to refresh service '" << _service.alias() << "', url: " << _service.url() << ", opts: " << _options << std::endl;
309
310 if ( _service.ttl() && !( _options.testFlag( zypp::RepoManagerFlags::RefreshService_forceRefresh) || _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) ) )
311 {
312 // Service defines a TTL; maybe we can re-use existing data without refresh.
313 zypp::Date lrf = _service.lrf();
314 if ( lrf )
315 {
316 zypp::Date now( zypp::Date::now() );
317 if ( lrf <= now )
318 {
319 if ( (lrf+=_service.ttl()) > now ) // lrf+= !
320 {
321 MIL << "Skip: '" << _service.alias() << "' metadata valid until " << lrf << std::endl;
322 return makeReadyTask( Ret::success() );
323 }
324 }
325 else
326 WAR << "Force: '" << _service.alias() << "' metadata last refresh in the future: " << lrf << std::endl;
327 }
328 }
329
331
332 return probeServiceIfNeeded () // if the type is unknown, try probing.
333 | and_then( [this]() {
334 // FIXME bsc#1080693: Shortcoming of (plugin)services (and repos as well) is that they
335 // are not aware of the RepoManagers rootDir. The service url, as created in known_services,
336 // contains the full path to the script. The script however has to be executed chrooted.
337 // Repos would need to know the RepoMangers rootDir to use the correct vars.d to replace
338 // repos variables. Until RepoInfoBase is aware if the rootDir, we need to explicitly pass it
339 // to ServiceRepos.
340 return fetchRepoListfromService( _repoMgr->zyppContext(), _repoMgr->options().rootDir, _service, nullptr );
341 } )
342 | [this]( expected<std::pair<zypp::ServiceInfo, RepoInfoList>> serviceReposExp ) {
343
344 if ( !serviceReposExp ) {
345 try {
346 std::rethrow_exception( serviceReposExp.error() );
347
348 } catch ( const zypp::repo::ServicePluginInformalException & e ) {
349 /* ignore ServicePluginInformalException and throw later */
350 _informalError = e;
351 } catch ( ... ) {
352 // all other errors cancel the operation
354 }
355 }
356
357 std::pair<zypp::ServiceInfo, RepoInfoList> serviceRepos = serviceReposExp.is_valid() ? std::move( serviceReposExp.get() ) : std::make_pair( _service, RepoInfoList{} );
358
359 // get target distro identifier
360 std::string servicesTargetDistro = _repoMgr->options().servicesTargetDistro;
361 if ( servicesTargetDistro.empty() ) {
362 servicesTargetDistro = zypp::Target::targetDistribution( zypp::Pathname() );
363 }
364 DBG << "ServicesTargetDistro: " << servicesTargetDistro << std::endl;
365
366 // filter repos by target distro
367 RepoCollector collector( servicesTargetDistro );
368 std::for_each( serviceRepos.second.begin(), serviceRepos.second.end(), [&]( const auto &r ){ collector.collect(r); } );
369
370 if ( _service.ttl () != serviceRepos.first.ttl () ) {
371 // repoindex.xml changed ttl
372 if ( !serviceRepos.first.ttl() )
373 serviceRepos.first.setLrf( zypp::Date() ); // don't need lrf when zero ttl
374
375 _serviceModified = true;
376 }
377
378 // service was maybe updated
379 _service = serviceRepos.first;
380
382 // On the fly remember the new repo states as defined the reopoindex.xml.
383 // Move into ServiceInfo later.
384 ServiceInfo::RepoStates newRepoStates;
385
386 // set service alias and base url for all collected repositories
387 for_( it, collector.repos.begin(), collector.repos.end() )
388 {
389 // First of all: Prepend service alias:
390 it->setAlias( zypp::str::form( "%s:%s", _service.alias().c_str(), it->alias().c_str() ) );
391 // set reference to the parent service
392 it->setService( _service.alias() );
393
394 // remember the new parsed repo state
395 newRepoStates[it->alias()] = *it;
396
397 // - If the repo url was not set by the repoindex parser, set service's url.
398 // - Libzypp currently has problem with separate url + path handling so just
399 // append a path, if set, to the baseurls
400 // - Credentials in the url authority will be extracted later, either if the
401 // repository is added or if we check for changed urls.
402 zypp::Pathname path;
403 if ( !it->path().empty() )
404 {
405 if ( it->path() != "/" )
406 path = it->path();
407 it->setPath("");
408 }
409
410 if ( it->baseUrlsEmpty() )
411 {
412 zypp::Url url( _service.rawUrl() );
413 if ( !path.empty() )
414 url.setPathName( url.getPathName() / path );
415 it->setBaseUrl( std::move(url) );
416 }
417 else if ( !path.empty() )
418 {
419 RepoInfo::url_set urls( it->rawBaseUrls() );
420 for ( zypp::Url & url : urls )
421 {
422 url.setPathName( url.getPathName() / path );
423 }
424 it->setBaseUrls( std::move(urls) );
425 }
426 }
427
429 // Now compare collected repos with the ones in the system...
430 //
431 RepoInfoList oldRepos;
432 _repoMgr->getRepositoriesInService( _service.alias(), std::back_inserter( oldRepos ) );
433
435 // find old repositories to remove...
436 for_( oldRepo, oldRepos.begin(), oldRepos.end() )
437 {
438 if ( ! foundAliasIn( oldRepo->alias(), collector.repos ) )
439 {
440 if ( oldRepo->enabled() )
441 {
442 // Currently enabled. If this was a user modification remember the state.
443 const auto & last = _service.repoStates().find( oldRepo->alias() );
444 if ( last != _service.repoStates().end() && ! last->second.enabled )
445 {
446 DBG << "Service removes user enabled repo " << oldRepo->alias() << std::endl;
447 _service.addRepoToEnable( oldRepo->alias() );
448 _serviceModified = true;
449 }
450 else
451 DBG << "Service removes enabled repo " << oldRepo->alias() << std::endl;
452 }
453 else
454 DBG << "Service removes disabled repo " << oldRepo->alias() << std::endl;
455
456 auto remRes = _repoMgr->removeRepository( *oldRepo );
457 if ( !remRes ) return Ret::error( remRes.error() );
458 }
459 }
460
461
463 // create missing repositories and modify existing ones if needed...
464 zypp::UrlCredentialExtractor urlCredentialExtractor( _repoMgr->options().rootDir ); // To collect any credentials stored in repo URLs
465 for_( it, collector.repos.begin(), collector.repos.end() )
466 {
467 // User explicitly requested the repo being enabled?
468 // User explicitly requested the repo being disabled?
469 // And hopefully not both ;) If so, enable wins.
470
471 zypp::TriBool toBeEnabled( zypp::indeterminate ); // indeterminate - follow the service request
472 DBG << "Service request to " << (it->enabled()?"enable":"disable") << " service repo " << it->alias() << std::endl;
473
475 {
476 DBG << "Opt RefreshService_restoreStatus " << it->alias() << std::endl;
477 // this overrides any pending request!
478 // Remove from enable request list.
479 // NOTE: repoToDisable is handled differently.
480 // It gets cleared on each refresh.
481 _service.delRepoToEnable( it->alias() );
482 // toBeEnabled stays indeterminate!
483 }
484 else
485 {
486 if ( _service.repoToEnableFind( it->alias() ) )
487 {
488 DBG << "User request to enable service repo " << it->alias() << std::endl;
489 toBeEnabled = true;
490 // Remove from enable request list.
491 // NOTE: repoToDisable is handled differently.
492 // It gets cleared on each refresh.
493 _service.delRepoToEnable( it->alias() );
494 _serviceModified = true;
495 }
496 else if ( _service.repoToDisableFind( it->alias() ) )
497 {
498 DBG << "User request to disable service repo " << it->alias() << std::endl;
499 toBeEnabled = false;
500 }
501 }
502
503 RepoInfoList::iterator oldRepo( findAlias( it->alias(), oldRepos ) );
504 if ( oldRepo == oldRepos.end() )
505 {
506 // Not found in oldRepos ==> a new repo to add
507
508 // Make sure the service repo is created with the appropriate enablement
509 if ( ! indeterminate(toBeEnabled) )
510 it->setEnabled( ( bool ) toBeEnabled );
511
512 DBG << "Service adds repo " << it->alias() << " " << (it->enabled()?"enabled":"disabled") << std::endl;
513 const auto &addRes = _repoMgr->addRepository( *it );
514 if (!addRes) return Ret::error( addRes.error() );
515 }
516 else
517 {
518 // ==> an exising repo to check
519 bool oldRepoModified = false;
520
521 if ( indeterminate(toBeEnabled) )
522 {
523 // No user request: check for an old user modificaton otherwise follow service request.
524 // NOTE: Assert toBeEnabled is boolean afterwards!
525 if ( oldRepo->enabled() == it->enabled() )
526 toBeEnabled = it->enabled(); // service requests no change to the system
527 else if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) )
528 {
529 toBeEnabled = it->enabled(); // RefreshService_restoreStatus forced
530 DBG << "Opt RefreshService_restoreStatus " << it->alias() << " forces " << (toBeEnabled?"enabled":"disabled") << std::endl;
531 }
532 else
533 {
534 const auto & last = _service.repoStates().find( oldRepo->alias() );
535 if ( last == _service.repoStates().end() || last->second.enabled != it->enabled() )
536 toBeEnabled = it->enabled(); // service request has changed since last refresh -> follow
537 else
538 {
539 toBeEnabled = oldRepo->enabled(); // service request unchaned since last refresh -> keep user modification
540 DBG << "User modified service repo " << it->alias() << " may stay " << (toBeEnabled?"enabled":"disabled") << std::endl;
541 }
542 }
543 }
544
545 // changed enable?
546 if ( toBeEnabled == oldRepo->enabled() )
547 {
548 DBG << "Service repo " << it->alias() << " stays " << (oldRepo->enabled()?"enabled":"disabled") << std::endl;
549 }
550 else if ( toBeEnabled )
551 {
552 DBG << "Service repo " << it->alias() << " gets enabled" << std::endl;
553 oldRepo->setEnabled( true );
554 oldRepoModified = true;
555 }
556 else
557 {
558 DBG << "Service repo " << it->alias() << " gets disabled" << std::endl;
559 oldRepo->setEnabled( false );
560 oldRepoModified = true;
561 }
562
563 // all other attributes follow the service request:
564
565 // changed name (raw!)
566 if ( oldRepo->rawName() != it->rawName() )
567 {
568 DBG << "Service repo " << it->alias() << " gets new NAME " << it->rawName() << std::endl;
569 oldRepo->setName( it->rawName() );
570 oldRepoModified = true;
571 }
572
573 // changed autorefresh
574 if ( oldRepo->autorefresh() != it->autorefresh() )
575 {
576 DBG << "Service repo " << it->alias() << " gets new AUTOREFRESH " << it->autorefresh() << std::endl;
577 oldRepo->setAutorefresh( it->autorefresh() );
578 oldRepoModified = true;
579 }
580
581 // changed priority?
582 if ( oldRepo->priority() != it->priority() )
583 {
584 DBG << "Service repo " << it->alias() << " gets new PRIORITY " << it->priority() << std::endl;
585 oldRepo->setPriority( it->priority() );
586 oldRepoModified = true;
587 }
588
589 // changed url?
590 {
591 RepoInfo::url_set newUrls( it->rawBaseUrls() );
592 urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below
593 if ( oldRepo->rawBaseUrls() != newUrls )
594 {
595 DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << std::endl;
596 oldRepo->setBaseUrls( std::move(newUrls) );
597 oldRepoModified = true;
598 }
599 }
600
601 // changed gpg check settings?
602 // ATM only plugin services can set GPG values.
603 if ( _service.type() == zypp::repo::ServiceType::PLUGIN )
604 {
605 zypp::TriBool ogpg[3]; // Gpg RepoGpg PkgGpg
606 zypp::TriBool ngpg[3];
607 oldRepo->getRawGpgChecks( ogpg[0], ogpg[1], ogpg[2] );
608 it-> getRawGpgChecks( ngpg[0], ngpg[1], ngpg[2] );
609 #define Z_CHKGPG(I,N) \
610 if ( ! sameTriboolState( ogpg[I], ngpg[I] ) ) \
611 { \
612 DBG << "Service repo " << it->alias() << " gets new "#N"Check " << ngpg[I] << std::endl; \
613 oldRepo->set##N##Check( ngpg[I] ); \
614 oldRepoModified = true; \
615 }
616 Z_CHKGPG( 0, Gpg );
617 Z_CHKGPG( 1, RepoGpg );
618 Z_CHKGPG( 2, PkgGpg );
619 #undef Z_CHKGPG
620 }
621
622 // changed gpgkey settings?
623 if ( oldRepo->rawGpgKeyUrls() != it->rawGpgKeyUrls() )
624 {
625 DBG << "Service repo " << it->alias() << " gets new GPGKEY url " << it->rawGpgKeyUrls() << std::endl;
626 oldRepo->setGpgKeyUrls( it->rawGpgKeyUrls() );
627 oldRepoModified = true;
628 }
629
630 // changed mirrorlist settings?
631 if ( oldRepo->rawCfgMirrorlistUrl() != it->rawCfgMirrorlistUrl() )
632 {
633 DBG << "Service repo " << it->alias() << " gets new MIRRORLIST url " << it->rawCfgMirrorlistUrl() << std::endl;
634 oldRepo->setMirrorlistUrl( it->rawCfgMirrorlistUrl() );
635 oldRepoModified = true;
636 }
637
638 // changed metalink settings?
639 if ( oldRepo->rawCfgMetalinkUrl() != it->rawCfgMetalinkUrl() )
640 {
641 DBG << "Service repo " << it->alias() << " gets new METALINK url " << it->rawCfgMetalinkUrl() << std::endl;
642 oldRepo->setMetalinkUrl( it->rawCfgMetalinkUrl() );
643 oldRepoModified = true;
644 }
645
646 // save if modified:
647 if ( oldRepoModified )
648 {
649 auto modRes = _repoMgr->modifyRepository( oldRepo->alias(), *oldRepo );
650 if ( !modRes ) return Ret::error( modRes.error() );
651 }
652 }
653 }
654
655 // Unlike reposToEnable, reposToDisable is always cleared after refresh.
656 if ( ! _service.reposToDisableEmpty() )
657 {
658 _service.clearReposToDisable();
659 _serviceModified = true;
660 }
661
662 // Remember original service request for next refresh
663 if ( _service.repoStates() != newRepoStates )
664 {
665 _service.setRepoStates( std::move(newRepoStates) );
666 _serviceModified = true;
667 }
668
670 // save service if modified: (unless a plugin service)
671 if ( _service.type() != zypp::repo::ServiceType::PLUGIN )
672 {
673 if ( _service.ttl() )
674 {
675 _service.setLrf( zypp::Date::now() ); // remember last refresh
676 _serviceModified = true; // or use a cookie file
677 }
678
679 if ( _serviceModified )
680 {
681 // write out modified service file.
682 auto modRes = _repoMgr->modifyService( _service.alias(), _service );
683 if ( !modRes ) return Ret::error( modRes.error() );
684 }
685 }
686
687 if ( _informalError ) {
688 return Ret::error( std::make_exception_ptr (_informalError.value()) );
689 }
690
691 return Ret::success( );
692 };
693 }
694
695
696 RepoManagerRef _repoMgr;
697 zypp::ServiceInfo _service;
699
700 // NOTE: It might be necessary to modify and rewrite the service info.
701 // Either when probing the type, or when adjusting the repositories
702 // enable/disable state.:
703 bool _serviceModified = false;
704
705 // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
706 // which is actually a notification. Using an exception for this
707 // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
708 // and in zypper.
709 std::optional<zypp::repo::ServicePluginInformalException> _informalError;
710 };
711 }
712
713 MaybeAwaitable<expected<void>> refreshService( RepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
714 {
715 RefreshServiceLogic impl( std::move(repoMgr), std::move(info), std::move(options) );
716 zypp_co_return zypp_co_await ( impl.execute() );
717 }
718
719}
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:27
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:463
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471
#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
Interface of repoindex.xml file reader.
static Date now()
Return the current time.
Definition Date.h:78
Base class for Exception.
Definition Exception.h:153
const std::string & msg() const
Return the message string provided to the ctor.
Definition Exception.h:206
void remember(const Exception &old_r)
Store an other Exception as history.
Definition Exception.cc:154
ExternalProgram extended to offer reading programs stderr.
bool stderrGetUpTo(std::string &retval_r, const char delim_r, bool returnDelim_r=false)
Read data up to delim_r from stderr (nonblocking).
int close() override
Wait for the progamm to complete.
std::vector< std::string > Arguments
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition Pathname.cc:281
What is known about a repository.
Definition RepoInfo.h:72
std::list< Url > url_set
Definition RepoInfo.h:108
Service data.
Definition ServiceInfo.h:37
repo::ServiceType type() const
Service type.
std::map< std::string, RepoState > RepoStates
Url manipulation class.
Definition Url.h:93
std::string getScheme() const
Returns the scheme name of the URL.
Definition Url.cc:560
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition Url.cc:631
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition Url.cc:791
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition Url.cc:903
const std::string & asString() const
String representation.
Definition Pathname.h:94
bool empty() const
Test for an empty path.
Definition Pathname.h:117
Just inherits Exception to separate media exceptions.
Read repository data from a .repo file.
Reads through a repoindex.xml file and collects repositories.
Date::Duration ttl() const
Metadata TTL (repoindex.xml:xpath:/repoindex@ttl or 0).
Exception for repository handling.
Service plugin has trouble providing the metadata but this should not be treated as error.
static Ptr create()
Definition process.cpp:49
SignalProxy< void(int)> sigFinished()
Definition process.cpp:294
zypp::RepoManagerFlags::RefreshServiceOptions RefreshServiceOptions
static expected success(ConsParams &&...params)
Definition expected.h:178
static expected error(ConsParams &&...params)
Definition expected.h:189
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
Definition ansi.h:855
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
@ RefreshService_restoreStatus
Force restoring repo enabled/disabled status.
@ RefreshService_forceRefresh
Force refresh even if TTL is not reached.
Callbacks light.
Definition Callback.h:146
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
Url details namespace.
Definition UrlBase.cc:58
MaybeAwaitable< expected< std::pair< zypp::ServiceInfo, RepoInfoList > > > fetchRepoListfromService(ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress)
MaybeAwaitable< expected< void > > refreshService(RepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
MaybeAwaitable< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
auto and_then(Fun &&function)
Definition expected.h:708
expected< void > assert_url(const ServiceInfo &info)
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:470
expected< void > assert_alias(const RepoInfo &info)
Definition repomanager.h:52
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
Definition repomanager.h:93
bool foundAliasIn(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Check if alias_r is present in repo/service container.
Definition repomanager.h:79
zypp::RepoInfoList RepoInfoList
Definition repomanager.h:40
auto mtry(F &&f, Args &&...args)
Definition mtry.h:50
#define Z_CHKGPG(I, N)
Collector< TOutputIterator > collector(TOutputIterator iter_r)
Convenience constructor.
Definition Collector.h:55
Service type enumeration.
Definition ServiceType.h:27