libzypp 17.38.15
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#include <solv/repo_solv.h>
15
16#include <algorithm>
17#include <zypp/Digest.h>
18
22#include <zypp-core/ng/pipelines/MTry>
23#include <zypp-core/ng/pipelines/Transform>
25#include <zypp-core/ng/ui/ProgressObserver>
27#include <zypp/HistoryLog.h>
28#include <zypp/ZConfig.h>
29#include <zypp/ZYppCallbacks.h>
33#include <zypp/sat/Pool.h>
37
42
43#include <fstream>
44#include <utility>
45
46#undef ZYPP_BASE_LOGGER_LOGGROUP
47#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
48
50 bool IGotIt(); // in readonly-mode
51}
52
53
54namespace zyppng
55{
56 namespace env
57 {
60 {
61 const char * env = getenv("ZYPP_PLUGIN_APPDATA_FORCE_COLLECT");
62 return( env && zypp::str::strToBool( env, true ) );
63 }
64 } // namespace env
65
66 namespace {
72 inline void cleanupNonRepoMetadataFolders( const zypp::Pathname & cachePath_r,
73 const zypp::Pathname & defaultCachePath_r,
74 const std::list<std::string> & repoEscAliases_r )
75 {
76 if ( cachePath_r != defaultCachePath_r )
77 return;
78
79 std::list<std::string> entries;
80 if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
81 {
82 entries.sort();
83 std::set<std::string> oldfiles;
84 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
85 std::inserter( oldfiles, oldfiles.end() ) );
86
87 // bsc#1178966: Files or symlinks here have been created by the user
88 // for whatever purpose. It's our cache, so we purge them now before
89 // they may later conflict with directories we need.
91 for ( const std::string & old : oldfiles )
92 {
93 if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
94 continue;
95 pi( cachePath_r/old );
96 if ( pi.isDir() )
98 else
100 }
101 }
102 }
103 } // namespace
104
106 {
107 switch ( obj ) {
108#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
109 OUTS( RefreshIfNeeded );
110 OUTS( RefreshForced );
111 OUTS( RefreshIfNeededIgnoreDelay );
112#undef OUTS
113 }
114 return str;
115 }
116
117 std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::RefreshCheckStatus obj )
118 {
119 switch ( obj ) {
120#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
121 OUTS( REFRESH_NEEDED );
122 OUTS( REPO_UP_TO_DATE );
123 OUTS( REPO_CHECK_DELAYED );
124#undef OUTS
125 }
126 return str;
127 }
128
129 std::ostream & operator<<( std::ostream & str, zypp::RepoManagerFlags::CacheBuildPolicy obj )
130 {
131 switch ( obj ) {
132#define OUTS(V) case zypp::RepoManagerFlags::V: str << #V; break
133 OUTS( BuildIfNeeded );
134 OUTS( BuildForced );
135#undef OUTS
136 }
137 return str;
138 }
139
140
141 std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
142 {
143 std::string filename( alias_r );
144 // replace slashes with underscores
145 zypp::str::replaceAll( filename, "/", "_" );
146
147 filename = zypp::Pathname(filename).extend("."+stem_r).asString();
148 MIL << "generating filename for " << stem_r << " [" << alias_r << "] : '" << filename << "'" << std::endl;
149 return filename;
150 }
151
153 {
154 // skip repositories meant for other distros than specified
155 if (!targetDistro.empty()
156 && !repo.targetDistribution().empty()
157 && repo.targetDistribution() != targetDistro)
158 {
159 MIL
160 << "Skipping repository meant for '" << repo.targetDistribution()
161 << "' distribution (current distro is '"
162 << targetDistro << "')." << std::endl;
163
164 return true;
165 }
166
167 repos.push_back(repo);
168 return true;
169 }
170
172 {
173 try {
174 MIL << "repo file: " << file << std::endl;
175 RepoCollector collector;
176 zypp::parser::RepoFileReader parser( file, std::bind( &RepoCollector::collect, &collector, std::placeholders::_1 ) );
177 return expected<std::list<RepoInfo>>::success( std::move(collector.repos) );
178 } catch ( ... ) {
180 }
181 }
182
192 template <typename ZContextRef>
193 std::list<RepoInfo> repositories_in_dir( ZContextRef zyppContext, const zypp::Pathname &dir )
194 {
195 MIL << "directory " << dir << std::endl;
196 std::list<RepoInfo> repos;
197 bool nonroot( geteuid() != 0 );
198 if ( nonroot && ! zypp::PathInfo(dir).userMayRX() )
199 {
200 JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo directory '%1%': Permission denied")) % dir );
201 }
202 else
203 {
204 std::list<zypp::Pathname> entries;
205 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
206 {
207 // TranslatorExplanation '%s' is a pathname
208 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
209 }
210
211 zypp::str::regex allowedRepoExt("^\\.repo(_[0-9]+)?$");
212 for ( std::list<zypp::Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
213 {
214 if ( zypp::str::regex_match(it->extension(), allowedRepoExt) )
215 {
216 if ( nonroot && ! zypp::PathInfo(*it).userMayR() )
217 {
218 JobReportHelper(zyppContext).warning( zypp::str::Format(_("Cannot read repo file '%1%': Permission denied")) % *it );
219 }
220 else
221 {
222 const std::list<RepoInfo> tmp( repositories_in_file( *it ).unwrap() );
223 repos.insert( repos.end(), tmp.begin(), tmp.end() );
224 }
225 }
226 }
227 }
228 return repos;
229 }
230
232 {
233 if ( info.repoOriginsEmpty() )
236 }
237
238 bool autoPruneInDir(const zypp::Pathname &path_r)
239 { return not zypp::PathInfo(path_r/".no_auto_prune").isExist(); }
240
241
243 : _zyppContext( std::move(zyppCtx) )
244 , _options( std::move(opt) )
245 , _pluginRepoverification( _options.pluginsPath / "repoverification",
246 _options.rootDir)
247 {
248
249 }
250
252 {
253 // trigger appdata refresh if some repos change
255 && geteuid() == 0 && ( _options.rootDir.empty() || _options.rootDir == "/" ) )
256 {
257 try {
258 std::list<zypp::Pathname> entries;
259 zypp::filesystem::readdir( entries, _options.pluginsPath/"appdata", false );
260 if ( ! entries.empty() )
261 {
263 cmd.push_back( "<" ); // discard stdin
264 cmd.push_back( ">" ); // discard stdout
265 cmd.push_back( "PROGRAM" ); // [2] - fix index below if changing!
266 for ( const auto & rinfo : repos() )
267 {
268 if ( ! rinfo.enabled() )
269 continue;
270 cmd.push_back( "-R" );
271 cmd.push_back( rinfo.alias() );
272 cmd.push_back( "-t" );
273 cmd.push_back( rinfo.type().asString() );
274 cmd.push_back( "-p" );
275 cmd.push_back( (rinfo.metadataPath()/rinfo.path()).asString() ); // bsc#1197684: path to the repodata/ directory inside the cache
276 }
277
278 for_( it, entries.begin(), entries.end() )
279 {
280 zypp::PathInfo pi( *it );
281 //DBG << "/tmp/xx ->" << pi << endl;
282 if ( pi.isFile() && pi.userMayRX() )
283 {
284 // trigger plugin
285 cmd[2] = pi.asString(); // [2] - PROGRAM
287 }
288 }
289 }
290 }
291 catch (...) {} // no throw in dtor
292 }
293 }
294
295
297 {
298 using namespace zyppng::operators;
299 return
301 | and_then( [this](){ return init_knownRepositories(); } );
302 }
303
304
306 {
307 return _options;
308 }
309
310
312 {
313 try {
314 using namespace zyppng::operators;
315
316 // ATTENTION when making this pipeline async
317 // consider moving it into a workflow object
318 // this var is caputured by ref to modify it from
319 // inside the pipeline, which would break.
320 zypp::Pathname mediarootpath;
321
323 | and_then( [&]( zypp::Pathname mrPath ) {
324 mediarootpath = std::move(mrPath);
326 })
327 | and_then( [&]( zypp::Pathname productdatapath ) {
328 zypp::repo::RepoType repokind = info.type();
329 // If unknown, probe the local metadata
330 if ( repokind == zypp::repo::RepoType::NONE )
331 repokind = probeCache( productdatapath );
332
333 // NOTE: The calling code expects an empty RepoStatus being returned
334 // if the metadata cache is empty. So additional components like the
335 // RepoInfos status are joined after the switch IFF the status is not
336 // empty.huhu
337 RepoStatus status;
338 switch ( repokind.toEnum() )
339 {
341 status = RepoStatus( productdatapath/"repodata/repomd.xml");
342 if ( info.requireStatusWithMediaFile() )
343 status = status && RepoStatus( mediarootpath/"media.1/media" );
344 break;
345
347 status = RepoStatus( productdatapath/"content" ) && RepoStatus( mediarootpath/"media.1/media" );
348 break;
349
351 // Dir status at last refresh. Plaindir uses the cookiefile as pseudo metadata index file.
352 // It gets touched if the refresh check finds the data being up-to-date. That's why we use
353 // the files mtime as timestamp (like the RepoStatus ctor in the other cases above).
354 status = RepoStatus::fromCookieFileUseMtime( productdatapath/"cookie" );
355 break;
356
358 // Return default RepoStatus in case of RepoType::NONE
359 // indicating it should be created?
360 // ZYPP_THROW(RepoUnknownTypeException());
361 break;
362 }
363
364 if ( ! status.empty() )
365 status = status && RepoStatus( info );
366
367 return expected<RepoStatus>::success(status);
368 });
369 } catch (...) {
371 }
372 }
373
374
379
380
381 expected<void> RepoManager::cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress )
382 {
383 try {
384
385 ProgressObserver::setup( myProgress, _("Cleaning metadata"), 100 );
386 ProgressObserver::start( myProgress );
387 zypp::filesystem::recursive_rmdir( _zyppContext->config().geoipCachePath() );
388 ProgressObserver::setCurrent ( myProgress, 50 );
390 ProgressObserver::finish ( myProgress );
391
392 } catch ( ... ) {
395 }
397 }
398
399
400 expected<void> RepoManager::cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress, bool isAutoClean )
401 {
402 try {
403 ProgressObserver::setup( myProgress, _("Cleaning packages"), 100 );
404 ProgressObserver::start( myProgress );
405
406 // bsc#1204956: Tweak to prevent auto pruning package caches
408 if ( not isAutoClean || autoPruneInDir( rpc.dirname() ) )
410
411 ProgressObserver::finish ( myProgress );
412
413 } catch (...) {
416 }
417
419 }
420
426
428 {
429 MIL << "going to probe the cached repo at " << path_r << std::endl;
430
432
433 if ( zypp::PathInfo(path_r/"/repodata/repomd.xml").isFile() )
435 else if ( zypp::PathInfo(path_r/"/content").isFile() )
437 else if ( zypp::PathInfo(path_r/"/cookie").isFile() )
439
440 MIL << "Probed cached type " << ret << " at " << path_r << std::endl;
441 return ret;
442 }
443
444
445 expected<void> RepoManager::cleanCacheDirGarbage( ProgressObserverRef myProgress )
446 {
447 try {
448 MIL << "Going to clean up garbage in cache dirs" << std::endl;
450
451 std::list<zypp::Pathname> cachedirs;
452 cachedirs.push_back(_options.repoRawCachePath);
453 cachedirs.push_back(_options.repoPackagesCachePath);
454 cachedirs.push_back(_options.repoSolvCachePath);
455
456 ProgressObserver::setup( myProgress, _("Cleaning up cache dirs"), cachedirs.size() );
457 ProgressObserver::start( myProgress );
458
459 for( const auto &dir : cachedirs )
460 {
461 // increase progress on end of every iteration
462 zypp_defer {
463 ProgressObserver::increase( myProgress );
464 };
465
466 if ( zypp::PathInfo(dir).isExist() )
467 {
468 std::list<zypp::Pathname> entries;
469 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
470 // TranslatorExplanation '%s' is a pathname
471 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
472
473 if ( !entries.size() )
474 continue;
475
476 auto dirProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Format( _("Cleaning up directory: %1%") ) % dir, entries.size() );
477 for( const auto &subdir : entries )
478 {
479 // if it does not belong known repo, make it disappear
480 bool found = false;
481 for_( r, repoBegin(), repoEnd() )
482 if ( subdir.basename() == r->escaped_alias() )
483 { found = true; break; }
484
485 if ( ! found && ( zypp::Date::now()-zypp::PathInfo(subdir).mtime() > zypp::Date::day ) )
487
488 ProgressObserver::increase( dirProgress );
489 }
490 ProgressObserver::finish( dirProgress );
491 }
492 }
493 } catch (...) {
494 // will finish all subprogress children
497 }
498 ProgressObserver::finish ( myProgress );
500 }
501
502
503 expected<void> RepoManager::cleanCache(const RepoInfo &info, ProgressObserverRef myProgress )
504 {
505 try {
506 ProgressObserver::setup( myProgress, _("Cleaning cache"), 100 );
507 ProgressObserver::start( myProgress );
508
509 MIL << "Removing raw metadata cache for " << info.alias() << std::endl;
511 cleanPoolSnapshot(); // derived from the solv caches we just dropped
512
513 ProgressObserver::finish( myProgress );
515
516 } catch (...) {
517 // will finish all subprogress children
520 }
521 }
522
523
524 namespace {
525 // On by default; ZYPP_POOL_SNAPSHOT=0 disables.
526 bool poolSnapshotEnabled()
527 {
528 const char * e = ::getenv( "ZYPP_POOL_SNAPSHOT" );
529 return !( e && strcmp( e, "0" ) == 0 );
530 }
531 }
532
534 { return _options.repoCachePath / "pool.snapshot"; }
535
537 {
538 // The snapshot is derived from the solv caches, so it is garbage as
539 // soon as any of them changes. It is bigger than all of them together,
540 // so leaving it behind on 'zypper clean' would be surprising.
541 const zypp::Pathname & snapshot { poolSnapshotPath() };
542 if ( zypp::PathInfo( snapshot, zypp::PathInfo::LSTAT ).isExist() )
543 {
544 MIL << "Removing pool snapshot " << snapshot << std::endl;
545 zypp::filesystem::unlink( snapshot );
546 }
547 // plus anything a writer left behind when it was killed
548 std::list<zypp::Pathname> entries;
549 if ( zypp::filesystem::readdir( entries, _options.repoCachePath, false ) == 0 )
550 {
551 for ( const zypp::Pathname & entry : entries )
552 if ( zypp::str::hasPrefix( entry.basename(), "pool.snapshot.new." ) )
553 {
554 MIL << "Removing leftover " << entry << std::endl;
556 }
557 }
558 }
559
561 {
562 // hash over the sorted aliases and their solv cookie files: any
563 // refresh or change of the repo set invalidates the snapshot,
564 // as does a libsolv or architecture change.
565 //
566 // NOTE: systemArchitecture() is only settled once the target has
567 // been initialized, so a caller which loads repos before doing that
568 // computes a different cookie for the same caches. See
569 // sat::Pool::setSnapshotCandidate.
570 std::vector<std::string> aliases;
571 std::vector<zypp::Pathname> cookiefiles;
572 for ( const RepoInfo & info : repos() )
573 {
574 if ( ! info.enabled() )
575 continue;
576 try {
577 cookiefiles.push_back( solv_path_for_repoinfo( _options, info ).unwrap() / "cookie" );
578 aliases.push_back( info.alias() );
579 } catch (...) {
580 return std::string();
581 }
582
583 }
584 aliases.push_back( "@System" );
585 cookiefiles.push_back( _options.repoSolvCachePath / "@System" / "cookie" );
586 // sort both by alias
587 std::vector<size_t> idx( aliases.size() );
588 for ( size_t n = 0; n < idx.size(); n++ ) idx[n] = n;
589 std::sort( idx.begin(), idx.end(), [&]( size_t a, size_t b ){ return aliases[a] < aliases[b]; } );
590
591 zypp::Digest dig;
592 if ( ! dig.create( "sha256" ) )
593 return std::string();
594 // The libsolv actually in use, not the one libzypp was compiled
595 // against: a libsolv update alone can change the solv format or the
596 // set of preinterned knownids, and would otherwise leave a snapshot
597 // that maps no more but still looks fresh.
598 const std::string version { std::string(::solv_toolversion) + " " + ::solv_version };
599 dig.update( version.c_str(), version.size() + 1 );
600 const std::string & arch { zypp::ZConfig::instance().systemArchitecture().asString() };
601 dig.update( arch.c_str(), arch.size() );
602 for ( size_t n : idx )
603 {
604 std::ifstream is( cookiefiles[n].c_str() );
605 std::string content { std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>() };
606 if ( content.empty() )
607 {
608 if ( aliases[n] != "@System" )
609 {
610 // An enabled repo without a solv cache (added but never
611 // refreshed) leaves the snapshot describing a repo set that is
612 // not the one this run will load, so it cannot be used at all.
613 MIL << "Not using the pool snapshot: repo " << aliases[n] << " has no solv cache" << std::endl;
614 return std::string();
615 }
616 {
617 // No target solv cache yet, so there is no cookie to hash.
618 // Safe: TargetImpl::load then builds the cache, which makes
619 // the cookie file appear and changes this digest, and it
620 // erases and reloads the system repo rather than taking it
621 // from a snapshot. Once a cache exists, any rpmdb change
622 // rewrites the cookie and invalidates the snapshot.
623 continue;
624 }
625 }
626 dig.update( aliases[n].c_str(), aliases[n].size() + 1 );
627 dig.update( content.c_str(), content.size() );
628 }
629 return dig.digest();
630 }
631
633 {
634 if ( _poolSnapshotState )
635 return _poolSnapshotState > 0;
637 if ( ! poolSnapshotEnabled() )
638 return false;
639 std::string cookie { poolSnapshotCookie() };
640 if ( cookie.empty() )
641 return false;
643 std::vector<std::string> aliases;
644 for ( const RepoInfo & info : repos() )
645 if ( info.enabled() )
646 aliases.push_back( info.alias() );
647 aliases.push_back( "@System" );
648 std::sort( aliases.begin(), aliases.end() );
649 auto pool { _zyppContext->satPool() };
650 if ( ! pool.reposEmpty() )
651 {
652 // pool_snapshot_map() needs a virgin pool, so a run which loaded
653 // something (typically the target) before the first repo can never
654 // map one. Writing one would produce a file that same run could
655 // never use - and it would do so again after every refresh.
656 MIL << "Not using the pool snapshot: the pool already holds repos, "
657 "load the repos before the target to make use of it" << std::endl;
658 return false;
659 }
660 pool.setSnapshotCandidate( path, cookie, aliases ); // arm writing after a normal load
661 if ( pool.mapSnapshot( path, cookie ) )
663 return _poolSnapshotState > 0;
664 }
665
667 {
668 if ( _poolIdsReserved )
669 return;
670 _poolIdsReserved = true;
671 unsigned numid = 0, numrel = 0;
672 for ( const RepoInfo & info : repos() )
673 {
674 if ( ! info.enabled() )
675 continue;
676 zypp::Pathname solvfile;
677 try {
678 solvfile = solv_path_for_repoinfo( _options, info ).unwrap() / "solv";
679 } catch (...) {
680 continue;
681 }
682 FILE * fp = ::fopen( solvfile.c_str(), "re" );
683 if ( ! fp )
684 continue;
685 unsigned nid = 0, nrel = 0;
686 if ( ::solv_read_idcounts( fp, &nid, &nrel ) == 0 )
687 {
688 numid += nid;
689 numrel += nrel;
690 }
691 ::fclose( fp );
692 }
693 if ( numid || numrel )
694 {
695 MIL << "Reserving pool ids for " << numid << " strings, " << numrel << " rels" << std::endl;
696 _zyppContext->satPool().reserveIds( numid, numrel );
697 }
698 }
699
700 expected<void> RepoManager::loadFromCache( const RepoInfo & info, ProgressObserverRef myProgress )
701 {
702 using namespace zyppng::operators;
703 return zyppng::mtry( [this, info, myProgress](){
704 ProgressObserver::setup( myProgress, _("Loading from cache"), 3 );
705 // Repos of a mapped snapshot are claimed one loadFromCache at a
706 // time; hold this so a pool query from a progress callback does
707 // not erase the ones still to come.
709 ProgressObserver::start( myProgress );
710
712
713 if ( tryLoadPoolSnapshot() )
714 {
715 zypp::Repository repo = _zyppContext->satPool().reposFind( info.alias() );
716 if ( repo )
717 {
718 MIL << "Repo " << info.alias() << " provided by the pool snapshot" << std::endl;
719 repo.setInfo( info );
720 ProgressObserver::increase( myProgress );
721 ProgressObserver::increase( myProgress );
722 return;
723 }
724 }
725
727 zypp::Pathname solvfile = solv_path_for_repoinfo(_options, info).unwrap() / "solv";
728
729 if ( ! zypp::PathInfo(solvfile).isExist() )
731
732 _zyppContext->satPool().reposErase( info.alias() );
733
734 ProgressObserver::increase ( myProgress );
735
736 zypp::Repository repo = _zyppContext->satPool().addRepoSolv( solvfile, info );
737
738 ProgressObserver::increase ( myProgress );
739
740 // test toolversion in order to rebuild solv file in case
741 // it was written by a different libsolv-tool parser.
742 const std::string & toolversion( zypp::sat::LookupRepoAttr( zypp::sat::SolvAttr::repositoryToolVersion, repo ).begin().asString() );
743 if ( toolversion != LIBSOLV_TOOLVERSION ) {
744 repo.eraseFromPool();
745 ZYPP_THROW(zypp::Exception(zypp::str::Str() << "Solv-file was created by '"<<toolversion<<"'-parser (want "<<LIBSOLV_TOOLVERSION<<")."));
746 }
747 })
748 | or_else( [this, info, myProgress]( std::exception_ptr exp ) {
749 ZYPP_CAUGHT( exp );
750 MIL << "Try to handle exception by rebuilding the solv-file" << std::endl;
751 return cleanCache( info, ProgressObserver::makeSubTask( myProgress ) )
752 | and_then([this, info, myProgress]{
754 })
755 | and_then( mtry([this, info = info]{
756 _zyppContext->satPool().addRepoSolv( solv_path_for_repoinfo(_options, info).unwrap() / "solv", info );
757 }));
758 })
759 | and_then([myProgress]{
760 ProgressObserver::finish ( myProgress );
762 })
763 | or_else([myProgress]( auto ex ){
765 return expected<void>::error(ex);
766 })
767 ;
768 }
769
770
772 {
773 try {
774 auto tosave = info;
775
776 // assert the directory exists
778
780 _options.knownReposPath, generateFilename(tosave));
781 // now we have a filename that does not exists
782 MIL << "Saving repo in " << repofile << std::endl;
783
784 std::ofstream file(repofile.c_str());
785 if (!file)
786 {
787 // TranslatorExplanation '%s' is a filename
788 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), repofile.c_str() )));
789 }
790
791 tosave.dumpAsIniOn(file);
792 tosave.setFilepath(repofile);
793 tosave.setMetadataPath( rawcache_path_for_repoinfo( _options, tosave ).unwrap() );
794 tosave.setPackagesPath( packagescache_path_for_repoinfo( _options, tosave ).unwrap() );
795 reposManip().insert(tosave);
796
797 // check for credentials in base Urls
798 zypp::UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
799
800 zypp::HistoryLog(_options.rootDir).addRepository(tosave);
801
802 // return the new repoinfo
803 return expected<RepoInfo>::success( tosave );
804
805 } catch (...) {
807 }
808 }
809
810
811 expected<void> RepoManager::removeRepository( const RepoInfo & info, ProgressObserverRef myProgress )
812 {
813 try {
814 ProgressObserver::setup( myProgress, zypp::str::form(_("Removing repository '%s'"), info.label().c_str()), 1 );
815 ProgressObserver::start( myProgress );
816
817 MIL << "Going to delete repo " << info.alias() << std::endl;
818
819 for( const auto &repo : repos() )
820 {
821 // they can be the same only if the provided is empty, that means
822 // the provided repo has no alias
823 // then skip
824 if ( (!info.alias().empty()) && ( info.alias() != repo.alias() ) )
825 continue;
826
827 // TODO match by url
828
829 // we have a matching repository, now we need to know
830 // where it does come from.
831 RepoInfo todelete = repo;
832 if (todelete.filepath().empty())
833 {
834 ZYPP_THROW(zypp::repo::RepoException( todelete, _("Can't figure out where the repo is stored.") ));
835 }
836 else
837 {
838 // figure how many repos are there in the file:
839 std::list<RepoInfo> filerepos = repositories_in_file(todelete.filepath()).unwrap();
840 if ( filerepos.size() == 0 // bsc#984494: file may have already been deleted
841 ||(filerepos.size() == 1 && filerepos.front().alias() == todelete.alias() ) )
842 {
843 // easy: file does not exist, contains no or only the repo to delete: delete the file
844 int ret = zypp::filesystem::unlink( todelete.filepath() );
845 if ( ! ( ret == 0 || ret == ENOENT ) )
846 {
847 // TranslatorExplanation '%s' is a filename
848 ZYPP_THROW(zypp::repo::RepoException( todelete, zypp::str::form( _("Can't delete '%s'"), todelete.filepath().c_str() )));
849 }
850 MIL << todelete.alias() << " successfully deleted." << std::endl;
851 }
852 else
853 {
854 // there are more repos in the same file
855 // write them back except the deleted one.
856 //TmpFile tmp;
857 //std::ofstream file(tmp.path().c_str());
858
859 // assert the directory exists
861
862 std::ofstream file(todelete.filepath().c_str());
863 if (!file)
864 {
865 // TranslatorExplanation '%s' is a filename
866 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), todelete.filepath().c_str() )));
867 }
868 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
869 fit != filerepos.end();
870 ++fit )
871 {
872 if ( (*fit).alias() != todelete.alias() )
873 (*fit).dumpAsIniOn(file);
874 }
875 }
876
877 // now delete it from cache
878 if ( isCached(todelete) )
879 cleanCache( todelete, ProgressObserver::makeSubTask( myProgress, 0.2 )).unwrap();
880 // now delete metadata (#301037)
881 cleanMetadata( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 )).unwrap();
882 cleanPackages( todelete, ProgressObserver::makeSubTask( myProgress, 0.4 ), true/*isAutoClean*/ ).unwrap();
883 reposManip().erase(todelete);
884 MIL << todelete.alias() << " successfully deleted." << std::endl;
885 zypp::HistoryLog(_options.rootDir).removeRepository(todelete);
886
887 ProgressObserver::finish(myProgress);
889 } // else filepath is empty
890 }
891 // should not be reached on a sucess workflow
893 } catch (...) {
895 return expected<void>::error( std::current_exception () );
896 }
897 }
898
899
900 expected<RepoInfo> RepoManager::modifyRepository( const std::string & alias, const RepoInfo & newinfo_r, ProgressObserverRef myProgress )
901 {
902 try {
903
904 ProgressObserver::setup( myProgress, _("Modifying repository"), 5 );
905 ProgressObserver::start( myProgress );
906
907 RepoInfo toedit = getRepositoryInfo(alias).unwrap();
908 RepoInfo newinfo( newinfo_r ); // need writable copy to upadte housekeeping data
909
910 // check if the new alias already exists when renaming the repo
911 if ( alias != newinfo.alias() && hasRepo( newinfo.alias() ) )
912 {
914 }
915
916 if (toedit.filepath().empty())
917 {
918 ZYPP_THROW(zypp::repo::RepoException( toedit, _("Can't figure out where the repo is stored.") ));
919 }
920 else
921 {
922 ProgressObserver::increase( myProgress );
923 // figure how many repos are there in the file:
924 std::list<RepoInfo> filerepos = repositories_in_file(toedit.filepath()).unwrap();
925
926 // there are more repos in the same file
927 // write them back except the deleted one.
928 //TmpFile tmp;
929 //std::ofstream file(tmp.path().c_str());
930
931 // assert the directory exists
933
934 std::ofstream file(toedit.filepath().c_str());
935 if (!file)
936 {
937 // TranslatorExplanation '%s' is a filename
938 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), toedit.filepath().c_str() )));
939 }
940 for ( std::list<RepoInfo>::const_iterator fit = filerepos.begin();
941 fit != filerepos.end();
942 ++fit )
943 {
944 // if the alias is different, dump the original
945 // if it is the same, dump the provided one
946 if ( (*fit).alias() != toedit.alias() )
947 (*fit).dumpAsIniOn(file);
948 else
949 newinfo.dumpAsIniOn(file);
950 }
951
952 ProgressObserver::increase( myProgress );
953
954 if ( toedit.enabled() && !newinfo.enabled() )
955 {
956 // On the fly remove solv.idx files for bash completion if a repo gets disabled.
957 const zypp::Pathname solvidx = solv_path_for_repoinfo(_options, newinfo).unwrap()/"solv.idx";
958 if ( zypp::PathInfo(solvidx).isExist() )
959 zypp::filesystem::unlink( solvidx );
960 }
961
962 newinfo.setFilepath(toedit.filepath());
963 newinfo.setMetadataPath( rawcache_path_for_repoinfo( _options, newinfo ).unwrap() );
964 newinfo.setPackagesPath( packagescache_path_for_repoinfo( _options, newinfo ).unwrap() );
965
966 ProgressObserver::increase( myProgress );
967
968 reposManip().erase(toedit);
969 reposManip().insert(newinfo);
970
971 ProgressObserver::increase( myProgress );
972
973 // check for credentials in Urls
975 zypp::HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
976 MIL << "repo " << alias << " modified" << std::endl;
977
978 ProgressObserver::finish ( myProgress );
979 return expected<RepoInfo>::success( newinfo );
980 }
981
982 } catch ( ... ) {
985 }
986 }
987
988
990 {
991 try {
992 RepoConstIterator it( findAlias( alias, repos() ) );
993 if ( it != repos().end() )
994 return make_expected_success(*it);
996 info.setAlias( alias );
998 } catch ( ... ) {
999 return expected<RepoInfo>::error( std::current_exception () );
1000 }
1001 }
1002
1003
1004
1006 {
1007 try {
1008
1009 for_( it, repoBegin(), repoEnd() )
1010 {
1011 for( const auto &origin : it->repoOrigins() )
1012 {
1013 if ( std::any_of( origin.begin(), origin.end(), [&url, &urlview]( const zypp::OriginEndpoint &ep ){ return (ep.url().asString(urlview) == url.asString(urlview)); }) )
1014 return make_expected_success(*it);
1015 }
1016 }
1017 RepoInfo info;
1018 info.setBaseUrl( url );
1020
1021 } catch ( ... ) {
1022 return expected<RepoInfo>::error( std::current_exception () );
1023 }
1024 }
1025
1026
1028 {
1029 using namespace zyppng::operators;
1030 return joinPipeline( _zyppContext,
1032 | [this, info](auto) { return zyppng::repo::RefreshContext::create( _zyppContext, info, shared_this<RepoManager>() ); }
1033 | and_then( [this, origin, policy]( zyppng::repo::RefreshContextRef &&refCtx ) {
1034 refCtx->setPolicy ( static_cast<zyppng::repo::RawMetadataRefreshPolicy>( policy ) );
1035
1036 return _zyppContext->provider()->prepareMedia( origin, zyppng::ProvideMediaSpec() )
1037 | and_then( [ r = std::move(refCtx) ]( auto mediaHandle ) mutable { return zyppng::RepoManagerWorkflow::checkIfToRefreshMetadata ( std::move(r), std::move(mediaHandle), nullptr ); } );
1038 })
1039 );
1040 }
1041
1042
1044 {
1045 using namespace zyppng::operators;
1046 // helper callback in case the repo type changes on the remote
1047 // do NOT capture by reference here, since this is possibly executed async
1048 const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
1049 // update probed type only for repos in system
1050 for( const auto &repo : repos() ) {
1051 if ( info.alias() == repo.alias() )
1052 {
1053 RepoInfo modifiedrepo = repo;
1054 modifiedrepo.setType( repokind );
1055 // don't modify .repo in refresh.
1056 // modifyRepository( info.alias(), modifiedrepo );
1057 break;
1058 }
1059 }
1060 };
1061
1062 // the list of URLs we want to have geo ip redirects for
1063 auto urls = info.baseUrls ();
1064 if ( info.mirrorListUrl ().isValid () )
1065 urls.push_back ( info.mirrorListUrl () );
1066
1067 return joinPipeline( _zyppContext,
1068 // make sure geoIP data is up 2 date, but ignore errors
1071 | and_then( [policy, myProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) {
1072 refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
1073 // in case probe detects a different repokind, update our internal repos
1074 refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb );
1075
1076 return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), myProgress );
1077 })
1078 | and_then([rMgr = shared_this<RepoManager>()]( repo::RefreshContextRef ctx ) {
1079
1080 if ( ! isTmpRepo( ctx->repoInfo() ) )
1081 rMgr->reposManip(); // remember to trigger appdata refresh
1082
1083 return expected<void>::success ();
1084 }));
1085 }
1086
1087
1088 std::vector<std::pair<RepoInfo, expected<void>>> RepoManager::refreshMetadata( std::vector<RepoInfo> infos, RawMetadataRefreshPolicy policy, ProgressObserverRef myProgress )
1089 {
1090 using namespace zyppng::operators;
1091
1092 ProgressObserver::setup( myProgress, "Refreshing repositories" , 1 );
1093
1094 auto r = std::move(infos)
1095 | transform( [this, policy, myProgress]( const RepoInfo &info ) {
1096
1097 auto subProgress = ProgressObserver::makeSubTask( myProgress, 1.0, zypp::str::Str() << _("Refreshing Repository: ") << info.alias(), 3 );
1098
1099 // helper callback in case the repo type changes on the remote
1100 // do NOT capture by reference here, since this is possibly executed async
1101 const auto &updateProbedType = [this, info = info]( zypp::repo::RepoType repokind ) {
1102 // update probed type only for repos in system
1103 for( const auto &repo : repos() ) {
1104 if ( info.alias() == repo.alias() )
1105 {
1106 RepoInfo modifiedrepo = repo;
1107 modifiedrepo.setType( repokind );
1108 // don't modify .repo in refresh.
1109 // modifyRepository( info.alias(), modifiedrepo );
1110 break;
1111 }
1112 }
1113 };
1114
1115 auto sharedThis = shared_this<RepoManager>();
1116
1117 return
1118 // make sure geoIP data is up 2 date, but ignore errors
1120 | [sharedThis, info = info](auto) { return zyppng::repo::RefreshContext::create( sharedThis->_zyppContext, info, sharedThis); }
1121 | inspect( incProgress( subProgress ) )
1122 | and_then( [policy, subProgress, cb = updateProbedType]( repo::RefreshContextRef refCtx ) {
1123 refCtx->setPolicy( static_cast<repo::RawMetadataRefreshPolicy>( policy ) );
1124 // in case probe detects a different repokind, update our internal repos
1125 refCtx->connectFunc( &repo::RefreshContext::sigProbedTypeChanged, cb );
1126
1127 return zyppng::RepoManagerWorkflow::refreshMetadata ( std::move(refCtx), ProgressObserver::makeSubTask( subProgress ) );
1128 })
1129 | inspect( incProgress( subProgress ) )
1130 | and_then([subProgress]( repo::RefreshContextRef ctx ) {
1131
1132 if ( ! isTmpRepo( ctx->repoInfo() ) )
1133 ctx->repoManager()->reposManip(); // remember to trigger appdata refresh
1134
1135 return zyppng::RepoManagerWorkflow::buildCache ( std::move(ctx), CacheBuildPolicy::BuildIfNeeded, ProgressObserver::makeSubTask( subProgress ) );
1136 })
1137 | inspect( incProgress( subProgress ) )
1138 | [ info = info, subProgress ]( expected<repo::RefreshContextRef> result ) {
1139 if ( result ) {
1141 return std::make_pair(info, expected<void>::success() );
1142 } else {
1144 return std::make_pair(info, expected<void>::error( result.error() ) );
1145 }
1146 };
1147 }
1148 | [myProgress]( auto res ) {
1150 return res;
1151 }
1152 );
1153
1154 return joinPipeline( _zyppContext, r );
1155 }
1156
1163
1165 {
1166 using namespace zyppng::operators;
1167
1168 RepoInfo::url_set allUrls;
1169 std::transform( origin.begin (), origin.end(), std::back_inserter(allUrls), []( const zypp::OriginEndpoint &ep ){ return ep.url(); } );
1170
1171 return joinPipeline( _zyppContext,
1173 | [this, origin=origin](auto) { return _zyppContext->provider()->prepareMedia( origin, zyppng::ProvideMediaSpec() ); }
1174 | and_then( [this, path = path]( auto mediaHandle ) {
1175 return RepoManagerWorkflow::probeRepoType( _zyppContext, std::move(mediaHandle), path );
1176 }));
1177 }
1178
1179
1180 expected<void> RepoManager::buildCache( const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress )
1181 {
1182 using namespace zyppng::operators;
1183 // The snapshot is derived from the solv caches, so drop it when one
1184 // of them is rebuilt. Only then: zypper refreshes every repo on every
1185 // run, and the workflow usually finds the cache up to date and leaves
1186 // it alone, so deleting unconditionally would throw the snapshot away
1187 // before a single run could map it. A rebuild rewrites the cookie
1188 // file, which is what cacheStatus() reads.
1189 const auto statusBefore { cacheStatus( info ) };
1190 return joinPipeline( _zyppContext,
1192 | and_then( [policy, myProgress]( repo::RefreshContextRef refCtx ) {
1193 return zyppng::RepoManagerWorkflow::buildCache ( std::move(refCtx), policy, myProgress );
1194 })
1195 | and_then([this, info, statusBefore]( auto ){
1196 const auto statusAfter { cacheStatus( info ) };
1197 if ( !statusBefore || !statusAfter || !( *statusBefore == *statusAfter ) )
1199 return expected<void>::success();
1200 })
1201 );
1202 }
1203
1204
1205 expected<RepoInfo> RepoManager::addRepository(const RepoInfo &info, ProgressObserverRef myProgress, const zypp::TriBool & forcedProbe )
1206 {
1207 return joinPipeline( _zyppContext, RepoManagerWorkflow::addRepository( shared_this<RepoManager>(), info, std::move(myProgress), forcedProbe ) );
1208 }
1209
1210
1211 expected<void> RepoManager::addRepositories(const zypp::Url &url, ProgressObserverRef myProgress)
1212 {
1213 using namespace zyppng::operators;
1215 }
1216
1217
1222
1223
1225 {
1226 try {
1227
1228 assert_alias( service ).unwrap();
1229
1230 // check if service already exists
1231 if ( hasService( service.alias() ) )
1233
1234 // Writable ServiceInfo is needed to save the location
1235 // of the .service file. Finaly insert into the service list.
1236 ServiceInfo toSave( service );
1237 saveService( toSave ).unwrap();
1238 _services.insert( toSave );
1239
1240 // check for credentials in Url
1241 zypp::UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
1242
1243 MIL << "added service " << toSave.alias() << std::endl;
1244
1245 } catch ( ... ) {
1246 return expected<void>::error( std::current_exception () );
1247 }
1248
1249 return expected<void>::success();
1250 }
1251
1252
1253 expected<void> RepoManager::refreshService( const std::string &alias, const RefreshServiceOptions &options_r )
1254 {
1256 }
1257
1261
1263 {
1264 using namespace zyppng::operators;
1265 // copy the set of services since refreshService
1266 // can eventually invalidate the iterator
1267 ServiceSet servicesCopy( serviceBegin(), serviceEnd() );
1268
1269 // convert the set into a vector, transform needs a container with push_back support
1270 std::vector<ServiceInfo> servicesVec;
1271 std::copy( std::make_move_iterator(servicesCopy.begin()), std::make_move_iterator(servicesCopy.end()), std::back_inserter(servicesVec));
1272
1273 return joinPipeline( _zyppContext,
1274 std::move(servicesVec)
1275 | transform( [options_r, this]( ServiceInfo i ){ return RepoServicesWorkflow::refreshService( shared_this<RepoManager>(), i, options_r ); } )
1276 | join()
1277 | collect()
1278 );
1279 }
1280
1282
1283
1284 expected<void> RepoManager::removeService( const std::string & alias )
1285 {
1286 try {
1287 MIL << "Going to delete service " << alias << std::endl;
1288
1289 const ServiceInfo & service = getService( alias );
1290
1291 zypp::Pathname location = service.filepath();
1292 if( location.empty() )
1293 {
1294 ZYPP_THROW(zypp::repo::ServiceException( service, _("Can't figure out where the service is stored.") ));
1295 }
1296
1297 ServiceSet tmpSet;
1299
1300 // only one service definition in the file
1301 if ( tmpSet.size() == 1 )
1302 {
1303 if ( zypp::filesystem::unlink(location) != 0 )
1304 {
1305 // TranslatorExplanation '%s' is a filename
1306 ZYPP_THROW(zypp::repo::ServiceException( service, zypp::str::form( _("Can't delete '%s'"), location.c_str() ) ));
1307 }
1308 MIL << alias << " successfully deleted." << std::endl;
1309 }
1310 else
1311 {
1313
1314 std::ofstream file(location.c_str());
1315 if( !file )
1316 {
1317 // TranslatorExplanation '%s' is a filename
1318 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), location.c_str() )));
1319 }
1320
1321 for_(it, tmpSet.begin(), tmpSet.end())
1322 {
1323 if( it->alias() != alias )
1324 it->dumpAsIniOn(file);
1325 }
1326
1327 MIL << alias << " successfully deleted from file " << location << std::endl;
1328 }
1329
1330 // now remove all repositories added by this service
1331 RepoCollector rcollector;
1333 boost::make_function_output_iterator( std::bind( &RepoCollector::collect, &rcollector, std::placeholders::_1 ) ) );
1334 // cannot do this directly in getRepositoriesInService - would invalidate iterators
1335 for_(rit, rcollector.repos.begin(), rcollector.repos.end())
1336 removeRepository(*rit).unwrap();
1337
1338 return expected<void>::success();
1339
1340 } catch ( ... ) {
1341 return expected<void>::error( std::current_exception () );
1342 }
1343 }
1344
1345
1346 expected<void> RepoManager::modifyService( const std::string & oldAlias, const ServiceInfo & newService )
1347 {
1348 try {
1349
1350 MIL << "Going to modify service " << oldAlias << std::endl;
1351
1352 // we need a writable copy to link it to the file where
1353 // it is saved if we modify it
1354 ServiceInfo service(newService);
1355
1356 if ( service.type() == zypp::repo::ServiceType::PLUGIN )
1357 {
1359 }
1360
1361 const ServiceInfo & oldService = getService(oldAlias);
1362
1363 zypp::Pathname location = oldService.filepath();
1364 if( location.empty() )
1365 {
1366 ZYPP_THROW(zypp::repo::ServiceException( oldService, _("Can't figure out where the service is stored.") ));
1367 }
1368
1369 // remember: there may multiple services being defined in one file:
1370 ServiceSet tmpSet;
1372
1374 std::ofstream file(location.c_str());
1375 for_(it, tmpSet.begin(), tmpSet.end())
1376 {
1377 if( *it != oldAlias )
1378 it->dumpAsIniOn(file);
1379 }
1380 service.dumpAsIniOn(file);
1381 file.close();
1382 service.setFilepath(location);
1383
1384 _services.erase(oldAlias);
1385 _services.insert(service);
1386 // check for credentials in Urls
1387 zypp::UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
1388
1389
1390 // changed properties affecting also repositories
1391 if ( oldAlias != service.alias() // changed alias
1392 || oldService.enabled() != service.enabled() ) // changed enabled status
1393 {
1394 std::vector<RepoInfo> toModify;
1395 getRepositoriesInService(oldAlias, std::back_inserter(toModify));
1396 for_( it, toModify.begin(), toModify.end() )
1397 {
1398 if ( oldService.enabled() != service.enabled() )
1399 {
1400 if ( service.enabled() )
1401 {
1402 // reset to last refreshs state
1403 const auto & last = service.repoStates().find( it->alias() );
1404 if ( last != service.repoStates().end() )
1405 it->setEnabled( last->second.enabled );
1406 }
1407 else
1408 it->setEnabled( false );
1409 }
1410
1411 if ( oldAlias != service.alias() )
1412 it->setService(service.alias());
1413
1414 modifyRepository(it->alias(), *it).unwrap();
1415 }
1416 }
1417
1418 return expected<void>::success();
1419
1420 } catch ( ... ) {
1421 return expected<void>::error( std::current_exception () );
1422 }
1423
1425 }
1426
1427
1428
1430 {
1431 try {
1432
1433 zypp::filesystem::assert_dir( _options.knownServicesPath );
1434 zypp::Pathname servfile = generateNonExistingName( _options.knownServicesPath,
1435 generateFilename( service ) );
1436 service.setFilepath( servfile );
1437
1438 MIL << "saving service in " << servfile << std::endl;
1439
1440 std::ofstream file( servfile.c_str() );
1441 if ( !file )
1442 {
1443 // TranslatorExplanation '%s' is a filename
1444 ZYPP_THROW( zypp::Exception(zypp::str::form( _("Can't open file '%s' for writing."), servfile.c_str() )));
1445 }
1446 service.dumpAsIniOn( file );
1447 MIL << "done" << std::endl;
1448
1449 return expected<void>::success();
1450
1451 } catch ( ... ) {
1452 return expected<void>::error( std::current_exception () );
1453 }
1454 }
1455
1471
1473 const std::string & basefilename ) const
1474 {
1475 std::string final_filename = basefilename;
1476 int counter = 1;
1477 while ( zypp::PathInfo(dir + final_filename).isExist() )
1478 {
1479 final_filename = basefilename + "_" + zypp::str::numstring(counter);
1480 ++counter;
1481 }
1482 return dir + zypp::Pathname(final_filename);
1483 }
1484
1485
1486 expected<void> RepoManager::touchIndexFile(const RepoInfo &info, const RepoManagerOptions &options)
1487 {
1488 try {
1489 zypp::Pathname productdatapath = rawproductdata_path_for_repoinfo( options, info ).unwrap();
1490
1491 zypp::repo::RepoType repokind = info.type();
1492 if ( repokind.toEnum() == zypp::repo::RepoType::NONE_e )
1493 // unknown, probe the local metadata
1494 repokind = probeCache( productdatapath );
1495 // if still unknown, just return
1496 if (repokind == zypp::repo::RepoType::NONE_e)
1497 return expected<void>::success();
1498
1499 zypp::Pathname p;
1500 switch ( repokind.toEnum() )
1501 {
1503 p = zypp::Pathname(productdatapath + "/repodata/repomd.xml");
1504 break;
1505
1507 p = zypp::Pathname(productdatapath + "/content");
1508 break;
1509
1511 p = zypp::Pathname(productdatapath + "/cookie");
1512 break;
1513
1515 default:
1516 break;
1517 }
1518
1519 // touch the file, ignore error (they are logged anyway)
1521 } catch ( ... ) {
1522 return expected<void>::error( ZYPP_FWD_CURRENT_EXCPT() );
1523 }
1524 return expected<void>::success();
1525 }
1526
1527 expected<void> RepoManager::refreshGeoIp( const RepoInfo::url_set &urls )
1528 {
1529 return joinPipeline( _zyppContext, RepoManagerWorkflow::refreshGeoIPData( _zyppContext, urls) );
1530 }
1531
1532 expected<void> RepoManager::touchIndexFile( const RepoInfo & info )
1533 {
1534 return touchIndexFile( info, _options );
1535 }
1536
1537
1538 expected<void> RepoManager::init_knownServices()
1539 {
1540 try {
1541 zypp::Pathname dir = _options.knownServicesPath;
1542 std::list<zypp::Pathname> entries;
1543 if (zypp::PathInfo(dir).isExist())
1544 {
1545 if ( zypp::filesystem::readdir( entries, dir, false ) != 0 )
1546 {
1547 // TranslatorExplanation '%s' is a pathname
1548 ZYPP_THROW(zypp::Exception(zypp::str::form(_("Failed to read directory '%s'"), dir.c_str())));
1549 }
1550
1551 //str::regex allowedServiceExt("^\\.service(_[0-9]+)?$");
1552 for_(it, entries.begin(), entries.end() )
1553 {
1554 zypp::parser::ServiceFileReader(*it, ServiceCollector(_services));
1555 }
1556 }
1557
1558 zypp::repo::PluginServices(_options.pluginsPath/"services", ServiceCollector(_services));
1559
1560 return expected<void>::success();
1561
1562 } catch ( ... ) {
1563 return expected<void>::error( std::current_exception () );
1564 }
1565
1566 }
1567
1568 namespace {
1575 inline void cleanupNonRepoMetadtaFolders( const zypp::Pathname & cachePath_r,
1576 const zypp::Pathname & defaultCachePath_r,
1577 const std::list<std::string> & repoEscAliases_r )
1578 {
1580 return;
1581
1582 if ( cachePath_r != defaultCachePath_r )
1583 return;
1584
1585 std::list<std::string> entries;
1586 if ( zypp::filesystem::readdir( entries, cachePath_r, false ) == 0 )
1587 {
1588 entries.sort();
1589 std::set<std::string> oldfiles;
1590 set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
1591 std::inserter( oldfiles, oldfiles.end() ) );
1592
1593 // bsc#1178966: Files or symlinks here have been created by the user
1594 // for whatever purpose. It's our cache, so we purge them now before
1595 // they may later conflict with directories we need.
1596 zypp::PathInfo pi;
1597 for ( const std::string & old : oldfiles )
1598 {
1599 if ( old == zypp::Repository::systemRepoAlias() ) // don't remove the @System solv file
1600 continue;
1601 pi( cachePath_r/old );
1602 if ( pi.isDir() )
1604 else
1606 }
1607 }
1608 }
1609 } // namespace
1610
1611
1613 {
1614 try {
1615
1616 MIL << "start construct known repos" << std::endl;
1617
1618 if ( zypp::PathInfo(_options.knownReposPath).isExist() )
1619 {
1620 std::list<std::string> repoEscAliases;
1621 std::list<RepoInfo> orphanedRepos;
1622 for ( RepoInfo & repoInfo : repositories_in_dir( _zyppContext, _options.knownReposPath ) )
1623 {
1624 // set the metadata path for the repo
1625 repoInfo.setMetadataPath( rawcache_path_for_repoinfo(_options, repoInfo).unwrap() );
1626 // set the downloaded packages path for the repo
1627 repoInfo.setPackagesPath( packagescache_path_for_repoinfo(_options, repoInfo).unwrap() );
1628 // remember it
1629 _reposX.insert( repoInfo ); // direct access via _reposX in ctor! no reposManip.
1630
1631 // detect orphaned repos belonging to a deleted service
1632 const std::string & serviceAlias( repoInfo.service() );
1633 if ( ! ( serviceAlias.empty() || hasService( serviceAlias ) ) )
1634 {
1635 WAR << "Schedule orphaned service repo for deletion: " << repoInfo << std::endl;
1636 orphanedRepos.push_back( repoInfo );
1637 continue; // don't remember it in repoEscAliases
1638 }
1639
1640 repoEscAliases.push_back(repoInfo.escaped_alias());
1641 }
1642
1643 // Cleanup orphanded service repos:
1644 if ( ! orphanedRepos.empty() )
1645 {
1646 for ( const auto & repoInfo : orphanedRepos )
1647 {
1648 MIL << "Delete orphaned service repo " << repoInfo.alias() << std::endl;
1649 // translators: Cleanup a repository previously owned by a meanwhile unknown (deleted) service.
1650 // %1% = service name
1651 // %2% = repository name
1652 JobReportHelper(_zyppContext).warning( zypp::str::Format(_("Unknown service '%1%': Removing orphaned service repository '%2%'"))
1653 % repoInfo.service()
1654 % repoInfo.alias() );
1655 try {
1656 removeRepository( repoInfo ).unwrap();
1657 }
1658 catch ( const zypp::Exception & caugth )
1659 {
1661 }
1662 }
1663 }
1664
1665 // bsc#1210740: Don't cleanup if read-only mode was promised.
1667 // delete metadata folders without corresponding repo (e.g. old tmp directories)
1668 //
1669 // bnc#891515: Auto-cleanup only zypp.conf default locations. Otherwise
1670 // we'd need somemagic file to identify zypp cache directories. Without this
1671 // we may easily remove user data (zypper --pkg-cache-dir . download ...)
1672 repoEscAliases.sort();
1673 cleanupNonRepoMetadtaFolders( _options.repoRawCachePath,
1674 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoMetadataPath() ),
1675 repoEscAliases );
1676 cleanupNonRepoMetadtaFolders( _options.repoSolvCachePath,
1677 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoSolvfilesPath() ),
1678 repoEscAliases );
1679 // bsc#1204956: Tweak to prevent auto pruning package caches
1680 if ( autoPruneInDir( _options.repoPackagesCachePath ) )
1681 cleanupNonRepoMetadtaFolders( _options.repoPackagesCachePath,
1682 zypp::Pathname::assertprefix( _options.rootDir, _zyppContext->config().builtinRepoPackagesPath() ),
1683 repoEscAliases );
1684 }
1685 }
1686 MIL << "end construct known repos" << std::endl;
1687
1688 return expected<void>::success();
1689
1690 } catch ( ... ) {
1691 return expected<void>::error( std::current_exception () );
1692 }
1693 }
1694} // namespace zyppng
#define zypp_defer
#define OUTS(VAL)
#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:130
#define WAR
Definition Logger.h:131
const std::string & asString() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Arch.cc:724
static const ValueType day
Definition Date.h:44
static Date now()
Return the current time.
Definition Date.h:78
Compute Message Digests (MD5, SHA1 etc).
Definition Digest.h:38
std::string digest()
get hex string representation of the digest
Definition Digest.cc:239
bool update(const char *bytes, size_t len)
feed data into digest computation algorithm
Definition Digest.cc:288
bool create(const std::string &name)
initialize creation of a new message digest
Definition Digest.cc:198
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)
Unless path_r does not already denote a path below root_r, combine them.
Definition Pathname.cc:272
What is known about a repository.
Definition RepoInfo.h:72
void setPackagesPath(const Pathname &path)
set the path where the local packages are stored
Definition RepoInfo.cc:798
url_set baseUrls() const
The complete set of repository urls as configured.
Definition RepoInfo.cc:858
std::ostream & dumpAsIniOn(std::ostream &str) const override
Write this RepoInfo object into str in a .repo file format.
Definition RepoInfo.cc:1087
void setMetadataPath(const Pathname &path)
Set the path where the local metadata is stored.
Definition RepoInfo.cc:795
void setType(const repo::RepoType &t)
set the repository type
Definition RepoInfo.cc:788
std::list< Url > url_set
Definition RepoInfo.h:108
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).
RepoStatus()
Default ctor.
static const std::string & systemRepoAlias()
Reserved system repository alias @System .
Definition Repository.cc:43
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
Arch systemArchitecture() const
The system architecture zypp uses.
Definition ZConfig.cc:857
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:794
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:192
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:133
const char * c_str() const
String representation.
Definition Pathname.h:113
const std::string & asString() const
String representation.
Definition Pathname.h:94
bool empty() const
Test for an empty path.
Definition Pathname.h:117
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.
void setFilepath(const Pathname &filename)
set the path to the .repo file
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
RAII: while any instance lives, detail::PoolImpl::prepare does not erase snapshot repos this run has ...
Definition Pool.h:182
static const SolvAttr repositoryToolVersion
Definition SolvAttr.h:193
Regular expression.
Definition Regex.h:95
std::shared_ptr< T > shared_this() const
Definition base.h:114
JobReportHelper(ContextRef r)
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)
std::string poolSnapshotCookie() const
Cookie describing the enabled repos and their solv caches, empty if the pool snapshot cannot be used.
expected< void > cleanPackages(const RepoInfo &info, ProgressObserverRef myProgress=nullptr, bool isAutoClean=false)
expected< RepoStatus > cacheStatus(const RepoInfo &info) const
expected< void > removeRepository(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
RepoSet::const_iterator RepoConstIterator
expected< bool > isCached(const RepoInfo &info) const
expected< void > buildCache(const RepoInfo &info, CacheBuildPolicy policy, ProgressObserverRef myProgress=nullptr)
expected< RepoInfo > addProbedRepository(RepoInfo info, zypp::repo::RepoType probedType)
std::string generateFilename(const RepoInfo &info) const
zypp::Pathname poolSnapshotPath() const
Where the pool snapshot lives.
expected< void > init_knownServices()
ServiceInfo getService(const std::string &alias) const
zypp::RepoManagerFlags::RefreshServiceOptions RefreshServiceOptions
expected< RepoInfo > modifyRepository(const std::string &alias, const RepoInfo &newinfo_r, ProgressObserverRef myProgress=nullptr)
zypp::DefaultIntegral< bool, false > _reposDirty
static expected< RepoStatus > metadataStatus(const RepoInfo &info, const RepoManagerOptions &options)
bool hasRepo(const std::string &alias) const
expected< void > saveService(ServiceInfo &service) const
expected< RepoInfo > getRepositoryInfo(const std::string &alias)
zypp::RepoManagerFlags::RawMetadataRefreshPolicy RawMetadataRefreshPolicy
static zypp::repo::RepoType probeCache(const zypp::Pathname &path_r)
Probe Metadata in a local cache directory.
const RepoSet & repos() const
ServiceConstIterator serviceBegin() const
zypp::Pathname generateNonExistingName(const zypp::Pathname &dir, const std::string &basefilename) const
ContextRefType _zyppContext
void getRepositoriesInService(const std::string &alias, OutputIterator out) const
RepoConstIterator repoEnd() const
expected< void > cleanCache(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
RepoConstIterator repoBegin() const
expected< void > initialize()
std::set< ServiceInfo > ServiceSet
ServiceInfo typedefs.
RepoSet & reposManip()
RepoManagerOptions _options
expected< void > init_knownRepositories()
int _poolSnapshotState
0 unknown, 1 mapped, -1 unusable
expected< void > cleanMetadata(const RepoInfo &info, ProgressObserverRef myProgress=nullptr)
bool tryLoadPoolSnapshot()
Try to map the pool snapshot on the first loadFromCache, and arm writing a fresh one after a normal l...
void reservePoolIds()
Peek at the solv files of all enabled repos and size the pool's id hashes once for their sum,...
ServiceConstIterator serviceEnd() const
bool hasService(const std::string &alias) const
const RepoManagerOptions & options() const
void cleanPoolSnapshot() const
Remove the pool snapshot and any leftover of an interrupted write.
zypp::RepoManagerFlags::CacheBuildPolicy CacheBuildPolicy
zypp::DefaultIntegral< bool, false > _poolIdsReserved
Functor collecting ServiceInfos into a ServiceSet.
static expected success(ConsParams &&...params)
Definition expected.h:178
static expected error(ConsParams &&...params)
Definition expected.h:189
SignalProxy< void(zypp::repo::RepoType)> sigProbedTypeChanged()
Definition refresh.cc:157
static expected< repo::RefreshContextRef > create(ContextRef zyppContext, zypp::RepoInfo info, RepoManagerRef repoManager)
Definition refresh.cc:31
CURL handle void * p
Definition curl_dl.cc:142
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t int int running_handles CURLINFO info
Definition curl_dl.cc:160
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
bool regex_match(const char *s, smatch &matches, const regex &regex) ZYPP_API
Regular expression matching.
Definition Regex.cc:80
unsigned short a
unsigned short b
Definition ansi.h:855
String related utilities and Regular expression matching.
RefreshCheckStatus
Possibly return state of RepoManager::checkIfToRefreshMetadata function.
Namespace intended to collect all environment variables we use.
bool ZYPP_PLUGIN_APPDATA_FORCE_COLLECT()
To trigger appdata refresh unconditionally.
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition PathInfo.cc:431
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:719
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:624
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:338
int touch(const Pathname &path)
Change file's modification and access times.
Definition PathInfo.cc:1256
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 hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition String.h:1097
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 asString(const Patch::Category &obj)
relates: Patch::Category string representation.
Definition Patch.cc:122
std::ostream & operator<<(std::ostream &str, const Capabilities &obj)
relates: Capabilities Stream output
MaybeAwaitable< expected< repo::RefreshCheckStatus > > checkIfToRefreshMetadata(repo::RefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
MaybeAwaitable< expected< void > > addRepositories(RepoManagerRef mgr, zypp::Url url, ProgressObserverRef myProgress)
MaybeAwaitable< expected< zypp::repo::RepoType > > probeRepoType(ContextRef ctx, Provide::LazyMediaHandle medium, zypp::Pathname path, std::optional< zypp::Pathname > targetPath)
MaybeAwaitable< expected< RepoInfo > > addRepository(RepoManagerRef mgr, RepoInfo info, ProgressObserverRef myProgress, const zypp::TriBool &forcedProbe)
MaybeAwaitable< expected< repo::RefreshContextRef > > refreshMetadata(repo::RefreshContextRef refCtx, LazyMediaHandle< Provide > medium, ProgressObserverRef progressObserver)
MaybeAwaitable< expected< repo::RefreshContextRef > > buildCache(repo::RefreshContextRef refCtx, zypp::RepoManagerFlags::CacheBuildPolicy policy, ProgressObserverRef progressObserver)
MaybeAwaitable< expected< void > > refreshGeoIPData(ContextRef ctx, RepoInfo::url_set urls)
MaybeAwaitable< expected< void > > refreshService(RepoManagerRef repoMgr, ServiceInfo info, zypp::RepoManagerFlags::RefreshServiceOptions options)
MaybeAwaitable< expected< zypp::repo::ServiceType > > probeServiceType(ContextRef ctx, const zypp::Url &url)
auto incProgress(ProgressObserverRef progressObserver, double progrIncrease=1.0, std::optional< std::string > newStr={})
auto join()
Definition wait.h:34
zypp::RepoManagerFlags::RawMetadataRefreshPolicy RawMetadataRefreshPolicy
Definition refresh.h:33
bool isTmpRepo(const RepoInfo &info_r)
Whether repo is not under RM control and provides its own methadata paths.
Definition repomanager.h:49
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.
void cleanupNonRepoMetadtaFolders(const zypp::Pathname &cachePath_r, const zypp::Pathname &defaultCachePath_r, const std::list< std::string > &repoEscAliases_r)
Generate a non existing filename in a directory, using a base name.
std::string filenameFromAlias(const std::string &alias_r, const std::string &stem_r)
Generate a related filename from a repo/service infos alias.
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:52
ResultType or_else(const expected< T, E > &exp, Function &&f)
Definition expected.h:554
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition expected.h:520
auto transform(Container< Msg, CArgs... > &&val, Transformation &&transformation)
Definition transform.h:64
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:93
std::enable_if_t<!std::is_same_v< void, T >, expected< Container< T >, E > > collect(Container< expected< T, E >, CArgs... > &&in)
Definition expected.h:586
expected< zypp::Pathname > packagescache_path_for_repoinfo(const RepoManagerOptions &opt, const RepoInfo &info)
Calculates the packages cache path for a repository.
auto joinPipeline(ContextRef ctx, T &&val)
Definition context.h:52
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,...
expected< T, E > inspect(expected< T, E > exp, Function &&f)
Definition expected.h:616
bool autoPruneInDir(const zypp::Pathname &path_r)
bsc#1204956: Tweak to prevent auto pruning package caches.
auto mtry(F &&f, Args &&...args)
Definition mtry.h:50
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_PRIVATE_CONSTR_ARG
Definition zyppglobal.h:153