libzypp 17.37.17
repomanager.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9
10#include "repomanager.h"
12
13#include <solv/solvversion.h>
14
18#include <zypp-core/zyppng/pipelines/MTry>
19#include <zypp-core/zyppng/pipelines/Transform>
20#include <zypp-core/zyppng/ui/ProgressObserver>
22#include <zypp/HistoryLog.h>
23#include <zypp/ZConfig.h>
24#include <zypp/ZYppCallbacks.h>
25#include <zypp/base/LogTools.h>
28#include <zypp/sat/Pool.h>
32
38
39#include <fstream>
40#include <utility>
41
42#undef ZYPP_BASE_LOGGER_LOGGROUP
43#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
44
46 bool IGotIt(); // in readonly-mode
47}
48
49
50namespace zyppng
51{
52 namespace env
53 {
56 {
57 const char * env = getenv("ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
58 return( env && zypp::str::strToBool( env, true ) );
59 }
60 } // namespace env
61
62 namespace {
68 inline void cleanupNonRepoMetadataFolders( const zypp::Pathname & cachePath_r,
69 const zypp::Pathname & defaultCachePath_r,
70 const std::list<std::string> & repoEscAliases_r )
71 {
72 if ( cachePath_r != defaultCachePath_r )
73 return;
74
75 std::list<std::string> entries;
76 if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
77 {
78 entries.sort();
79 std::set<std::string> oldfiles;
80 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
81 std::inserter( oldfiles, oldfiles.end() ) );
82
83 // bsc#1178966: Files or symlinks here have been created by the user
84 // for whatever purpose. It's our cache, so we purge them now before
85 // they may later conflict with directories we need.
87 for ( const std::string & old : oldfiles )
88 {
89 if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
90 continue;
91 pi( cachePath_r/old );
92 if ( pi.isDir() )
94 else
96 }
97 }
98 }
99 } // namespace
100
102 {
103 switch ( obj ) {
104#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
105 OUTS( RefreshIfNeeded );
106 OUTS( RefreshForced );
107 OUTS( RefreshIfNeededIgnoreDelay );
108#undef OUTS
109 }
110 return str;
111 }
112
113 std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::RefreshCheckStatus obj )
114 {
115 switch ( obj ) {
116#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
117 OUTS( REFRESH_NEEDED );
118 OUTS( REPO_UP_TO_DATE );
119 OUTS( REPO_CHECK_DELAYED );
120#undef OUTS
121 }
122 return str;
123 }
124
125 std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::CacheBuildPolicy obj )
126 {
127 switch ( obj ) {
128#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
129 OUTS( BuildIfNeeded );
130 OUTS( BuildForced );
131#undef OUTS
132 }
133 return str;
134 }
135
136
137 std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
138 {
139 std::string filename( alias_r );
140 // replace slashes with underscores
141 zypp::str::replaceAll( filename, "/", "_" );
142
143 filename = zypp::Pathname(filename).extend("."+stem_r).asString();
144 MIL << "generating filename for " << stem_r << " [" << alias_r << "] : '" << filename << "'" << std::endl;
145 return filename;
146 }
147
149 {
150 // skip repositories meant for other distros than specified
151 if (!targetDistro.empty()
152 && !repo.targetDistribution().empty()
153 && repo.targetDistribution() != targetDistro)
154 {
155 MIL
156 << "Skipping repository meant for '" << repo.targetDistribution()
157 << "' distribution (current distro is '"
158 << targetDistro << "')." << std::endl;
159
160 return true;
161 }
162
163 repos.push_back(repo);
164 return true;
165 }
166
168 {
169 try {
170 MIL << "repo file: " << file << std::endl;
171 RepoCollector collector;
172 zypp::parser::RepoFileReader parser( file, std::bind( &RepoCollector::collect, &collector, std::placeholders::_1 ) );
173 return expected<std::list<RepoInfo>>::success( std::move(collector.repos) );
174 } catch ( ... ) {
176 }
177 }
178
188 template <typename ZContextRef>
189 std::list<RepoInfo> repositories_in_dir( ZContextRef zyppContext, const zypp::Pathname &dir )
190 {
191 MIL << "directory " << dir << std::endl;
192 std::list<RepoInfo> repos;
193 bool nonroot( geteuid() != 0 );
194 if ( nonroot && ! zypp::PathInfo(dir).userMayRX() )
195 {
196 JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo directory '%1%': Permission denied")) % dir );
197 }
198 else
199 {
200 std::list<zypp::Pathname> entries;
201 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
202 {
203 // TranslatorExplanation '%s' is a pathname
204 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
205 }
206
207 zypp::str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
208 for ( std::list<zypp::Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
209 {
210 if ( zypp::str::regex_match(it->extension(), allowedRepoExt) )
211 {
212 if ( nonroot && ! zypp::PathInfo(*it).userMayR() )
213 {
214 JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo file '%1%': Permission denied")) % *it );
215 }
216 else
217 {
218 const std::list<RepoInfo> tmp( repositories_in_file( *it ).unwrap() );
219 repos.insert( repos.end(), tmp.begin(), tmp.end() );
220 }
221 }
222 }
223 }
224 return repos;
225 }
226
233
234 bool autoPruneInDir(const zypp::Pathname &path_r)
235 { return not zypp::PathInfo(path_r/".no_auto_prune").isExist(); }
236
237
238 template <typename ZyppContextRefType>
240 : _zyppContext( std::move(zyppCtx) )
241 , _options( std::move(opt) )
242 , _pluginRepoverification( _options.pluginsPath / "repoverification",
243 _options.rootDir)
244 {
245
246 }
247
248 template <typename ZyppContextRefType>
250 {
251 // trigger appdata refresh if some repos change
253 && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
254 {
255 try {
256 std::list<zypp::Pathname> entries;
257 zypp::filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
258 if ( ! entries.empty() )
259 {
261 cmd.push_back( "<" ); // discard stdin
262 cmd.push_back( ">" ); // discard stdout
263 cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
264 for ( const auto & rinfo : repos() )
265 {
266 if ( ! rinfo.enabled() )
267 continue;
268 cmd.push_back( "-R" );
269 cmd.push_back( rinfo.alias() );
270 cmd.push_back( "-t" );
271 cmd.push_back( rinfo.type().asString() );
272 cmd.push_back( "-p" );
273 cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache
274 }
275
276 for_( it, entries.begin(), entries.end() )
277 {
278 zypp::PathInfo pi( *it );
279 //DBG << "/tmp/xx ->" << pi << endl;
280 if ( pi.isFile() && pi.userMayRX() )
281 {
282 // trigger plugin
283 cmd[2] = pi.asString(); // [2] - PROGRAM
285 }
286 }
287 }
288 }
289 catch (...) {} // no throw in dtor
290 }
291 }
292
293 template<typename ZyppContextRefType>
295 {
296 using namespace zyppng::operators;
297 return
299 | and_then( [this](){ return init_knownRepositories(); } );
300 }
301
302 template<typename ZyppContextRefType>
307
308 template <typename ZyppContextRefType>
310 {
311 try {
312 using namespace zyppng::operators;
313
314 // ATTENTION when making this pipeline async
315 // consider moving it into a workflow object
316 // this var is caputured by ref to modify it from
317 // inside the pipeline, which would break.
318 zypp::Pathname mediarootpath;
319
320 return rawcache_path_for_repoinfo( options, info )
321 | and_then( [&]( zypp::Pathname mrPath ) {
322 mediarootpath = std::move(mrPath);
324 })
325 | and_then( [&]( zypp::Pathname productdatapath ) {
326 zypp::repo::RepoType repokind = info.type();
327 // If unknown, probe the local metadata
328 if ( repokind == zypp::repo::RepoType::NONE )
329 repokind = probeCache( productdatapath );
330
331 // NOTE: The calling code expects an empty RepoStatus being returned
332 // if the metadata cache is empty. So additional components like the
333 // RepoInfos status are joined after the switch IFF the status is not
334 // empty.huhu
335 RepoStatus status;
336 switch ( repokind.toEnum() )
337 {
339 status = RepoStatus( productdatapath/"repodata/repomd.xml");
340 if ( info.requireStatusWithMediaFile() )
341 status = status && RepoStatus( mediarootpath/"media.1/media" );
342 break;
343
345 status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" );
346 break;
347
349 // Dir status at last refresh. Plaindir uses the cookiefile as pseudo metadata index file.
350 // It gets touched if the refresh check finds the data being up-to-date. That's why we use
351 // the files mtime as timestamp (like the RepoStatus ctor in the other cases above).
352 status = RepoStatus::fromCookieFileUseMtime( productdatapath/"cookie" );
353 break;
354
356 // Return default RepoStatus in case of RepoType::NONE
357 // indicating it should be created?
358 // ZYPP_THROW(RepoUnknownTypeException());
359 break;
360 }
361
362 if ( ! status.empty() )
363 status = status && RepoStatus( info );
364
365 return expected<RepoStatus>::success(status);
366 });
367 } catch (...) {
369 }
370 }
371
372 template <typename ZyppContextRefType>
377
378 template <typename ZyppContextRefType>
379 expected<void> RepoManager<ZyppContextRefType>::cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress )
380 {
381 try {
382
383 ProgressObserver::setup( myProgress, _("Cleaning metadata"), 100 );
384 ProgressObserver::start( myProgress );
385 zypp::filesystem::recursive_rmdir( _zyppContext->config().geoipCachePath() );
386 ProgressObserver::setCurrent ( myProgress, 50 );
388 ProgressObserver::finish ( myProgress );
389
390 } catch ( ... ) {
393 }
395 }
396
397 template <typename ZyppContextRefType>
398 expected<void> RepoManager<ZyppContextRefType>::cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress, bool isAutoClean )
399 {
400 try {
401 ProgressObserver::setup( myProgress, _("Cleaning packages"), 100 );
402 ProgressObserver::start( myProgress );
403
404 // bsc#1204956: Tweak to prevent auto pruning package caches
406 if ( not isAutoClean || autoPruneInDir( rpc.dirname() ) )
408
409 ProgressObserver::finish ( myProgress );
410
411 } catch (...) {
414 }
415
417 }
418
424 template <typename ZyppContextRefType>
426 {
427 MIL << "going to probe the cached repo at " << path_r << std::endl;
428
430
431 if ( zypp::PathInfo(path_r/"/repodata/repomd.xml").isFile() )
433 else if ( zypp::PathInfo(path_r/"/content").isFile() )
435 else if ( zypp::PathInfo(path_r/"/cookie").isFile() )
437
438 MIL << "Probed cached type " << ret << " at " << path_r << std::endl;
439 return ret;
440 }
441
442 template <typename ZyppContextRefType>
444 {
445 try {
446 MIL << "Going to clean up garbage in cache dirs" << std::endl;
447
448 std::list<zypp::Pathname> cachedirs;
449 cachedirs.push_back(_options.repoRawCachePath);
450 cachedirs.push_back(_options.repoPackagesCachePath);
451 cachedirs.push_back(_options.repoSolvCachePath);
452
453 ProgressObserver::setup( myProgress, _("Cleaning up cache dirs"), cachedirs.size() );
454 ProgressObserver::start( myProgress );
455
456 for( const auto &dir : cachedirs )
457 {
458 // increase progress on end of every iteration
459 zypp_defer {
460 ProgressObserver::increase( myProgress );
461 };
462
463 if ( zypp::PathInfo(dir).isExist() )
464 {
465 std::list<zypp::Pathname> entries;
466 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
467 // TranslatorExplanation '%s' is a pathname
468 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
469
470 if ( !entries.size() )
471 continue;
472
473 auto dirProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Format( _("Cleaning up directory: %1%") ) % dir, entries.size() );
474 for( const auto &subdir : entries )
475 {
476 // if it does not belong known repo, make it disappear
477 bool found = false;
478 for_( r, repoBegin(), repoEnd() )
479 if ( subdir.basename() == r->escaped_alias() )
480 { found = true; break; }
481
482 if ( ! found && ( zypp::Date::now()-zypp::PathInfo(subdir).mtime() > zypp::Date::day ) )
484
485 ProgressObserver::increase( dirProgress );
486 }
487 ProgressObserver::finish( dirProgress );
488 }
489 }
490 } catch (...) {
491 // will finish all subprogress children
494 }
495 ProgressObserver::finish ( myProgress );
497 }
498
499 template <typename ZyppContextRefType>
500 expected<void> RepoManager<ZyppContextRefType>::cleanCache(const RepoInfo &info, ProgressObserverRef myProgress )
501 {
502 try {
503 ProgressObserver::setup( myProgress, _("Cleaning cache"), 100 );
504 ProgressObserver::start( myProgress );
505
506 MIL << "Removing raw metadata cache for " << info.alias() << std::endl;
508
509 ProgressObserver::finish( myProgress );
511
512 } catch (...) {
513 // will finish all subprogress children
516 }
517 }
518
519 template <typename ZyppContextRefType>
520 expected<void> RepoManager<ZyppContextRefType>::loadFromCache( const RepoInfo & info, ProgressObserverRef myProgress )
521 {
522 using namespace zyppng::operators;
523 return zyppng::mtry( [this, info, myProgress](){
524 ProgressObserver::setup( myProgress, _("Loading from cache"), 3 );
525 ProgressObserver::start( myProgress );
526
527 assert_alias(info).unwrap();
528 zypp::Pathname solvfile = solv_path_for_repoinfo(_options, info).unwrap() / "solv";
529
530 if ( ! zypp::PathInfo(solvfile).isExist() )
532
533 _zyppContext->satPool().reposErase( info.alias() );
534
535 ProgressObserver::increase ( myProgress );
536
537 zypp::Repository repo = _zyppContext->satPool().addRepoSolv( solvfile, info );
538
539 ProgressObserver::increase ( myProgress );
540
541 // test toolversion in order to rebuild solv file in case
542 // it was written by a different libsolv-tool parser.
543 const std::string & toolversion( zypp::sat::LookupRepoAttr( zypp::sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
544 if ( toolversion != LIBSOLV_TOOLVERSION ) {
545 repo.eraseFromPool();
546 ZYPP_THROW(zypp::Exception(zypp::str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
547 }
548 })
549 | or_else( [this, info, myProgress]( std::exception_ptr exp ) {
550 ZYPP_CAUGHT( exp );
551 MIL << "Try to handle exception by rebuilding the solv-file" << std::endl;
552 return cleanCache( info, ProgressObserver::makeSubTask( myProgress ) )
553 | and_then([this, info, myProgress]{
555 })
556 | and_then( mtry([this, info = info]{
557 _zyppContext->satPool().addRepoSolv( solv_path_for_repoinfo(_options, info).unwrap() / "solv", info );
558 }));
559 })
560 | and_then([myProgress]{
561 ProgressObserver::finish ( myProgress );
563 })
564 | or_else([myProgress]( auto ex ){
566 return expected<void>::error(ex);
567 })
568 ;
569 }
570
571 template <typename ZyppContextRefType>
573 {
574 try {
575 auto tosave = info;
576
577 // assert the directory exists
579
581 _options.knownReposPath, generateFilename(tosave));
582 // now we have a filename that does not exists
583 MIL << "Saving repo in " << repofile << std::endl;
584
585 std::ofstream file(repofile.c_str());
586 if (!file)
587 {
588 // TranslatorExplanation '%s' is a filename
589 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
590 }
591
592 tosave.dumpAsIniOn(file);
593 tosave.setFilepath(repofile);
594 tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ).unwrap() );
595 tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ).unwrap() );
596 reposManip().insert(tosave);
597
598 // check for credentials in base Urls
599 zypp::UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
600
601 zypp::HistoryLog(_options.rootDir).addRepository(tosave);
602
603 // return the new repoinfo
604 return expected<RepoInfo>::success( tosave );
605
606 } catch (...) {
608 }
609 }
610
611 template <typename ZyppContextRefType>
612 expected<void> RepoManager<ZyppContextRefType>::removeRepository( const RepoInfo & info, ProgressObserverRef myProgress )
613 {
614 try {
615 ProgressObserver::setup( myProgress, zypp::str::form(_("Removing repository '%s'"), info.label().c_str()), 1 );
616 ProgressObserver::start( myProgress );
617
618 MIL << "Going to delete repo " << info.alias() << std::endl;
619
620 for( const auto &repo : repos() )
621 {
622 // they can be the same only if the provided is empty, that means
623 // the provided repo has no alias
624 // then skip
625 if ( (!info.alias().empty()) && ( info.alias() != repo.alias() ) )
626 continue;
627
628 // TODO match by url
629
630 // we have a matching repository, now we need to know
631 // where it does come from.
632 RepoInfo todelete = repo;
633 if (todelete.filepath().empty())
634 {
635 ZYPP_THROW(zypp::repo::RepoException( todelete, _("Can't figure out where the repo is stored.") ));
636 }
637 else
638 {
639 // figure how many repos are there in the file:
640 std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath()).unwrap();
641 if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
642 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
643 {
644 // easy: file does not exist, contains no or only the repo to delete: delete the file
645 int ret = zypp::filesystem::unlink( todelete.filepath() );
646 if ( ! ( ret == 0 || ret == ENOENT ) )
647 {
648 // TranslatorExplanation '%s' is a filename
649 ZYPP_THROW(zypp::repo::RepoException( todelete, zypp::str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
650 }
651 MIL << todelete.alias() << " successfully deleted." << std::endl;
652 }
653 else
654 {
655 // there are more repos in the same file
656 // write them back except the deleted one.
657 //TmpFile tmp;
658 //std::ofstream file(tmp.path().c_str());
659
660 // assert the directory exists
662
663 std::ofstream file(todelete.filepath().c_str());
664 if (!file)
665 {
666 // TranslatorExplanation '%s' is a filename
667 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
668 }
669 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
670 fit != filerepos.end();
671 ++fit )
672 {
673 if ( (*fit).alias() != todelete.alias() )
674 (*fit).dumpAsIniOn(file);
675 }
676 }
677
678 // now delete it from cache
679 if ( isCached(todelete) )
680 cleanCache( todelete, ProgressObserver::makeSubTask( myProgress, 0.2 )).unwrap();
681 // now delete metadata (#301037)
682 cleanMetadata( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 )).unwrap();
683 cleanPackages( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 ), true/*isAutoClean*/ ).unwrap();
684 reposManip().erase(todelete);
685 MIL << todelete.alias() << " successfully deleted." << std::endl;
686 zypp::HistoryLog(_options.rootDir).removeRepository(todelete);
687
688 ProgressObserver::finish(myProgress);
690 } // else filepath is empty
691 }
692 // should not be reached on a sucess workflow
694 } catch (...) {
696 return expected<void>::error( std::current_exception () );
697 }
698 }
699
700 template <typename ZyppContextRefType>
701 expected<RepoInfo> RepoManager<ZyppContextRefType>::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, ProgressObserverRef myProgress )
702 {
703 try {
704
705 ProgressObserver::setup( myProgress, _("Modifying repository"), 5 );
706 ProgressObserver::start( myProgress );
707
708 RepoInfo toedit = getRepositoryInfo(alias).unwrap();
709 RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
710
711 // check if the new alias already exists when renaming the repo
712 if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
713 {
715 }
716
717 if (toedit.filepath().empty())
718 {
719 ZYPP_THROW(zypp::repo::RepoException( toedit, _("Can't figure out where the repo is stored.") ));
720 }
721 else
722 {
723 ProgressObserver::increase( myProgress );
724 // figure how many repos are there in the file:
725 std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath()).unwrap();
726
727 // there are more repos in the same file
728 // write them back except the deleted one.
729 //TmpFile tmp;
730 //std::ofstream file(tmp.path().c_str());
731
732 // assert the directory exists
734
735 std::ofstream file(toedit.filepath().c_str());
736 if (!file)
737 {
738 // TranslatorExplanation '%s' is a filename
739 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
740 }
741 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
742 fit != filerepos.end();
743 ++fit )
744 {
745 // if the alias is different, dump the original
746 // if it is the same, dump the provided one
747 if ( (*fit).alias() != toedit.alias() )
748 (*fit).dumpAsIniOn(file);
749 else
750 newinfo.dumpAsIniOn(file);
751 }
752
753 ProgressObserver::increase( myProgress );
754
755 if ( toedit.enabled() && !newinfo.enabled() )
756 {
757 // On the fly remove solv.idx files for bash completion if a repo gets disabled.
758 const zypp::Pathname solvidx = solv_path_for_repoinfo(_options, newinfo).unwrap()/"solv.idx";
759 if ( zypp::PathInfo(solvidx).isExist() )
760 zypp::filesystem::unlink( solvidx );
761 }
762
763 newinfo.setFilepath(toedit.filepath());
764 newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ).unwrap() );
765 newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ).unwrap() );
766
767 ProgressObserver::increase( myProgress );
768
769 reposManip().erase(toedit);
770 reposManip().insert(newinfo);
771
772 ProgressObserver::increase( myProgress );
773
774 // check for credentials in Urls
776 zypp::HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
777 MIL << "repo " << alias << " modified" << std::endl;
778
779 ProgressObserver::finish ( myProgress );
780 return expected<RepoInfo>::success( newinfo );
781 }
782
783 } catch ( ... ) {
786 }
787 }
788
789 template <typename ZyppContextRefType>
791 {
792 try {
793 RepoConstIterator it( findAlias( alias, repos() ) );
794 if ( it != repos().end() )
795 return make_expected_success(*it);
796 RepoInfo info;
797 info.setAlias( alias );
799 } catch ( ... ) {
800 return expected<RepoInfo>::error( std::current_exception () );
801 }
802 }
803
804
805 template <typename ZyppContextRefType>
807 {
808 try {
809
810 for_( it, repoBegin(), repoEnd() )
811 {
812 for( const auto &origin : it->repoOrigins() )
813 {
814 if ( std::any_of( origin.begin(), origin.end(), [&url, &urlview]( const zypp::OriginEndpoint &ep ){ return (ep.url().asString(urlview) == url.asString(urlview)); }) )
815 return make_expected_success(*it);
816 }
817 }
818 RepoInfo info;
819 info.setBaseUrl( url );
821
822 } catch ( ... ) {
823 return expected<RepoInfo>::error( std::current_exception () );
824 }
825 }
826
827 template<typename ZyppContextRefType>
829 {
830 using namespace zyppng::operators;
833 | [this, info](auto) { return zyppng::repo::RefreshContext<ZyppContextRefType>::create( _zyppContext, info, shared_this<RepoManager<ZyppContextRefType>>() ); }
834 | and_then( [this, origin, policy]( zyppng::repo::RefreshContextRef<ZyppContextRefType> &&refCtx ) {
835 refCtx->setPolicy ( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
836
837 return _zyppContext->provider()->prepareMedia( origin, zyppng::ProvideMediaSpec() )
838 | and_then( [ r = std::move(refCtx) ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), std::move(mediaHandle), nullptr ); } );
839 })
840 );
841 }
842
843 template<typename ZyppContextRefType>
845 {
846 using namespace zyppng::operators;
847 // helper callback in case the repo type changes on the remote
848 // do NOT capture by reference here, since this is possibly executed async
849 const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
850 // update probed type only for repos in system
851 for( const auto &repo : repos() ) {
852 if ( info.alias() == repo.alias() )
853 {
854 RepoInfo modifiedrepo = repo;
855 modifiedrepo.setType( repokind );
856 // don't modify .repo in refresh.
857 // modifyRepository( info.alias(), modifiedrepo );
858 break;
859 }
860 }
861 };
862
863 // the list of URLs we want to have geo ip redirects for
864 auto urls = info.baseUrls ();
865 if ( info.mirrorListUrl ().isValid () )
866 urls.push_back ( info.mirrorListUrl () );
867
869 // make sure geoIP data is up 2 date, but ignore errors
872 | and_then( [policy, myProgress, cb = updateProbedType]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
873 refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
874 // in case probe detects a different repokind, update our internal repos
876
877 return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), myProgress );
878 })
879 | and_then([rMgr = shared_this<RepoManager<ZyppContextRefType>>()]( repo::RefreshContextRef<ZyppContextRefType> ctx ) {
880
881 if ( ! isTmpRepo( ctx->repoInfo() ) )
882 rMgr->reposManip(); // remember to trigger appdata refresh
883
884 return expected<void>::success ();
885 }));
886 }
887
888 template<typename ZyppContextRefType>
889 std::vector<std::pair<RepoInfo, expected<void>>> RepoManager<ZyppContextRefType>::refreshMetadata( std::vector<RepoInfo> infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress )
890 {
891 using namespace zyppng::operators;
892
893 ProgressObserver::setup( myProgress, "Refreshing repositories" , 1 );
894
895 auto r = std::move(infos)
896 | transform( [this, policy, myProgress]( const RepoInfo &info ) {
897
898 auto subProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Str() << _("Refreshing Repository: ") << info.alias(), 3 );
899
900 // helper callback in case the repo type changes on the remote
901 // do NOT capture by reference here, since this is possibly executed async
902 const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
903 // update probed type only for repos in system
904 for( const auto &repo : repos() ) {
905 if ( info.alias() == repo.alias() )
906 {
907 RepoInfo modifiedrepo = repo;
908 modifiedrepo.setType( repokind );
909 // don't modify .repo in refresh.
910 // modifyRepository( info.alias(), modifiedrepo );
911 break;
912 }
913 }
914 };
915
917
918 return
919 // make sure geoIP data is up 2 date, but ignore errors
921 | [sharedThis, info = info](auto) { return zyppng::repo::RefreshContext<ZyppContextRefType>::create( sharedThis->_zyppContext, info, sharedThis); }
922 | inspect( incProgress( subProgress ) )
923 | and_then( [policy, subProgress, cb = updateProbedType]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
924 refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
925 // in case probe detects a different repokind, update our internal repos
927
928 return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), ProgressObserver::makeSubTask( subProgress ) );
929 })
930 | inspect( incProgress( subProgress ) )
931 | and_then([subProgress]( repo::RefreshContextRef<ZyppContextRefType> ctx ) {
932
933 if ( ! isTmpRepo( ctx->repoInfo() ) )
934 ctx->repoManager()->reposManip(); // remember to trigger appdata refresh
935
936 return zyppng::RepoManagerWorkflow::buildCache ( std::move(ctx), CacheBuildPolicy::BuildIfNeeded, ProgressObserver::makeSubTask( subProgress ) );
937 })
938 | inspect( incProgress( subProgress ) )
939 | [ info = info, subProgress ]( expected<repo::RefreshContextRef<ZyppContextRefType>> result ) {
940 if ( result ) {
942 return std::make_pair(info, expected<void>::success() );
943 } else {
945 return std::make_pair(info, expected<void>::error( result.error() ) );
946 }
947 };
948 }
949 | [myProgress]( auto res ) {
951 return res;
952 }
953 );
954
955 return joinPipeline( _zyppContext, r );
956 }
957
964 template<typename ZyppContextRefType>
966 {
967 using namespace zyppng::operators;
968
969 RepoInfo::url_set allUrls;
970 std::transform( origin.begin (), origin.end(), std::back_inserter(allUrls), []( const zypp::OriginEndpoint &ep ){ return ep.url(); } );
971
974 | [this, origin=origin](auto) { return _zyppContext->provider()->prepareMedia( origin, zyppng::ProvideMediaSpec() ); }
975 | and_then( [this, path = path]( auto mediaHandle ) {
976 return RepoManagerWorkflow::probeRepoType( _zyppContext, std::move(mediaHandle), path );
977 }));
978 }
979
980 template<typename ZyppContextRefType>
981 expected<void> RepoManager<ZyppContextRefType>::buildCache( const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress )
982 {
983 using namespace zyppng::operators;
986 | and_then( [policy, myProgress]( repo::RefreshContextRef<ZyppContextRefType> refCtx ) {
987 return zyppng::RepoManagerWorkflow::buildCache ( std::move(refCtx), policy, myProgress );
988 })
989 | and_then([]( auto ){ return expected<void>::success(); })
990 );
991 }
992
993 template<typename ZyppContextRefType>
994 expected<RepoInfo> RepoManager<ZyppContextRefType>::addRepository(const RepoInfo &info, ProgressObserverRef myProgress, const zypp::TriBool & forcedProbe )
995 {
996 return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this<RepoManager<ZyppContextRefType>>(), info, std::move(myProgress), forcedProbe ) );
997 }
998
999 template<typename ZyppContextRefType>
1005
1006 template <typename ZyppContextRefType>
1011
1012 template <typename ZyppContextRefType>
1014 {
1015 try {
1016
1017 assert_alias( service ).unwrap();
1018
1019 // check if service already exists
1020 if ( hasService( service.alias() ) )
1022
1023 // Writable ServiceInfo is needed to save the location
1024 // of the .service file. Finaly insert into the service list.
1025 ServiceInfo toSave( service );
1026 saveService( toSave ).unwrap();
1027 _services.insert( toSave );
1028
1029 // check for credentials in Url
1030 zypp::UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1031
1032 MIL << "added service " << toSave.alias() << std::endl;
1033
1034 } catch ( ... ) {
1035 return expected<void>::error( std::current_exception () );
1036 }
1037
1038 return expected<void>::success();
1039 }
1040
1041 template<typename ZyppContextRefType>
1046
1050 template<typename ZyppContextRefType>
1052 {
1053 using namespace zyppng::operators;
1054 // copy the set of services since refreshService
1055 // can eventually invalidate the iterator
1056 ServiceSet servicesCopy( serviceBegin(), serviceEnd() );
1057
1058 // convert the set into a vector, transform needs a container with push_back support
1059 std::vector<ServiceInfo> servicesVec;
1060 std::copy( std::make_move_iterator(servicesCopy.begin()), std::make_move_iterator(servicesCopy.end()), std::back_inserter(servicesVec));
1061
1062 return joinPipeline( _zyppContext,
1063 std::move(servicesVec)
1064 | transform( [options_r, this]( ServiceInfo i ){ return RepoServicesWorkflow::refreshService( shared_this<RepoManager<ZyppContextRefType>>(), i, options_r ); } )
1065 | join()
1066 | collect()
1067 );
1068 }
1069
1071
1072 template <typename ZyppContextRefType>
1074 {
1075 try {
1076 MIL << "Going to delete service " << alias << std::endl;
1077
1078 const ServiceInfo & service = getService( alias );
1079
1080 zypp::Pathname location = service.filepath();
1081 if( location.empty() )
1082 {
1083 ZYPP_THROW(zypp::repo::ServiceException( service, _("Can't figure out where the service is stored.") ));
1084 }
1085
1086 ServiceSet tmpSet;
1088
1089 // only one service definition in the file
1090 if ( tmpSet.size() == 1 )
1091 {
1092 if ( zypp::filesystem::unlink(location) != 0 )
1093 {
1094 // TranslatorExplanation '%s' is a filename
1095 ZYPP_THROW(zypp::repo::ServiceException( service, zypp::str::form( _("Can't delete '%s'"), location.c_str() ) ));
1096 }
1097 MIL << alias << " successfully deleted." << std::endl;
1098 }
1099 else
1100 {
1102
1103 std::ofstream file(location.c_str());
1104 if( !file )
1105 {
1106 // TranslatorExplanation '%s' is a filename
1107 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), location.c_str() )));
1108 }
1109
1110 for_(it, tmpSet.begin(), tmpSet.end())
1111 {
1112 if( it->alias() != alias )
1113 it->dumpAsIniOn(file);
1114 }
1115
1116 MIL << alias << " successfully deleted from file " << location << std::endl;
1117 }
1118
1119 // now remove all repositories added by this service
1120 RepoCollector rcollector;
1122 boost::make_function_output_iterator( std::bind( &RepoCollector::collect, &rcollector, std::placeholders::_1 ) ) );
1123 // cannot do this directly in getRepositoriesInService - would invalidate iterators
1124 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
1125 removeRepository(*rit).unwrap();
1126
1127 return expected<void>::success();
1128
1129 } catch ( ... ) {
1130 return expected<void>::error( std::current_exception () );
1131 }
1132 }
1133
1134 template <typename ZyppContextRefType>
1135 expected<void> RepoManager<ZyppContextRefType>::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
1136 {
1137 try {
1138
1139 MIL << "Going to modify service " << oldAlias << std::endl;
1140
1141 // we need a writable copy to link it to the file where
1142 // it is saved if we modify it
1143 ServiceInfo service(newService);
1144
1145 if ( service.type() == zypp::repo::ServiceType::PLUGIN )
1146 {
1148 }
1149
1150 const ServiceInfo & oldService = getService(oldAlias);
1151
1152 zypp::Pathname location = oldService.filepath();
1153 if( location.empty() )
1154 {
1155 ZYPP_THROW(zypp::repo::ServiceException( oldService, _("Can't figure out where the service is stored.") ));
1156 }
1157
1158 // remember: there may multiple services being defined in one file:
1159 ServiceSet tmpSet;
1161
1163 std::ofstream file(location.c_str());
1164 for_(it, tmpSet.begin(), tmpSet.end())
1165 {
1166 if( *it != oldAlias )
1167 it->dumpAsIniOn(file);
1168 }
1169 service.dumpAsIniOn(file);
1170 file.close();
1171 service.setFilepath(location);
1172
1173 _services.erase(oldAlias);
1174 _services.insert(service);
1175 // check for credentials in Urls
1176 zypp::UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
1177
1178
1179 // changed properties affecting also repositories
1180 if ( oldAlias != service.alias() // changed alias
1181 || oldService.enabled() != service.enabled() ) // changed enabled status
1182 {
1183 std::vector<RepoInfo> toModify;
1184 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
1185 for_( it, toModify.begin(), toModify.end() )
1186 {
1187 if ( oldService.enabled() != service.enabled() )
1188 {
1189 if ( service.enabled() )
1190 {
1191 // reset to last refreshs state
1192 const auto & last = service.repoStates().find( it->alias() );
1193 if ( last != service.repoStates().end() )
1194 it->setEnabled( last->second.enabled );
1195 }
1196 else
1197 it->setEnabled( false );
1198 }
1199
1200 if ( oldAlias != service.alias() )
1201 it->setService(service.alias());
1202
1203 modifyRepository(it->alias(), *it).unwrap();
1204 }
1205 }
1206
1207 return expected<void>::success();
1208
1209 } catch ( ... ) {
1210 return expected<void>::error( std::current_exception () );
1211 }
1212
1214 }
1215
1216
1217 template <typename ZyppContextRefType>
1219 {
1220 try {
1221
1222 zypp::filesystem::assert_dir( _options.knownServicesPath );
1223 zypp::Pathname servfile = generateNonExistingName( _options.knownServicesPath,
1224 generateFilename( service ) );
1225 service.setFilepath( servfile );
1226
1227 MIL << "saving service in " << servfile << std::endl;
1228
1229 std::ofstream file( servfile.c_str() );
1230 if ( !file )
1231 {
1232 // TranslatorExplanation '%s' is a filename
1233 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), servfile.c_str() )));
1234 }
1235 service.dumpAsIniOn( file );
1236 MIL << "done" << std::endl;
1237
1238 return expected<void>::success();
1239
1240 } catch ( ... ) {
1241 return expected<void>::error( std::current_exception () );
1242 }
1243 }
1244
1260 template <typename ZyppContextRefType>
1262 const std::string & basefilename ) const
1263 {
1264 std::string final_filename = basefilename;
1265 int counter = 1;
1266 while ( zypp::PathInfo(dir + final_filename).isExist() )
1267 {
1268 final_filename = basefilename + "_" + zypp::str::numstring(counter);
1269 ++counter;
1270 }
1271 return dir + zypp::Pathname(final_filename);
1272 }
1273
1274 template <typename ZyppContextRefType>
1276 {
1277 try {
1278 zypp::Pathname productdatapath = rawproductdata_path_for_repoinfo( options, info ).unwrap();
1279
1280 zypp::repo::RepoType repokind = info.type();
1281 if ( repokind.toEnum() == zypp::repo::RepoType::NONE_e )
1282 // unknown, probe the local metadata
1283 repokind = probeCache( productdatapath );
1284 // if still unknown, just return
1285 if (repokind == zypp::repo::RepoType::NONE_e)
1286 return expected<void>::success();
1287
1289 switch ( repokind.toEnum() )
1290 {
1292 p = zypp::Pathname(productdatapath + "/repodata/repomd.xml");
1293 break;
1294
1296 p = zypp::Pathname(productdatapath + "/content");
1297 break;
1298
1300 p = zypp::Pathname(productdatapath + "/cookie");
1301 break;
1302
1304 default:
1305 break;
1306 }
1307
1308 // touch the file, ignore error (they are logged anyway)
1310 } catch ( ... ) {
1312 }
1313 return expected<void>::success();
1314 }
1315
1316 template<typename ZyppContextRefType>
1321
1322 template <typename ZyppContextRefType>
1327
1328 template <typename ZyppContextRefType>
1330 {
1331 try {
1332 zypp::Pathname dir = _options.knownServicesPath;
1333 std::list<zypp::Pathname> entries;
1334 if (zypp::PathInfo(dir).isExist())
1335 {
1336 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
1337 {
1338 // TranslatorExplanation '%s' is a pathname
1339 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
1340 }
1341
1342 //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
1343 for_(it, entries.begin(), entries.end() )
1344 {
1346 }
1347 }
1348
1350
1351 return expected<void>::success();
1352
1353 } catch ( ... ) {
1354 return expected<void>::error( std::current_exception () );
1355 }
1356
1357 }
1358
1359 namespace {
1366 inline void cleanupNonRepoMetadtaFolders( const zypp::Pathname & cachePath_r,
1367 const zypp::Pathname & defaultCachePath_r,
1368 const std::list<std::string> & repoEscAliases_r )
1369 {
1371 return;
1372
1373 if ( cachePath_r != defaultCachePath_r )
1374 return;
1375
1376 std::list<std::string> entries;
1377 if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
1378 {
1379 entries.sort();
1380 std::set<std::string> oldfiles;
1381 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
1382 std::inserter( oldfiles, oldfiles.end() ) );
1383
1384 // bsc#1178966: Files or symlinks here have been created by the user
1385 // for whatever purpose. It's our cache, so we purge them now before
1386 // they may later conflict with directories we need.
1387 zypp::PathInfo pi;
1388 for ( const std::string & old : oldfiles )
1389 {
1390 if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
1391 continue;
1392 pi( cachePath_r/old );
1393 if ( pi.isDir() )
1395 else
1397 }
1398 }
1399 }
1400 } // namespace
1401
1402 template <typename ZyppContextRefType>
1404 {
1405 try {
1406
1407 MIL << "start construct known repos" << std::endl;
1408
1409 if ( zypp::PathInfo(_options.knownReposPath).isExist() )
1410 {
1411 std::list<std::string> repoEscAliases;
1412 std::list<RepoInfo> orphanedRepos;
1413 for ( RepoInfo & repoInfo : repositories_in_dir( _zyppContext, _options.knownReposPath ) )
1414 {
1415 // set the metadata path for the repo
1416 repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo).unwrap() );
1417 // set the downloaded packages path for the repo
1418 repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo).unwrap() );
1419 // remember it
1420 _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
1421
1422 // detect orphaned repos belonging to a deleted service
1423 const std::string & serviceAlias( repoInfo.service() );
1424 if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
1425 {
1426 WAR << "Schedule orphaned service repo for deletion: " << repoInfo << std::endl;
1427 orphanedRepos.push_back( repoInfo );
1428 continue; // don't remember it in repoEscAliases
1429 }
1430
1431 repoEscAliases.push_back(repoInfo.escaped_alias());
1432 }
1433
1434 // Cleanup orphanded service repos:
1435 if ( ! orphanedRepos.empty() )
1436 {
1437 for ( const auto & repoInfo : orphanedRepos )
1438 {
1439 MIL << "Delete orphaned service repo " << repoInfo.alias() << std::endl;
1440 // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
1441 // %1% = service name
1442 // %2% = repository name
1443 JobReportHelper(_zyppContext).warning( zypp::str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'"))
1444 % repoInfo.service()
1445 % repoInfo.alias() );
1446 try {
1447 removeRepository( repoInfo ).unwrap();
1448 }
1449 catch ( const zypp::Exception & caugth )
1450 {
1452 }
1453 }
1454 }
1455
1456 // bsc#1210740: Don't cleanup if read-only mode was promised.
1458 // delete metadata folders without corresponding repo (e.g. old tmp directories)
1459 //
1460 // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise
1461 // we'd need somemagic file to identify zypp cache directories. Without this
1462 // we may easily remove user data (zypper --pkg-cache-dir . download ...)
1463 repoEscAliases.sort();
1464 cleanupNonRepoMetadtaFolders( _options.repoRawCachePath,
1465 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoMetadataPath() ),
1466 repoEscAliases );
1467 cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath,
1468 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoSolvfilesPath() ),
1469 repoEscAliases );
1470 // bsc#1204956: Tweak to prevent auto pruning package caches
1471 if ( autoPruneInDir( _options.repoPackagesCachePath ) )
1472 cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath,
1473 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoPackagesPath() ),
1474 repoEscAliases );
1475 }
1476 }
1477 MIL << "end construct known repos" << std::endl;
1478
1479 return expected<void>::success();
1480
1481 } catch ( ... ) {
1482 return expected<void>::error( std::current_exception () );
1483 }
1484 }
1485
1486 // explicitely intantiate the template types we want to work with
1487 template class RepoManager<SyncContextRef>;
1488 template class RepoManager<ContextRef>;
1489} // namespace zyppng
#define OUTS(V)
static const ValueType day
Definition Date.h:44
static Date now()
Return the current time.
Definition Date.h:78
Base class for Exception.
Definition Exception.h:153
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition Exception.cc:140
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
Writing the zypp history file.
Definition HistoryLog.h:57
void modifyRepository(const RepoInfo &oldrepo, const RepoInfo &newrepo)
Log certain modifications to a repository.
void addRepository(const RepoInfo &repo)
Log a newly added repository.
void removeRepository(const RepoInfo &repo)
Log recently removed repository.
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
endpoint_iterator end()
endpoint_iterator begin()
Represents a single, configurable network endpoint, combining a URL with specific access settings.
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r prefixed with root_r, unless it is already prefixed.
Definition Pathname.cc:272
What is known about a repository.
Definition RepoInfo.h:72
MirroredOriginSet repoOrigins() const
The repodata origins.
Definition RepoInfo.cc:697
repo::RepoType type() const
Type of repository,.
Definition RepoInfo.cc:750
void setBaseUrl(Url url)
Clears current base URL list and adds url.
Definition RepoInfo.cc:684
void setPackagesPath(const Pathname &path)
set the path where the local packages are stored
Definition RepoInfo.cc:720
url_set baseUrls() const
The complete set of repository urls as configured.
Definition RepoInfo.cc:777
bool requireStatusWithMediaFile() const
Returns true if this repository requires the media.1/media file to be included in the metadata status...
Definition RepoInfo.cc:1131
Url mirrorListUrl() const
Url of a file which contains a list of repository urls.
Definition RepoInfo.cc:753
std::ostream & dumpAsIniOn(std::ostream &str) const override
Write this RepoInfo object into str in a .repo file format.
Definition RepoInfo.cc:1003
void setMetadataPath(const Pathname &path)
Set the path where the local metadata is stored.
Definition RepoInfo.cc:717
void setType(const repo::RepoType &t)
set the repository type
Definition RepoInfo.cc:710
std::list< Url > url_set
Definition RepoInfo.h:108
bool repoOriginsEmpty() const
whether repo origins are available
Definition RepoInfo.cc:702
void cleanCacheDirGarbage(const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove any subdirectories of cache directories which no longer belong to any of known repositories.
void cleanMetadata(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local metadata.
void addService(const std::string &alias, const Url &url)
Adds a new service by its alias and URL.
void removeService(const std::string &alias)
Removes service specified by its name.
repo::ServiceType probeService(const Url &url) const
Probe the type or the service.
void cleanCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
clean local cache
void refreshServices(const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refreshes all enabled services.
void addRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds a repository to the list of known repositories.
void addRepositories(const Url &url, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Adds repositores from a repo file to the list of known repositories.
void refreshMetadata(const RepoInfo &info, RawMetadataRefreshPolicy policy=RefreshIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local raw cache.
void refreshGeoIp(const RepoInfo::url_set &urls)
void refreshService(const std::string &alias, const RefreshServiceOptions &options_r=RefreshServiceOptions())
Refresh specific service.
void modifyRepository(const std::string &alias, const RepoInfo &newinfo, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Modify repository attributes.
void removeRepository(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Remove the best matching repository from known repos list.
RepoInfo getRepositoryInfo(const std::string &alias, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Find a matching repository info.
RefreshCheckStatus checkIfToRefreshMetadata(const RepoInfo &info, const Url &url, RawMetadataRefreshPolicy policy=RefreshIfNeeded)
Checks whether to refresh metadata for specified repository and url.
void buildCache(const RepoInfo &info, CacheBuildPolicy policy=BuildIfNeeded, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Refresh local cache.
RepoManager(RepoManagerOptions options=RepoManagerOptions())
void loadFromCache(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Load resolvables into the pool.
void cleanPackages(const RepoInfo &info, const ProgressData::ReceiverFnc &progressrcv=ProgressData::ReceiverFnc())
Clean local package cache.
RepoStatus metadataStatus(const RepoInfo &info) const
Status of local metadata.
void modifyService(const std::string &oldAlias, const ServiceInfo &service)
Modifies service file (rewrites it with new values) and underlying repositories if needed.
repo::RepoType probe(const Url &url, const Pathname &path) const
Probe repo metadata type.
Track changing files or directories.
Definition RepoStatus.h:41
static RepoStatus fromCookieFileUseMtime(const Pathname &path)
Reads the status from a cookie file but uses the files mtime.
bool empty() const
Whether the status is empty (empty checksum)
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
Definition Repository.cc:38
Service data.
Definition ServiceInfo.h:37
repo::ServiceType type() const
Service type.
const RepoStates & repoStates() const
Access the remembered repository states.
Url url() const
The service url.
std::ostream & dumpAsIniOn(std::ostream &str) const override
Writes ServiceInfo to stream in ".service" format.
Extract credentials in Url authority and store them via CredentialManager.
bool collect(const Url &url_r)
Remember credentials stored in URL authority leaving the password in url_r.
Url manipulation class.
Definition Url.h:93
bool isValid() const
Verifies the Url.
Definition Url.cc:507
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
const std::string & asString() const
Return current Pathname as String.
Definition PathInfo.h:253
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition Pathname.h:175
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:126
const char * c_str() const
String representation.
Definition Pathname.h:112
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Read repository data from a .repo file.
Read service data from a .service file.
Repository already exists and some unique attribute can't be duplicated.
Exception for repository handling.
std::string label() const
Label for use in messages for the user interface.
void setFilepath(const Pathname &filename)
set the path to the .repo file
void setAlias(const std::string &alias)
set the repository alias
Pathname filepath() const
File where this repo was read from.
bool enabled() const
If enabled is false, then this repository must be ignored as if does not exists, except when checking...
std::string alias() const
unique identifier for this source.
thrown when it was impossible to determine one url for this repo.
The repository cache is not built yet so you can't create the repostories from the cache.
thrown when it was impossible to match a repository
Service already exists and some unique attribute can't be duplicated.
Base Exception for service handling.
Lightweight repository attribute value lookup.
Definition LookupAttr.h:265
static const SolvAttr repositoryToolVersion
Definition SolvAttr.h:193
Regular expression.
Definition Regex.h:95
std::shared_ptr< T > shared_this() const
Definition base.h:113
bool error(std::string msg_r, UserData userData_r=UserData())
send error text
bool warning(std::string msg_r, UserData userData_r=UserData())
send warning text
static void increase(ProgressObserverRef progress, double inc=1.0, const std::optional< std::string > &newLabel={})
static ProgressObserverRef makeSubTask(ProgressObserverRef parentProgress, float weight=1.0, const std::string &label=std::string(), int steps=100)
static void setup(ProgressObserverRef progress, const std::string &label=std::string(), int steps=100)
static void finish(ProgressObserverRef progress, ProgressObserver::FinishResult result=ProgressObserver::Success)
The RepoManager class Provides knowledge and methods to maintain repo settings and metadata for a giv...
ServiceInfo getService(const std::string &alias) const
std::set< ServiceInfo > ServiceSet
ServiceInfo typedefs.
ServiceConstIterator serviceBegin() const
expected< void > cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress=nullptr, bool isAutoClean=false)
static expected< void > touchIndexFile(const RepoInfo &info, const RepoManagerOptions &options)
expected< RepoInfo > getRepositoryInfo(const std::string &alias)
expected< RepoInfo > modifyRepository(const std::string &alias, const RepoInfo &newinfo_r, ProgressObserverRef myProgress=nullptr)
void getRepositoriesInService(const std::string &alias, OutputIterator out) const
zypp::RepoManagerFlags::RawMetadataRefreshPolicy RawMetadataRefreshPolicy
ServiceConstIterator serviceEnd() const
static zypp::repo::RepoType probeCache(const zypp::Pathname &path_r)
Probe Metadata in a local cache directory.
expected< void > init_knownServices()
expected< RepoInfo > addProbedRepository(RepoInfo info, zypp::repo::RepoType probedType)
const RepoSet & repos() const
expected< bool > isCached(const RepoInfo &info) const
expected< void > initialize()
zypp::Pathname generateNonExistingName(const zypp::Pathname &dir, const std::string &basefilename) const
Generate a non existing filename in a directory, using a base name.
expected< void > buildCache(const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress=nullptr)
RepoSet::const_iterator RepoConstIterator
RepoManagerOptions _options
expected< void > init_knownRepositories()
expected< void > cleanCache(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
zypp::DefaultIntegral< bool, false > _reposDirty
expected< void > cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
static expected< RepoStatus > metadataStatus(const RepoInfo &info, const RepoManagerOptions &options)
expected< void > removeRepository(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
bool hasService(const std::string &alias) const
RepoConstIterator repoBegin() const
expected< void > saveService(ServiceInfo &service) const
bool hasRepo(const std::string &alias) const
std::string generateFilename(const RepoInfo &info) const
RepoConstIterator repoEnd() const
zypp::RepoManagerFlags::RefreshServiceOptions RefreshServiceOptions
const RepoManagerOptions & options() const
zypp::RepoManagerFlags::CacheBuildPolicy CacheBuildPolicy
ContextRefType _zyppContext
RepoSet & reposManip()
Functor collecting ServiceInfos into a ServiceSet.
static expected success(ConsParams &&...params)
Definition expected.h:115
static expected error(ConsParams &&...params)
Definition expected.h:126
static expected< repo::RefreshContextRef< ZyppContextRefType > > create(ZyppContextRefType zyppContext, zypp::RepoInfo info, RepoManagerRef< ContextRefType > repoManager)
Definition refresh.cc:32
SignalProxy< void(zypp::repo::RepoType)> sigProbedTypeChanged()
Definition refresh.cc:158
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
Definition Arch.h:364
String related utilities and Regular expression matching.
RefreshCheckStatus
Possibly return state of RepoManager::checkIfToRefreshMetadata function.
Namespace intended to collect all environment variables we use.
Definition Env.h:25
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition PathInfo.cc:417
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:610
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:324
int touch(const Pathname &path)
Change file's modification and access times.
Definition PathInfo.cc:1242
std::string & replaceAll(std::string &str_r, const std::string &from_r, const std::string &to_r)
Replace all occurrences of from_r with to_r in str_r (inplace).
Definition String.cc:333
std::string numstring(char n, int w=0)
Definition String.h:290
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition Regex.h:70
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:500
Url details namespace.
Definition UrlBase.cc:58
std::string join(const ParamVec &pvec, const std::string &psep)
Join parameter vector to a string.
Definition UrlUtils.cc:252
std::ostream & operator<<(std::ostream &str, const SerialNumber &obj)
std::string asString(const Patch::Category &obj)
Definition Patch.cc:122
AsyncOpRef< expected< zypp::repo::RepoType > > probeRepoType(ContextRef ctx, AsyncLazyMediaHandle medium, zypp::Pathname path, std::optional< zypp::Pathname > targetPath)
AsyncOpRef< expected< repo::RefreshCheckStatus > > checkIfToRefreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
AsyncOpRef< expected< void > > refreshGeoIPData(ContextRef ctx, RepoInfo::url_set urls)
AsyncOpRef< expected< void > > addRepositories(AsyncRepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress)
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > refreshMetadata(repo::AsyncRefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
AsyncOpRef< expected< RepoInfo > > addRepository(AsyncRepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress, const zypp::TriBool &forcedProbe)
AsyncOpRef< expected< repo::AsyncRefreshContextRef > > buildCache(repo::AsyncRefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
AsyncOpRef< expected< void > > refreshService(AsyncRepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
AsyncOpRef< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
auto incProgress(ProgressObserverRef progressObserver, double progrIncrease=1.0, std::optional< std::string > newStr={})
zypp::RepoManagerFlags::RawMetadataRefreshPolicy RawMetadataRefreshPolicy
Definition refresh.h:33
Exp mtry(F &&f, Args &&...args)
Definition mtry.h:28
bool isTmpRepo(const RepoInfo &info_r)
Whether repo is not under RM control and provides its own methadata paths.
Definition repomanager.h:55
expected< void > assert_urls(const RepoInfo &info)
std::list< RepoInfo > repositories_in_dir(ZContextRef zyppContext, const zypp::Pathname &dir)
List of RepoInfo's from a directory.
std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
Generate a related filename from a repo/service infos alias.
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:397
expected< zypp::Pathname > rawcache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw cache path for a repository, this is usually /var/cache/zypp/alias.
expected< void > assert_alias(const RepoInfo &info)
Definition repomanager.h:58
ResultType or_else(const expected< T, E > &exp, Function &&f)
Definition expected.h:463
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition expected.h:423
auto joinPipeline(ContextRef ctx, AsyncOpRef< T > res)
Definition context.h:81
expected< zypp::Pathname > solv_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the solv cache path for a repository.
expected< std::list< RepoInfo > > repositories_in_file(const zypp::Pathname &file)
Reads RepoInfo's from a repo file.
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::enable_if_t<!std::is_same_v< void, T >, expected< Container< T >, E > > collect(Container< expected< T, E >, CArgs... > &&in)
Definition expected.h:501
expected< zypp::Pathname > packagescache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the packages cache path for a repository.
expected< zypp::Pathname > rawproductdata_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the raw product metadata path for a repository, this is inside the raw cache dir,...
Container< Ret > transform(Container< Msg, CArgs... > &&val, Transformation &&transformation)
Definition transform.h:31
expected< T, E > inspect(expected< T, E > exp, Function &&f)
Definition expected.h:531
bool autoPruneInDir(const zypp::Pathname &path_r)
bsc#1204956: Tweak to prevent auto pruning package caches.
Repo manager settings.
Repository type enumeration.
Definition RepoType.h:29
static const RepoType YAST2
Definition RepoType.h:31
Type toEnum() const
Definition RepoType.h:49
static const RepoType RPMMD
Definition RepoType.h:30
static const RepoType NONE
Definition RepoType.h:33
static const RepoType RPMPLAINDIR
Definition RepoType.h:32
Convenient building of std::string with boost::format.
Definition String.h:254
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213
Url::asString() view options.
Definition UrlBase.h:41
Simple callback to collect the results.
std::string targetDistro
bool collect(const RepoInfo &repo)
#define zypp_defer
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:27
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:463
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define MIL
Definition Logger.h:100
#define WAR
Definition Logger.h:101
#define ZYPP_PRIVATE_CONSTR_ARG
Definition zyppglobal.h:160