libzypp 17.37.10

serviceswf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "serviceswf.h"
10
11
12#include <zypp-core/ExternalProgram.h>
13#include <zypp-core/base/Gettext.h>
14#include <zypp-core/base/LogTools.h>
15#include <zypp-core/zyppng/pipelines/MTry>
16#include <zypp-core/zyppng/pipelines/Await>
17#include <zypp-core/zyppng/io/Process>
18#include <zypp-media/ng/providespec.h>
19#include <zypp/parser/RepoindexFileReader.h>
20#include <zypp/parser/RepoFileReader.h>
21#include <zypp/repo/RepoException.h>
22#include <zypp/Target.h>
23#include <zypp/zypp_detail/urlcredentialextractor_p.h>
24
25#include <zypp/ng/Context>
26#include <zypp/ng/workflows/contextfacade.h>
27#include <zypp/ng/workflows/logichelpers.h>
28#include <zypp/ng/workflows/mediafacade.h>
29
30#undef ZYPP_BASE_LOGGER_LOGGROUP
31#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
32
33 namespace zyppng::RepoServicesWorkflow {
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 );
94 zypp::repo::ServicePluginInformalException ex ( e.msg() );
95 ex.remember( e );
96 return expected<std::pair<zypp::ServiceInfo, RepoInfoList>>::error( ZYPP_EXCPT_PTR( ex ) );
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>;
118 using Ret = expected<std::pair<zypp::ServiceInfo, RepoInfoList>>;
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 );
151 zypp::parser::RepoFileReader parser( buffer, callback );
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
177 zypp::ExternalProgram::Arguments args;
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 ( ... ) {
195 return expected<int>::error( ZYPP_FWD_CURRENT_EXCPT() );
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
244 AsyncOpRef<expected<std::pair<zypp::ServiceInfo, RepoInfoList>>> fetchRepoListfromService( ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress )
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>;
267 using MediaHandle = std::conditional_t<isAsync, ProvideMediaHandle, SyncMediaHandle>;
268 using ProvideRes = std::conditional_t<isAsync, zyppng::ProvideRes, SyncProvideRes>;
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);
285 return expected<zypp::repo::ServiceType>::error( ZYPP_EXCPT_PTR(enew) );
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);
292 return expected<zypp::repo::ServiceType>::error( ZYPP_EXCPT_PTR(enew) );
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() );
298 return expected<zypp::repo::ServiceType>::error( ZYPP_EXCPT_PTR(enew) );
299 }
300
301 return expected<zypp::repo::ServiceType>::success( zypp::repo::ServiceType::NONE );
302 };
303 }
304 }
305
306 AsyncOpRef<expected<zypp::repo::ServiceType> > probeServiceType(ContextRef ctx, const zypp::Url &url)
307 {
308 return probeServiceLogic( std::move(ctx), url );
309 }
310
311 expected<zypp::repo::ServiceType> probeServiceType(SyncContextRef ctx, const zypp::Url &url)
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;
342 return expected<void>::success();
343 } );
344
345 }
346 return makeReadyResult( expected<void>::success() );
347 }
348
349 MaybeAsyncRef<Ret> execute() {
350
351 try {
352 assert_alias( _service ).unwrap();
353 assert_url( _service ).unwrap();
354 } catch (...) {
355 return makeReadyResult(Ret::error(ZYPP_FWD_CURRENT_EXCPT()));
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
403 return Ret::error( ZYPP_FWD_CURRENT_EXCPT() );
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
524 if ( _options.testFlag( zypp::RepoManagerFlags::RefreshService_restoreStatus ) )
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;
748 zypp::RepoManager::RefreshServiceOptions _options;
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
763 AsyncOpRef<expected<void>> refreshService(AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
764 {
765 return SimpleExecutor<RefreshServiceLogic, AsyncOp<expected<void>>>::run( std::move(repoMgr), std::move(info), std::move(options) );
766 }
767
768 expected<void> refreshService(SyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
769 {
770 return SimpleExecutor<RefreshServiceLogic, SyncOp<expected<void>>>::run( std::move(repoMgr), std::move(info), std::move(options) );
771 }
772
773}
RepoException.h
RepoFileReader.h
RepoindexFileReader.h
Interface of repoindex.xml file reader.
Target.h
ContextRefType
zypp::Date::now
static Date now()
Return the current time.
Definition Date.h:78
zypp::Exception
Base class for Exception.
Definition Exception.h:153
zypp::Exception::msg
const std::string & msg() const
Return the message string provided to the ctor.
Definition Exception.h:206
zypp::Exception::remember
void remember(const Exception &old_r)
Store an other Exception as history.
Definition Exception.cc:154
zypp::ExternalProgramWithStderr
ExternalProgram extended to offer reading programs stderr.
Definition ExternalProgram.h:266
zypp::ExternalProgramWithStderr::stderrGetUpTo
bool stderrGetUpTo(std::string &retval_r, const char delim_r, bool returnDelim_r=false)
Read data up to delim_r from stderr (nonblocking).
Definition ExternalProgram.cc:525
zypp::ExternalProgram::close
int close() override
Wait for the progamm to complete.
Definition ExternalProgram.cc:357
zypp::ExternalProgram::Arguments
std::vector< std::string > Arguments
Definition ExternalProgram.h:68
zypp::Pathname::stripprefix
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
zypp::RepoInfo
What is known about a repository.
Definition RepoInfo.h:72
zypp::RepoInfo::url_set
std::list< Url > url_set
Definition RepoInfo.h:108
zypp::RepoManager::RefreshService_restoreStatus
static constexpr RefreshServiceBit RefreshService_restoreStatus
Definition RepoManager.h:92
zypp::RepoManager::RefreshService_forceRefresh
static constexpr RefreshServiceBit RefreshService_forceRefresh
Definition RepoManager.h:93
zypp::RepoManager::RefreshServiceOptions
RepoManagerFlags::RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
Definition RepoManager.h:98
zypp::ServiceInfo
Service data.
Definition ServiceInfo.h:37
zypp::ServiceInfo::type
repo::ServiceType type() const
Service type.
Definition ServiceInfo.cc:111
zypp::ServiceInfo::RepoStates
std::map< std::string, RepoState > RepoStates
Definition ServiceInfo.h:185
zypp::Url
Url manipulation class.
Definition Url.h:93
zypp::Url::getScheme
std::string getScheme() const
Returns the scheme name of the URL.
Definition Url.cc:551
zypp::Url::asString
std::string asString() const
Returns a default string representation of the Url object.
Definition Url.cc:515
zypp::Url::getPathName
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition Url.cc:622
zypp::Url::setPathName
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition Url.cc:782
zypp::Url::setQueryParam
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition Url.cc:894
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:47
zypp::filesystem::Pathname::asString
const std::string & asString() const
String representation.
Definition Pathname.h:93
zypp::filesystem::Pathname::empty
bool empty() const
Test for an empty path.
Definition Pathname.h:116
zypp::parser::RepoFileReader
Read repository data from a .repo file.
Definition RepoFileReader.h:52
zypp::parser::RepoindexFileReader
Reads through a repoindex.xml file and collects repositories.
Definition RepoindexFileReader.h:45
zypp::parser::RepoindexFileReader::ttl
Date::Duration ttl() const
Metadata TTL (repoindex.xml:xpath:/repoindex@ttl or 0).
Definition RepoindexFileReader.cc:343
zypp::repo::ServicePluginInformalException
Service plugin has trouble providing the metadata but this should not be treated as error.
Definition RepoException.h:276
zyppng::Process::create
static Ptr create()
Definition process.cpp:49
zyppng::Process::StdErr
@ StdErr
Definition process.h:49
zyppng::Process::StdOut
@ StdOut
Definition process.h:48
zyppng::Process::sigFinished
SignalProxy< void(int)> sigFinished()
Definition process.cpp:294
zyppng::ProvideFileSpec
Definition providespec.h:92
zyppng::ProvideMediaSpec
Definition providespec.h:29
zyppng::ProvideRes
A ProvideRes object is a reference counted ownership of a resource in the cache provided by a Provide...
Definition provideres.h:36
zyppng::expected
Definition expected.h:27
zyppng::expected::unwrap
T & unwrap()
Definition expected.h:173
zyppng::expected::success
static expected success(ConsParams &&...params)
Definition expected.h:115
zyppng::expected::error
static expected error(ConsParams &&...params)
Definition expected.h:126
zyppng::expected< std::pair< zypp::ServiceInfo, RepoInfoList > >::error
std::exception_ptr & error()
Definition expected.h:225
contextfacade.h
logichelpers.h
ZYPP_ENABLE_LOGIC_BASE
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition logichelpers.h:223
mediafacade.h
std
Definition Arch.h:364
std::conditional_t
typename conditional< B, T, F >::type conditional_t
Definition TypeTraits.h:39
zypp::RepoManagerFlags::RefreshServiceOptions
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
Definition RepoManagerFlags.h:42
zypp::RepoManagerFlags::RefreshService_restoreStatus
@ RefreshService_restoreStatus
Force restoring repo enabled/disabled status.
Definition RepoManagerFlags.h:36
zypp::callback
Callbacks light.
Definition Callback.h:146
zypp::parser
Definition HistoryLogReader.cc:30
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
zypp::url
Url details namespace.
Definition UrlBase.cc:58
zypp::TriBool
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
zyppng::RepoServicesWorkflow
Definition serviceswf.cc:33
zyppng::RepoServicesWorkflow::refreshService
AsyncOpRef< expected< void > > refreshService(AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
Definition serviceswf.cc:763
zyppng::RepoServicesWorkflow::fetchRepoListfromService
AsyncOpRef< expected< std::pair< zypp::ServiceInfo, RepoInfoList > > > fetchRepoListfromService(ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress)
Definition serviceswf.cc:244
zyppng::RepoServicesWorkflow::probeServiceType
AsyncOpRef< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
Definition serviceswf.cc:306
zyppng::operators
Definition asyncresult.h:279
zyppng::operators::and_then
auto and_then(Fun &&function)
Definition expected.h:623
zyppng::mtry
Exp mtry(F &&f, Args &&...args)
Definition mtry.h:28
zyppng::assert_url
expected< void > assert_url(const ServiceInfo &info)
Definition repomanager.h:161
zyppng::await
auto await(SignalGetter &&sigGet)
Definition await.h:64
zyppng::makeReadyResult
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition asyncop.h:297
zyppng::AsyncOpRef
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition asyncop.h:255
zyppng::make_expected_success
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:397
zyppng::assert_alias
expected< void > assert_alias(const RepoInfo &info)
Definition repomanager.h:58
zyppng::SyncRepoManagerRef
RepoManagerRef< SyncContextRef > SyncRepoManagerRef
Definition repomanager.h:49
zyppng::AsyncRepoManagerRef
RepoManagerRef< ContextRef > AsyncRepoManagerRef
Definition repomanager.h:52
zyppng::findAlias
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
Definition repomanager.h:99
zyppng::foundAliasIn
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
zyppng::RepoInfoList
zypp::RepoInfoList RepoInfoList
Definition repomanager.h:38
providespec.h
Z_CHKGPG
#define Z_CHKGPG(I, N)
serviceswf.h
zypp::functor::Collector::collector
Collector< TOutputIterator > collector(TOutputIterator iter_r)
Convenience constructor.
Definition Collector.h:55
zypp::repo::ServiceType
Service type enumeration.
Definition ServiceType.h:27
zyppng::LogicBase
Definition logichelpers.h:161
zyppng::SimpleExecutor
Definition logichelpers.h:212
urlcredentialextractor_p.h
ExternalProgram.h
for_
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:27
ZYPP_CAUGHT
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
ZYPP_EXCPT_PTR
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:463
ZYPP_FWD_CURRENT_EXCPT
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471
Gettext.h
_
#define _(MSG)
Definition Gettext.h:39
LogTools.h
DBG
#define DBG
Definition Logger.h:99
MIL
#define MIL
Definition Logger.h:100
ERR
#define ERR
Definition Logger.h:102
WAR
#define WAR
Definition Logger.h:101