libzypp  17.38.7
serviceswf.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 #include "serviceswf.h"
10 
11 
13 #include <zypp-core/base/Gettext.h>
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>
25 #include <zypp/ng/media/provide.h>
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;
96  ProgressObserverRef _myProgress;
97  };
98 
99  struct FetchPluginServiceLogic
100  {
101  public:
102  using Ret = expected<std::pair<zypp::ServiceInfo, RepoInfoList>>;
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;
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 );
135  zypp::parser::RepoFileReader parser( buffer, callback );
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 
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;
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;
292  return expected<void>::success();
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 
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
353  return Ret::error( ZYPP_FWD_CURRENT_EXCPT() );
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
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;
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 }
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:560
Service data.
Definition: ServiceInfo.h:36
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: Target.cc:102
Force restoring repo enabled/disabled status.
#define MIL
Definition: Logger.h:103
bool _serviceModified
Definition: serviceswf.cc:703
std::optional< zypp::repo::ServicePluginInformalException > _informalError
Definition: serviceswf.cc:709
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: Url.cc:903
Reads through a repoindex.xml file and collects repositories.
std::string asString(const Patch::Category &obj)
relates: Patch::Category string representation.
Definition: Patch.cc:122
SignalProxy< void(int)> sigFinished()
Definition: process.cpp:294
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
ExternalProgram extended to offer reading programs stderr.
Force refresh even if TTL is not reached.
MaybeAwaitable< expected< void > > refreshService(RepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
Definition: serviceswf.cc:713
Collector< TOutputIterator > collector(TOutputIterator iter_r)
relates: Collector Convenience constructor.
Definition: Collector.h:55
std::list< RepoInfo > RepoInfoList
relates: RepoInfo
Definition: RepoInfo.h:636
Definition: ansi.h:854
MaybeAwaitable< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
Definition: serviceswf.cc:231
What is known about a repository.
Definition: RepoInfo.h:71
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition: expected.h:470
Service plugin has trouble providing the metadata but this should not be treated as error...
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
static expected error(ConsParams &&...params)
Definition: expected.h:189
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:39
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:463
expected< void > assert_url(const ServiceInfo &info)
Definition: repomanager.h:155
#define ERR
Definition: Logger.h:105
Extract credentials in Url authority and store them via CredentialManager.
Interface of repoindex.xml file reader.
zypp::RepoInfoList RepoInfoList
Definition: repomanager.h:40
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:31
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:154
ServiceInfo _service
Definition: serviceswf.cc:95
bool empty() const
Test for an empty path.
Definition: Pathname.h:117
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:791
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
Store and operate on date (time_t).
Definition: Date.h:32
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:524
static Ptr create()
Definition: process.cpp:49
Just inherits Exception to separate media exceptions.
Service type enumeration.
Definition: ServiceType.h:26
expected< void > assert_alias(const RepoInfo &info)
Definition: repomanager.h:52
#define WAR
Definition: Logger.h:104
Read repository data from a .repo file.
#define _(MSG)
Definition: Gettext.h:39
std::list< Url > url_set
Definition: RepoInfo.h:108
std::vector< std::string > Arguments
static expected success(ConsParams &&...params)
Definition: expected.h:178
Provide::Res ProvideRes
Definition: provide.h:154
zypp::ServiceInfo ServiceInfo
Definition: repomanager.h:41
std::string _stderrBuf
Definition: serviceswf.cc:216
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:475
MaybeAwaitable< expected< std::pair< zypp::ServiceInfo, RepoInfoList > > > fetchRepoListfromService(ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress)
Definition: serviceswf.cc:220
zypp::Pathname _root_r
Definition: serviceswf.cc:94
Base class for Exception.
Definition: Exception.h:152
Exception for repository handling.
Definition: RepoException.h:37
static Date now()
Return the current time.
Definition: Date.h:78
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:631
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
Definition: repomanager.h:93
std::map< std::string, RepoState > RepoStates
Definition: ServiceInfo.h:185
RepoManagerRef _repoMgr
Definition: serviceswf.cc:696
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition: expected.h:520
auto mtry(F &&f, Args &&...args)
Definition: mtry.h:50
ContextRef _ctx
Definition: serviceswf.cc:93
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition: Exception.h:471
#define Z_CHKGPG(I, N)
zypp::RepoManagerFlags::RefreshServiceOptions RefreshServiceOptions
Definition: repomanager.h:256
std::string _stdoutBuf
Definition: serviceswf.cc:215
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
repo::ServiceType type() const
Service type.
Definition: ServiceInfo.cc:111
ProgressObserverRef _myProgress
Definition: serviceswf.cc:96
Url manipulation class.
Definition: Url.h:92
#define DBG
Definition: Logger.h:102
RepoManager::RefreshServiceOptions _options
Definition: serviceswf.cc:698
const std::string & msg() const
Return the message string provided to the ctor.
Definition: Exception.h:206