libzypp 17.38.3
commitpackagepreloader.cc
Go to the documentation of this file.
5#include <zypp/media/MediaCurl2.h> // for shared logic like authenticate
6#include <zypp/media/MediaHandlerFactory.h> // to detect the URL type
14#include <zypp/MediaSetAccess.h>
15#include <zypp/Package.h>
16#include <zypp/SrcPackage.h>
17#include <zypp/ZConfig.h>
18#include <zypp-core/base/Env.h>
19
20namespace zypp {
21
22 namespace {
23
24 inline bool preloadEnabled()
25 {
26 TriBool envstate = env::getenvBool( "ZYPP_PCK_PRELOAD" );
27 if ( indeterminate(envstate) ) {
28#if APIConfig(LIBZYPP_CONFIG_USE_SERIAL_PACKAGE_DOWNLOAD_BY_DEFAULT)
29 return false;
30#else
31 return true;
32#endif
33 }
34 return bool(envstate);
35 }
36
37 zypp::Pathname pckCachedLocation ( const PoolItem &pck ) {
38 if ( pck.isKind<Package>() ) {
39 return pck->asKind<Package>()->cachedLocation();
40 } else if ( pck.isKind<SrcPackage>() ) {
41 return pck->asKind<SrcPackage>()->cachedLocation();
42 }
43 return {};
44 }
45
46 }
47
52
54 public:
55 enum State {
58 //ZckHead,
59 //ZckData,
61 };
62
64
65 bool finished ( ) const {
66 return (_s == Finished);
67 }
68
69 void nextJob () {
70
71 // clean state vars
72 _started = false;
73 _firstAuth = true;
75 _tmpFile.reset();
77 _taintedMirrors.clear();
78
79 if ( _parent._requiredDls.empty() ) {
80
81 if ( _myMirror ) {
82 _myMirror->refs--;
83 _myMirror = nullptr;
85 }
86
87 MIL << "No more jobs pending, exiting worker" << std::endl;
88 // exit!
89 _s = Finished;
90 _sigFinished.emit();
91 return;
92 }
93
94 _job = _parent._requiredDls.front();
95 _parent._requiredDls.pop_front();
96
97 auto loc = _job.lookupLocation();
98 const auto repoInfo = _job.repoInfo();
99
100 _targetPath = repoInfo.predownloadPath();
101 if ( !repoInfo.path().emptyOrRoot () ) {
102 _targetPath /= repoInfo.path();
103 }
104 _targetPath /= loc.filename();
105
106 // select a mirror we want to use
107 if ( !prepareMirror( ) ) {
108 finishCurrentJob ( _targetPath, {}, media::CommitPreloadReport::ERROR, asString( _("no mirror found") ), true );
109 return nextJob();
110 }
111
112 if ( filesystem::assert_dir( _targetPath.dirname()) != 0 ) {
113 ERR << "Failed to create target dir for file: " << _targetPath << std::endl;
114 finishCurrentJob ( _targetPath, {}, media::CommitPreloadReport::ERROR, asString( _("could not create target file") ), true );
115 return nextJob();
116 }
117
118
121
122 try {
123 makeJobUrl ( url, settings );
124 } catch ( const zypp::Exception &e ) {
125 ERR << "Failed to create job URL for file: " << _targetPath << " ("<<e<<")" << std::endl;
126 finishCurrentJob ( _targetPath, {}, media::CommitPreloadReport::ERROR, zypp::str::Format(_("Error: Failed to initialize transfer settings (%1%).")) % e.asUserString(), true );
127 return nextJob();
128 }
129
130 // check if the file is there already
131 {
132 PathInfo pathInfo(_targetPath);
133 if ( pathInfo.isExist() ) {
134 // just in case there is something else that is not a file we delete it
135 if ( !pathInfo.isFile() ) {
136 if ( pathInfo.isDir () )
138 else
140
141 } else if ( is_checksum( _targetPath, loc.checksum() ) ) {
142 // if we have the file already, no need to download again
144 return nextJob();
145
146 } else {
147 // everything else we delete
149 }
150 }
151 }
152
153 // we download into a temp file so that we don't leave broken files in case of errors or a crash
155
156 if ( _s == Pending ) {
157 // init case, set up request
158 _req = std::make_shared<zyppng::NetworkRequest>( url, _tmpFile );
162 } else {
163 _req->resetRequestRanges();
164 _req->setUrl( url );
165 _req->setTargetFilePath( _tmpFile );
166 }
167
168 // TODO check for zchunk
169
170 _s = SimpleDl;
171 _req->transferSettings() = settings;
172 _parent._dispatcher->enqueue(_req);
173 }
174
178
179 private:
180
181 // TODO some smarter logic that selects mirrors
183
184 const auto &pi = _job;
185
186 if ( _myMirror ) {
187 if ( _currentRepoId == pi.repository().id() ) {
188 return true;
189 }
191 _myMirror->refs--;
192 _myMirror = nullptr;
193 }
194
196 if ( !_myMirror )
197 return false;
198
199 _currentRepoId = pi.repository().id();
200 _myMirror->refs++;
201 return true;
202 }
203
208
209 if ( _myMirror ) {
210 _myMirror->miss++;
211 _taintedMirrors.insert( _myMirror );
212 }
213
214 // try to find another mirror
215 auto mirrPtr = findUsableMirror ( _myMirror, false );
216 if ( mirrPtr ) {
217 if ( _myMirror ) {
218 _myMirror->refs--;
219 }
220 _myMirror = mirrPtr;
221 _myMirror->refs++;
222 return true;
223 }
224 return false;
225 }
226
230 RepoUrl *findUsableMirror( RepoUrl *skip = nullptr, bool allowTainted = true ) {
231 auto &repoDlInfo = _parent._dlRepoInfo.at( _job.repository().id() );
232
233 std::vector<RepoUrl>::iterator curr = repoDlInfo._baseUrls.end();
234 int currentSmallestRef = INT_MAX;
235
236 for ( auto i = repoDlInfo._baseUrls.begin(); i != repoDlInfo._baseUrls.end(); i++ ) {
237 auto mirrorPtr = &(*i);
238
239 if ( skip == mirrorPtr )
240 continue;
241
242 if ( !allowTainted && _taintedMirrors.find(mirrorPtr) != _taintedMirrors.end() )
243 continue;
244
245 // we are adding the file misses on top of the refcount
246 // that way we will use mirrors that often miss a file less
247 if ( ( i->refs + i->miss ) < currentSmallestRef ) {
248 currentSmallestRef = ( i->refs + i->miss );
249 curr = i;
250 }
251 }
252
253 if ( curr == repoDlInfo._baseUrls.end() )
254 return nullptr;
255 return &(*curr);
256 }
257
259 MIL << "Request for " << req.url() << " started" << std::endl;
260 }
261
263 if ( !_started ) {
264 _started = true;
265
266 callback::UserData userData( "CommitPreloadReport/fileStart" );
267 userData.set( "Url", _req->url() );
268 _parent._report->fileStart( _targetPath, userData );
269 }
270
271 ByteCount downloaded;
272 if ( _lastByteCount == 0 )
273 downloaded = count;
274 else
275 downloaded = count - _lastByteCount;
276 _lastByteCount = count;
277
278 _parent.reportBytesDownloaded( downloaded );
279 }
280
282 MIL << "Request for " << req.url() << " finished. (" << err.toString() << ")" << std::endl;
283 if ( !req.hasError() ) {
284 // apply umask and move the _tmpFile into _targetPath
286 _tmpFile.resetDispose(); // rename consumed the file, no need to unlink.
288 } else {
289 // error
290 finishCurrentJob ( _targetPath, req.url(), media::CommitPreloadReport::ERROR, _("failed to rename temporary file."), true );
291 }
292 } else {
293 // handle errors and auth
294 const auto &error = req.error();
295 switch ( error.type() ) {
312 ERR << "Download from mirror failed for file " << req.url () << " trying to taint mirror and move on" << std::endl;
313
314 std::string lastError = req.extendedErrorString();
315 while ( taintCurrentMirror() ) {
317
318 const auto str = zypp::str::Format(_("Error: \"%1%\", trying next mirror.")) % lastError;
320
321 try {
324 makeJobUrl ( url, settings );
325
326 MIL << "Found new mirror: " << url << " recovering, retry count: " << _notFoundRetry << std::endl;
327
328 _req->setUrl( url );
329 _req->transferSettings () = settings;
330
331 _parent._dispatcher->enqueue( _req );
332 return;
333
334 } catch ( const zypp::Exception &e ) {
335 ERR << "Failed to setup mirror: ( " << e << " ), trying next!" << std::endl;
336 lastError = e.asUserString();
337 continue;
338 }
339 break;
340 }
341
342 ERR << "No mirror found, giving up on file: " << req.url() << std::endl;
344 break;
345 }
348
349 //in case we got a auth hint from the server the error object will contain it
350 std::string authHint = error.extraInfoValue("authHint", std::string());
351
353 bool newCreds = media::MediaNetworkCommonHandler::authenticate( _myMirror->baseUrl, cm, req.transferSettings(), authHint, _firstAuth );
354 if ( newCreds) {
355 _firstAuth = false;
356 _parent._dispatcher->enqueue( _req );
357 return;
358 }
359
361 break;
362
365 break;
366 }
368 // should never happen
369 DBG << "BUG: Download error flag is set , but Error code is NoError" << std::endl;
370 break;
371 }
372 }
373 nextJob();
374 }
375
376 void finishCurrentJob( const zypp::Pathname &localPath, const std::optional<zypp::Url> &url, media::CommitPreloadReport::Error e, const std::optional<std::string> &errorMessage, bool fatal ) {
377
378 callback::UserData userData( "CommitPreloadReport/fileDone" );
379 if ( url )
380 userData.set( "Url", *url );
381 if ( errorMessage )
382 userData.set( "description", *errorMessage );
383
384 if ( e != media::CommitPreloadReport::NO_ERROR && fatal )
385 _parent._missedDownloads = true;
386
387 _parent._report->fileDone( localPath, e, userData );
388 }
389
390 void makeJobUrl ( zypp::Url &resultUrl, media::TransferSettings &resultSet ) {
391
392 // rewrite Url
393 zypp::Url url = _myMirror->baseUrl;
394
397
398 const auto &loc = _job.lookupLocation();
399
400 // rewrite URL for media handle
401 if ( loc.medianr() > 1 )
402 url = MediaSetAccess::rewriteUrl( url ,loc.medianr() );
403
404 // append path to file
405 url.appendPathName( loc.filename() );
406
407 // add extra headers
408 for ( const auto & el : _myMirror->headers ) {
409 std::string header { el.first };
410 header += ": ";
411 header += el.second;
412 MIL << "Added custom header -> " << header << std::endl;
413 settings.addHeader( std::move(header) );
414 }
415
416 resultUrl = url;
417 resultSet = settings;
418 }
419
420 private:
423 zyppng::NetworkRequestRef _req;
424
428 bool _started = false;
429 bool _firstAuth = true;
430 RepoUrl *_myMirror = nullptr;
433
434 // retry handling
436 std::set<RepoUrl *> _taintedMirrors; //< mirrors that returned 404 for the current request
437
439
440 };
441
444
445 void CommitPackagePreloader::preloadTransaction( const std::vector<sat::Transaction::Step> &steps)
446 {
447 if ( !preloadEnabled() ) {
448 MIL << "CommitPackagePreloader disabled" << std::endl;
449 return;
450 }
451
452 // preload happens only if someone handles the report
453 if ( !_report->connected() ) {
454 MIL << "No receiver for the CommitPreloadReport, skipping preload phase" << std::endl;
455 return;
456 }
457
458 auto ev = zyppng::EventLoop::create();
459 _dispatcher = std::make_shared<zyppng::NetworkRequestDispatcher>();
460 _dispatcher->setMaximumConcurrentConnections( MediaConfig::instance().download_max_concurrent_connections() );
462 _dispatcher->setHostSpecificHeader ("download.opensuse.org", "X-ZYpp-DistributionFlavor", str::asString(media::MediaCurl2::distributionFlavorHeader()) );
463 _dispatcher->setHostSpecificHeader ("download.opensuse.org", "X-ZYpp-AnonymousId", str::asString(media::MediaCurl2::anonymousIdHeader()) );
464 _dispatcher->setHostSpecificHeader ("cdn.opensuse.org", "X-ZYpp-DistributionFlavor", str::asString(media::MediaCurl2::distributionFlavorHeader()) );
465 _dispatcher->setHostSpecificHeader ("cdn.opensuse.org", "X-ZYpp-AnonymousId", str::asString(media::MediaCurl2::anonymousIdHeader()) );
466 _dispatcher->run();
467
468 _pTracker = std::make_shared<internal::ProgressTracker>();
469 _requiredBytes = 0;
471 _missedDownloads = false;
472 _lastProgressUpdate.reset();
473
474 zypp_defer {
475 _dispatcher.reset();
476 _pTracker.reset();
477 };
478
479 for ( const auto &step : steps ) {
480 switch ( step.stepType() )
481 {
484 // proceed: only install actions may require download.
485 break;
486
487 default:
488 // next: no download for non-packages and delete actions.
489 continue;
490 break;
491 }
492
493 PoolItem pi(step.satSolvable());
494
495 if ( !pi->isKind<Package>() && !pi->isKind<SrcPackage>() )
496 continue;
497
498 // no checksum ,no predownload, Fetcher would ignore it
499 if ( pi->lookupLocation().checksum().empty() )
500 continue;
501
502 // check if Package is cached already
503 if( !pckCachedLocation(pi).empty() )
504 continue;
505
506 auto repoDlsIter = _dlRepoInfo.find( pi.repository().id() );
507 if ( repoDlsIter == _dlRepoInfo.end() ) {
508
509 // make sure download path for this repo exists
510 if ( filesystem::assert_dir( pi.repoInfo().predownloadPath() ) != 0 ) {
511 ERR << "Failed to create predownload cache for repo " << pi.repoInfo().alias() << std::endl;
512 return;
513 }
514
515 // filter base URLs that do not download
516 std::vector<RepoUrl> repoUrls;
517 const auto origins = pi.repoInfo().repoOrigins();
518 for ( const auto &origin: origins ) {
519 std::for_each( origin.begin(), origin.end(), [&]( const zypp::OriginEndpoint &u ) {
520 media::UrlResolverPlugin::HeaderList custom_headers;
521 Url url = media::UrlResolverPlugin::resolveUrl(u.url(), custom_headers);
522
523 if ( media::MediaHandlerFactory::handlerType(url) != media::MediaHandlerFactory::MediaCURLType )
524 return;
525
526 // use geo IP if available
527 {
528 const auto rewriteUrl = media::MediaNetworkCommonHandler::findGeoIPRedirect( url );
529 if ( rewriteUrl.isValid () )
530 url = rewriteUrl;
531 }
532
533 if ( !pi.repoInfo().path().emptyOrRoot() )
534 url.appendPathName( pi.repoInfo().path() );
535
536 MIL << "Adding Url: " << url << " to the mirror set" << std::endl;
537
538 repoUrls.push_back( RepoUrl {
539 .baseUrl = std::move(url),
540 .headers = std::move(custom_headers)
541 } );
542 });
543 }
544
545 // skip this solvable if it has no downloading base URLs
546 if( repoUrls.empty() ) {
547 MIL << "Skipping predownload for " << step.satSolvable() << " no downloading URL" << std::endl;
548 continue;
549 }
550
551 // TODO here we could block to fetch mirror informations, either if the RepoInfo has a metalink or mirrorlist entry
552 // or if the hostname of the repo is d.o.o
553 if ( repoUrls.begin()->baseUrl.getHost() == "download.opensuse.org" ){
554 //auto req = std::make_shared<zyppng::NetworkRequest>( );
555 }
556
557 _dlRepoInfo.insert( std::make_pair(
558 pi.repository().id(),
560 ._baseUrls = std::move(repoUrls)
561 }
562 ));
563 }
564
565
566 _requiredBytes += pi.lookupLocation().downloadSize();
567 _requiredDls.push_back( pi );
568 }
569
570 if ( _requiredDls.empty() )
571 return;
572
573 // order by repo
574 std::sort( _requiredDls.begin(), _requiredDls.end(), []( const PoolItem &a , const PoolItem &b ) { return a.repository() < b.repository(); });
575
576 const auto &workerDone = [&, this](){
577 if ( std::all_of( _workers.begin(), _workers.end(), []( const auto &w ) { return w->finished();} ) )
578 ev->quit();
579 };
580
581 _report->start();
582 zypp_defer {
583 _report->finish( _missedDownloads ? media::CommitPreloadReport::MISS : media::CommitPreloadReport::SUCCESS );
584 };
585
586 MIL << "Downloading packages via " << MediaConfig::instance().download_max_concurrent_connections() << " connections." << std::endl;
587
588 // we start a worker for each configured connection
589 for ( int i = 0; i < MediaConfig::instance().download_max_concurrent_connections() ; i++ ) {
590 // if we run out of jobs before we started all workers, stop
591 if (_requiredDls.empty())
592 break;
593 auto worker = std::make_shared<PreloadWorker>(*this);
594 worker->sigWorkerFinished().connect(workerDone);
595 worker->nextJob();
596 _workers.push_back( std::move(worker) );
597 }
598
599 if( std::any_of( _workers.begin(), _workers.end(), []( const auto &w ) { return !w->finished(); } ) ) {
600 MIL << "Running preload event loop!" << std::endl;
601 ev->run();
602 }
603
604 MIL << "Preloading done, mirror stats: " << std::endl;
605 for ( const auto &elem : _dlRepoInfo ) {
606 std::for_each ( elem.second._baseUrls.begin (), elem.second._baseUrls.end(), []( const RepoUrl &repoUrl ){
607 MIL << "url: " << repoUrl.baseUrl << " misses: " << repoUrl.miss << std::endl;
608 });
609 }
610 MIL << "Preloading done, mirror stats end" << std::endl;
611 }
612
614 {
615 if ( !preloadEnabled() ) {
616 MIL << "CommitPackagePreloader disabled" << std::endl;
617 return;
618 }
619 std::for_each( _dlRepoInfo.begin (), _dlRepoInfo.end(), []( const auto &elem ){
620 filesystem::clean_dir ( Repository(elem.first).info().predownloadPath() );
621 });
622 }
623
625 {
626 return _missedDownloads;
627 }
628
630 {
631 // throttle progress updates to one time per second
632 const auto now = clock::now();
633 bool canUpdate = false;
634 if ( _lastProgressUpdate ) {
635 const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - *_lastProgressUpdate);
636 canUpdate = (duration >= std::chrono::milliseconds(500));
637 } else {
638 canUpdate = true;
639 }
640
641 _downloadedBytes += newBytes;
643
644 // update progress one time per second
645 if( canUpdate ) {
647 callback::UserData userData( "CommitPreloadReport/progress" );
648 userData.set( "dbps_avg" , static_cast<double>( _pTracker->_drateTotal ) );
649 userData.set( "dbps_current", static_cast<double>( _pTracker->_drateLast ) );
650 userData.set( "bytesReceived", static_cast<double>( _pTracker->_dnlNow ) );
651 userData.set( "bytesRequired", static_cast<double>( _pTracker->_dnlTotal ) );
652 if ( !_report->progress( _pTracker->_dnlPercent, userData ) ) {
653 _missedDownloads = true;
654 _requiredDls.clear();
655 _dispatcher->cancelAll( _("Cancelled by user."));
656 }
657 }
658 }
659
660}
#define zypp_defer
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
Store and operate with byte count.
Definition ByteCount.h:32
void onRequestProgress(zyppng::NetworkRequest &req, zypp::ByteCount count)
RepoUrl * findUsableMirror(RepoUrl *skip=nullptr, bool allowTainted=true)
Tries to find a usable mirror.
void makeJobUrl(zypp::Url &resultUrl, media::TransferSettings &resultSet)
void onRequestStarted(zyppng::NetworkRequest &req)
bool taintCurrentMirror()
Taints the current mirror, returns true if a alternative was found.
void onRequestFinished(zyppng::NetworkRequest &req, const zyppng::NetworkRequestError &err)
void finishCurrentJob(const zypp::Pathname &localPath, const std::optional< zypp::Url > &url, media::CommitPreloadReport::Error e, const std::optional< std::string > &errorMessage, bool fatal)
callback::SendReport< media::CommitPreloadReport > _report
std::optional< clock::time_point > _lastProgressUpdate
zyppng::Ref< internal::ProgressTracker > _pTracker
std::map< Repository::IdType, RepoDownloadData > _dlRepoInfo
void reportBytesDownloaded(ByteCount newBytes)
void preloadTransaction(const std::vector< sat::Transaction::Step > &steps)
zyppng::NetworkRequestDispatcherRef _dispatcher
Base class for Exception.
Definition Exception.h:153
std::string asUserString() const
Translated error message as string suitable for the user.
Definition Exception.cc:131
long download_max_concurrent_connections() const
static MediaConfig & instance()
static Url rewriteUrl(const Url &url_r, const media::MediaNr medianr)
Replaces media number in specified url with given medianr.
Represents a single, configurable network endpoint, combining a URL with specific access settings.
Package interface.
Definition Package.h:34
Combining sat::Solvable and ResStatus.
Definition PoolItem.h:51
Pathname predownloadPath() const
Path where this repo packages are predownloaded.
Definition RepoInfo.cc:759
MirroredOriginSet repoOrigins() const
The repodata origins.
Definition RepoInfo.cc:733
Pathname path() const
Repository path.
Definition RepoInfo.cc:822
IdType id() const
Expert backdoor.
Definition Repository.h:321
sat::detail::RepoIdType IdType
Definition Repository.h:44
SrcPackage interface.
Definition SrcPackage.h:30
Url manipulation class.
Definition Url.h:93
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:971
Typesafe passing of user data via callbacks.
Definition UserData.h:40
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition UserData.h:119
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
bool emptyOrRoot() const
Test for "" or "/".
Definition Pathname.h:127
static ManagedFile asManagedFile()
Create a temporary file and convert it to a automatically cleaned up ManagedFile.
Definition TmpPath.cc:200
bool authenticate(const Url &url, TransferSettings &settings, const std::string &availAuthTypes, bool firstTry)
Holds transfer setting.
void addHeader(std::string &&val_r)
add a header, on the form "Foo: Bar" (trims)
std::multimap< std::string, std::string > HeaderList
std::string alias() const
unique identifier for this source.
@ TRANSACTION_MULTIINSTALL
[M] Install(multiversion) item (
Definition Transaction.h:67
@ TRANSACTION_INSTALL
[+] Install(update) item
Definition Transaction.h:66
WeakPtr parent() const
Definition base.cc:26
static Ptr create()
The NetworkRequestError class Represents a error that occured in.
std::string toString() const
toString Returns a string representation of the error
bool hasError() const
Checks if there was a error with the request.
Definition request.cc:1035
SignalProxy< void(NetworkRequest &req, const NetworkRequestError &err)> sigFinished()
Signals that the download finished.
Definition request.cc:1079
SignalProxy< void(NetworkRequest &req, zypp::ByteCount count)> sigBytesDownloaded()
Signals that new data has been downloaded, this is only the payload and does not include control data...
Definition request.cc:1069
std::string extendedErrorString() const
In some cases, curl can provide extended error information collected at runtime.
Definition request.cc:1027
NetworkRequestError error() const
Returns the last set Error.
Definition request.cc:1019
SignalProxy< void(NetworkRequest &req)> sigStarted()
Signals that the dispatcher dequeued the request and actually starts downloading data.
Definition request.cc:1064
TransferSettings & transferSettings()
Definition request.cc:995
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
unsigned short a
unsigned short b
void prepareSettingsAndUrl(zypp::Url &url_r, zypp::media::TransferSettings &s)
String related utilities and Regular expression matching.
TriBool getenvBool(const C_Str &var_r)
If the environment variable var_r is set to a legal true or false string return bool,...
Definition Env.h:32
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition PathInfo.cc:385
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:719
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:338
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition PathInfo.cc:761
int chmodApplyUmask(const Pathname &path, mode_t mode)
Similar to 'chmod', but mode is modified by the process's umask in the usual way.
Definition PathInfo.cc:1120
static const RepoIdType noRepoId(0)
Id to denote Repo::noRepository.
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition String.h:140
Url details namespace.
Definition UrlBase.cc:58
Easy-to use interface to the ZYPP dependency resolver.
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition ManagedFile.h:27
std::string asString(const Patch::Category &obj)
Definition Patch.cc:122
Pathname cachedLocation(const OnMediaLocation &loc_r, const RepoInfo &repo_r)
Definition Package.cc:99
media::UrlResolverPlugin::HeaderList headers
RepoInfo repoInfo() const
Repository repository() const
Convenient building of std::string with boost::format.
Definition String.h:254