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