libzypp  17.36.3
serviceswf.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 #include "serviceswf.h"
10 
11 
13 #include <zypp-core/base/Gettext.h>
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;
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;
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;
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 
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;
342  return expected<void>::success();
343  } );
344 
345  }
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 
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 
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
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  // save if modified:
673  if ( oldRepoModified )
674  {
675  auto modRes = _repoMgr->modifyRepository( oldRepo->alias(), *oldRepo );
676  if ( !modRes ) return Ret::error( modRes.error() );
677  }
678  }
679  }
680 
681  // Unlike reposToEnable, reposToDisable is always cleared after refresh.
682  if ( ! _service.reposToDisableEmpty() )
683  {
684  _service.clearReposToDisable();
685  _serviceModified = true;
686  }
687 
688  // Remember original service request for next refresh
689  if ( _service.repoStates() != newRepoStates )
690  {
691  _service.setRepoStates( std::move(newRepoStates) );
692  _serviceModified = true;
693  }
694 
696  // save service if modified: (unless a plugin service)
697  if ( _service.type() != zypp::repo::ServiceType::PLUGIN )
698  {
699  if ( _service.ttl() )
700  {
701  _service.setLrf( zypp::Date::now() ); // remember last refresh
702  _serviceModified = true; // or use a cookie file
703  }
704 
705  if ( _serviceModified )
706  {
707  // write out modified service file.
708  auto modRes = _repoMgr->modifyService( _service.alias(), _service );
709  if ( !modRes ) return Ret::error( modRes.error() );
710  }
711  }
712 
713  if ( _informalError ) {
714  return Ret::error( std::make_exception_ptr (_informalError.value()) );
715  }
716 
717  return Ret::success( );
718  };
719  }
720 
721 
722  RepoMgrRefType _repoMgr;
725 
726  // NOTE: It might be necessary to modify and rewrite the service info.
727  // Either when probing the type, or when adjusting the repositories
728  // enable/disable state.:
729  bool _serviceModified = false;
730 
731  // FIXME Ugly hack: ServiceRepos may throw ServicePluginInformalException
732  // which is actually a notification. Using an exception for this
733  // instead of signal/callback is bad. Needs to be fixed here, in refreshServices()
734  // and in zypper.
735  std::optional<zypp::repo::ServicePluginInformalException> _informalError;
736  };
737  }
738 
740  {
741  return SimpleExecutor<RefreshServiceLogic, AsyncOp<expected<void>>>::run( std::move(repoMgr), std::move(info), std::move(options) );
742  }
743 
745  {
746  return SimpleExecutor<RefreshServiceLogic, SyncOp<expected<void>>>::run( std::move(repoMgr), std::move(info), std::move(options) );
747  }
748 
749 }
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:551
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:100
bool _serviceModified
Definition: serviceswf.cc:729
static constexpr RefreshServiceBit RefreshService_restoreStatus
Definition: RepoManager.h:92
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:30
std::optional< zypp::repo::ServicePluginInformalException > _informalError
Definition: serviceswf.cc:735
#define _(MSG)
Definition: Gettext.h:39
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: Url.cc:856
Reads through a repoindex.xml file and collects repositories.
RepoManagerFlags::RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
Definition: RepoManager.h:98
SignalProxy< void(int)> sigFinished()
Definition: process.cpp:294
AsyncOpRef< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
Definition: serviceswf.cc:306
RepoMgrRefType _repoMgr
Definition: serviceswf.cc:722
RefreshServiceFlags RefreshServiceOptions
Options tuning RefreshService.
ExternalProgram extended to offer reading programs stderr.
A ProvideRes object is a reference counted ownership of a resource in the cache provided by a Provide...
Definition: provideres.h:35
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
Definition: Arch.h:363
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:397
Service plugin has trouble providing the metadata but this should not be treated as error...
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:37
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:428
zypp::RepoManager::RefreshServiceOptions _options
Definition: serviceswf.cc:724
expected< void > assert_url(const ServiceInfo &info)
Definition: repomanager.h:161
#define ERR
Definition: Logger.h:102
Extract credentials in Url authority and store them via CredentialManager.
Interface of repoindex.xml file reader.
zypp::RepoInfoList RepoInfoList
Definition: repomanager.h:38
AsyncOpRef< expected< std::pair< zypp::ServiceInfo, RepoInfoList > > > fetchRepoListfromService(ContextRef ctx, zypp::Pathname root_r, ServiceInfo service, ProgressObserverRef myProgress)
Definition: serviceswf.cc:244
void remember(const Exception &old_r)
Store an other Exception as history.
Definition: Exception.cc:141
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Definition: Bit.h:57
ServiceInfo _service
Definition: serviceswf.cc:104
Exp mtry(F &&f, Args &&...args)
Definition: mtry.h:28
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:782
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
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:515
static Ptr create()
Definition: process.cpp:49
Just inherits Exception to separate media exceptions.
Service type enumeration.
Definition: ServiceType.h:26
RepoManagerRef< SyncContextRef > SyncRepoManagerRef
Definition: repomanager.h:49
expected< void > assert_alias(const RepoInfo &info)
Definition: repomanager.h:58
#define WAR
Definition: Logger.h:101
int close() override
Wait for the progamm to complete.
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition: logichelpers.h:223
static constexpr RefreshServiceBit RefreshService_forceRefresh
Definition: RepoManager.h:93
Read repository data from a .repo file.
typename conditional< B, T, F >::type conditional_t
Definition: TypeTraits.h:39
std::list< Url > url_set
Definition: RepoInfo.h:108
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition: asyncop.h:297
std::vector< std::string > Arguments
static expected success(ConsParams &&...params)
Definition: expected.h:115
zypp::ServiceInfo ServiceInfo
Definition: repomanager.h:39
std::string _stderrBuf
Definition: serviceswf.cc:166
bool stderrGetUpTo(std::string &retval_r, const char delim_r, bool returnDelim_r=false)
Read data up to delim_r from stderr (nonblocking).
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition: asyncop.h:255
zypp::Pathname _root_r
Definition: serviceswf.cc:103
Base class for Exception.
Definition: Exception.h:146
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:622
AsyncOpRef< expected< void > > refreshService(AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
Definition: serviceswf.cc:739
Iterator findAlias(const std::string &alias_r, Iterator begin_r, Iterator end_r)
Find alias_r in repo/service container.
Definition: repomanager.h:99
std::map< std::string, RepoState > RepoStates
Definition: ServiceInfo.h:185
RepoManagerRef< ContextRef > AsyncRepoManagerRef
Definition: repomanager.h:52
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition: expected.h:423
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition: Exception.h:436
#define Z_CHKGPG(I, N)
std::string _stdoutBuf
Definition: serviceswf.cc:165
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:105
Url manipulation class.
Definition: Url.h:92
#define DBG
Definition: Logger.h:99
ZyppContextRefType _ctx
Definition: serviceswf.cc:102
const std::string & msg() const
Return the message string provided to the ctor.
Definition: Exception.h:196