libzypp 17.38.3
repodownloaderwf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "repodownloaderwf.h"
10#include <fstream>
11#include <utility>
12
15#include <zypp-media/ng/ProvideSpec>
16
17#include <zypp/KeyRing.h>
18#include <zypp/ZConfig.h>
19
20#include <zypp/ng/Context>
21#include <zypp/ng/media/Provide>
22#include <zypp/ng/repo/Downloader>
27
31
35
36#undef ZYPP_BASE_LOGGER_LOGGROUP
37#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::repomanager"
38
39
40namespace zyppng {
41 namespace {
42
43 using namespace zyppng::operators;
44
45 struct DownloadMasterIndexLogic
46 {
47 public:
48 using MediaHandle = typename Provide::MediaHandle;
49 using ProvideRes = typename Provide::Res;
50
51 DownloadMasterIndexLogic( repo::DownloadContextRef &&ctxRef, MediaHandle &&mediaHandle, zypp::filesystem::Pathname &&masterIndex_r )
52 : _dlContext( std::move(ctxRef) )
53 , _media(std::move( mediaHandle ))
54 , _masterIndex(std::move( masterIndex_r ))
55 { }
56
57 public:
58 MaybeAwaitable<expected<repo::DownloadContextRef>> execute( ) {
59
60 zypp::RepoInfo ri = _dlContext->repoInfo();
61 // always download them, even if repoGpgCheck is disabled
62 _sigpath = _masterIndex.extend( ".asc" );
63 _keypath = _masterIndex.extend( ".key" );
64 _destdir = _dlContext->destDir();
65
66 auto providerRef = _dlContext->zyppContext()->provider();
67 return provider()->provide( _media, _masterIndex, ProvideFileSpec().setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ).setMirrorsAllowed( false ) )
68 | and_then( [this]( ProvideRes && masterres ) {
69 // update the gpg keys provided by the repo
70 return RepoInfoWorkflow::fetchGpgKeys( _dlContext->zyppContext(), _dlContext->repoInfo() )
71 | and_then( [this](){
72
73 // fetch signature and maybe key file
74 return provider()->provide( _media, _sigpath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ).setMirrorsAllowed( false ) )
75
76 | and_then( Provide::copyResultToDest ( provider(), _destdir / _sigpath ) )
77
78 | [this]( expected<zypp::ManagedFile> sigFile ) {
79 zypp::Pathname sigpathLocal { _destdir/_sigpath };
80 if ( !sigFile.is_valid () || !zypp::PathInfo(sigpathLocal).isExist() ) {
81 return makeReadyTask(expected<void>::success()); // no sigfile, valid result
82 }
83 _dlContext->files().push_back( std::move(*sigFile) );
84
85 // check if we got the key, if not we fall back to downloading the .key file
86 auto expKeyId = mtry( &KeyRing::readSignatureKeyId, _dlContext->zyppContext()->keyRing(), sigpathLocal );
87 if ( expKeyId && !_dlContext->zyppContext()->keyRing()->isKeyKnown(*expKeyId) ) {
88
89 bool needsMirrorToFetchKey = _dlContext->repoInfo().baseUrlsEmpty() && _dlContext->repoInfo().mirrorListUrl().isValid() ;
90 if ( needsMirrorToFetchKey ) {
91 // when dealing with mirrors we notify the user to use gpgKeyUrl instead of
92 // fetching the gpg key from any mirror
93 JobReportHelper( _dlContext->zyppContext() ).warning(_("Downloading signature key via mirrors, consider explicitely setting gpgKeyUrl via the repository configuration instead."));
94 }
95
96 // we did not get the key via gpgUrl downloads, lets fallback
97 return provider()->provide( _media, _keypath, ProvideFileSpec().setOptional( true ).setDownloadSize( zypp::ByteCount( 20, zypp::ByteCount::MB ) ).setMirrorsAllowed(needsMirrorToFetchKey) )
98 | and_then( Provide::copyResultToDest ( provider(), _destdir / _keypath ) )
99 | and_then( [this]( zypp::ManagedFile keyFile ) {
100 _dlContext->files().push_back( std::move(keyFile));
102 });
103 }
104
105 // we should not reach this line, but if we do we continue and fail later if its required
106 return makeReadyTask(expected<void>::success());
107 };
108 })
109 | [masterres=std::move(masterres)]( expected<void> ) {
110 return make_expected_success( std::move(masterres) );
111 };
112
113 } )
114 // execute plugin verification if there is one
115 | and_then( std::bind( &DownloadMasterIndexLogic::pluginVerification, this, std::placeholders::_1 ) )
116
117 // signature checking
118 | and_then( std::bind( &DownloadMasterIndexLogic::signatureCheck, this, std::placeholders::_1 ) )
119
120 // copy everything into a directory
121 | and_then( Provide::copyResultToDest ( providerRef, _destdir / _masterIndex ) )
122
123 // final tasks
124 | and_then([this]( zypp::ManagedFile &&masterIndex ) {
125 // Accepted!
126 _dlContext->repoInfo().setMetadataPath( _destdir );
127 _dlContext->repoInfo().setValidRepoSignature( _repoSigValidated );
128
129 // release the media handle
130 _media = MediaHandle();
131 auto &allFiles = _dlContext->files();
132
133 // make sure the masterIndex is in front
134 allFiles.insert( allFiles.begin (), std::move(masterIndex) );
135 return make_expected_success( std::move(_dlContext) );
136 });
137 }
138
139
140 private:
141 ProvideRef provider () {
142 return _dlContext->zyppContext()->provider();
143 }
144
145 MaybeAwaitable<expected<ProvideRes>> signatureCheck ( ProvideRes &&res ) {
146
147 if ( _dlContext->repoInfo().repoGpgCheck() ) {
148
149 // The local files are in destdir_r, if they were present on the server
150 zypp::Pathname sigpathLocal { _destdir/_sigpath };
151 zypp::Pathname keypathLocal { _destdir/_keypath };
152 bool isSigned = zypp::PathInfo(sigpathLocal).isExist();
153
154 if ( isSigned || _dlContext->repoInfo().repoGpgCheckIsMandatory() ) {
155
156 auto verifyCtx = zypp::keyring::VerifyFileContext( res.file() );
157
158 // only add the signature if it exists
159 if ( isSigned )
160 verifyCtx.signature( sigpathLocal );
161
162 // only add the key if it exists
163 if ( zypp::PathInfo(keypathLocal).isExist() ) {
164 try {
165 _dlContext->zyppContext()->keyRing()->importKey( zypp::PublicKey(keypathLocal), false );
166 } catch (...) {
167 return makeReadyTask( expected<ProvideRes>::error( ZYPP_FWD_CURRENT_EXCPT() ) );
168 }
169 }
170
171 // set the checker context even if the key is not known
172 // (unsigned repo, key file missing; bnc #495977)
173 verifyCtx.keyContext( _dlContext->repoInfo() );
174
175 return getExtraKeysInRepomd( std::move(res ) )
176 | and_then([this, vCtx = std::move(verifyCtx) ]( ProvideRes &&res ) mutable {
177 for ( const auto &keyData : _buddyKeys ) {
178 DBG << "Keyhint remember buddy " << keyData << std::endl;
179 vCtx.addBuddyKey( keyData.id() );
180 }
181
182 return SignatureFileCheckWorkflow::verifySignature( _dlContext->zyppContext(), std::move(vCtx))
183 | and_then([ this, res = std::move(res) ]( zypp::keyring::VerifyFileContext verRes ){
184 // remember the validation status
185 _repoSigValidated = verRes.fileValidated();
186 return make_expected_success(std::move(res));
187 });
188 });
189
190 } else {
191 WAR << "Accept unsigned repository because repoGpgCheck is not mandatory for " << _dlContext->repoInfo().alias() << std::endl;
192 }
193 } else {
194 WAR << "Signature checking disabled in config of repository " << _dlContext->repoInfo().alias() << std::endl;
195 }
196 return makeReadyTask(expected<ProvideRes>::success(res));
197 }
198
199 // execute the repo verification if there is one
200 expected<ProvideRes> pluginVerification ( ProvideRes &&prevRes ) {
201 // The local files are in destdir_r, if they were present on the server
202 zypp::Pathname sigpathLocal { _destdir/_sigpath };
203 zypp::Pathname keypathLocal { _destdir/_keypath };
204
205 if ( _dlContext->pluginRepoverification() && _dlContext->pluginRepoverification()->isNeeded() ) {
206 try {
207
208 if ( zypp::PathInfo(sigpathLocal).isExist() && !zypp::PathInfo(keypathLocal).isExist() ) {
209 auto kr = _dlContext->zyppContext()->keyRing();
210 // if we have a signature but no keyfile, we need to export it from the keyring
211 auto expKeyId = mtry( &KeyRing::readSignatureKeyId, kr.get(), sigpathLocal );
212 if ( !expKeyId ) {
213 MIL << "Failed to read signature from file: " << sigpathLocal << std::endl;
214 } else {
215 std::ofstream os( keypathLocal.c_str() );
216 if ( kr->isKeyKnown(*expKeyId) ) {
217 kr->dumpPublicKey(
218 *expKeyId,
219 kr->isKeyTrusted(*expKeyId),
220 os
221 );
222 }
223 }
224 }
225
226 _dlContext->pluginRepoverification()->getChecker( sigpathLocal, keypathLocal, _dlContext->repoInfo() )( prevRes.file() );
227 } catch ( ... ) {
228 return expected<ProvideRes>::error( std::current_exception () );
229 }
230 }
231 return make_expected_success(std::move(prevRes));
232 }
233
238 MaybeAwaitable<expected<ProvideRes>> getExtraKeysInRepomd ( ProvideRes &&res ) {
239
240 if ( _masterIndex.basename() != "repomd.xml" ) {
241 return makeReadyTask( expected<ProvideRes>::success( std::move(res) ) );
242 }
243
244 std::vector<std::pair<std::string,std::string>> keyhints { zypp::parser::yum::RepomdFileReader(res.file()).keyhints() };
245 if ( keyhints.empty() )
246 return makeReadyTask( expected<ProvideRes>::success( std::move(res) ) );
247 DBG << "Check keyhints: " << keyhints.size() << std::endl;
248
249 auto keyRing { _dlContext->zyppContext()->keyRing() };
251 | transform( [this, keyRing]( std::pair<std::string, std::string> val ) {
252
253 const auto& [ file, keyid ] = val;
254 auto keyData = keyRing->trustedPublicKeyData( keyid );
255 if ( keyData ) {
256 DBG << "Keyhint is already trusted: " << keyid << " (" << file << ")" << std::endl;
257 return makeReadyTask ( expected<zypp::PublicKeyData>::success(keyData) ); // already a trusted key
258 }
259
260 DBG << "Keyhint search key " << keyid << " (" << file << ")" << std::endl;
261
262 keyData = keyRing->publicKeyData( keyid );
263 if ( keyData )
264 return makeReadyTask( expected<zypp::PublicKeyData>::success(keyData) );
265
266 // TODO: Enhance the key caching in general...
267 const zypp::ZConfig & conf = _dlContext->zyppContext()->config();
268 zypp::Pathname cacheFile = conf.repoManagerRoot() / conf.pubkeyCachePath() / file;
269
270 return zypp::PublicKey::noThrow(cacheFile)
271 | [ keyid = keyid ]( auto &&key ){
272 if ( key.fileProvidesKey( keyid ) )
273 return make_expected_success( std::forward<decltype(key)>(key) );
274 else
275 return expected<zypp::PublicKey>::error( std::make_exception_ptr (zypp::Exception("File does not provide key")));
276 }
277 | or_else ([ this, file = file, keyid = keyid, cacheFile ] ( auto ) mutable -> MaybeAwaitable<expected<zypp::PublicKey>> {
278 auto providerRef = _dlContext->zyppContext()->provider();
279 return providerRef->provide( _media, file, ProvideFileSpec().setOptional(true).setMirrorsAllowed(false) )
280 | and_then( Provide::copyResultToDest( providerRef, _destdir / file ) )
281 | and_then( [this, providerRef, file, keyid , cacheFile = std::move(cacheFile)]( zypp::ManagedFile &&res ) {
282
283 // remember we downloaded the file
284 _dlContext->files().push_back ( std::move(res) );
285
286 auto key = zypp::PublicKey::noThrow( _dlContext->files().back() );
287 if ( not key.fileProvidesKey( keyid ) ) {
288 const std::string str = (zypp::str::Str() << "Keyhint " << file << " does not contain a key with id " << keyid << ". Skipping it.");
289 WAR << str << std::endl;
290 return makeReadyTask(expected<zypp::PublicKey>::error( std::make_exception_ptr( zypp::Exception(str)) ));
291 }
292
293 // Try to cache it...
295 return providerRef->copyFile( key.path(), cacheFile )
296 | [ key ]( expected<zypp::ManagedFile> res ) mutable {
297 if ( res ) {
298 // do not delete from cache
299 res->resetDispose ();
300 }
301 return expected<zypp::PublicKey>::success( std::move(key) );
302 };
303 });
304 })
305 | and_then( [ keyRing, keyid = keyid ]( zypp::PublicKey key ){
306 keyRing->importKey( key, false ); // store in general keyring (not trusted!)
307 return expected<zypp::PublicKeyData>::success(keyRing->publicKeyData( keyid )); // fetch back from keyring in case it was a hidden key
308 });
309 })
310 | [this, res = res] ( std::vector<expected<zypp::PublicKeyData>> &&keyHints ) mutable {
311 std::for_each( keyHints.begin(), keyHints.end(), [this]( expected<zypp::PublicKeyData> &keyData ){
312 if ( keyData && *keyData ) {
313 if ( not zypp::PublicKey::isSafeKeyId( keyData->id() ) ) {
314 WAR << "Keyhint " << keyData->id() << " for " << *keyData << " is not strong enough for auto import. Just caching it." << std::endl;
315 return;
316 }
317 _buddyKeys.push_back ( std::move(keyData.get()) );
318 }
319 });
320
321 MIL << "Check keyhints done. Buddy keys: " << _buddyKeys.size() << std::endl;
322 return expected<ProvideRes>::success (std::move(res));
323 };
324 }
325
326 repo::DownloadContextRef _dlContext;
327 MediaHandle _media;
328 zypp::Pathname _masterIndex;
329
330 zypp::Pathname _destdir;
331 zypp::Pathname _sigpath;
332 zypp::Pathname _keypath;
333 zypp::TriBool _repoSigValidated = zypp::indeterminate;
334
335 std::vector<zypp::PublicKeyData> _buddyKeys;
336 };
337
338 }
339
340 MaybeAwaitable<expected<repo::DownloadContextRef> > RepoDownloaderWorkflow::downloadMasterIndex(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::Pathname masterIndex_r)
341 {
342 DownloadMasterIndexLogic impl( std::move(dl), std::move(mediaHandle), std::move(masterIndex_r) );
343 zypp_co_return zypp_co_await( impl.execute() );
344 }
345
346 MaybeAwaitable<expected<repo::DownloadContextRef>> RepoDownloaderWorkflow::downloadMasterIndex ( repo::DownloadContextRef dl, LazyMediaHandle<Provide> mediaHandle, zypp::filesystem::Pathname masterIndex_r )
347 {
348 using namespace zyppng::operators;
349 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
350 | and_then([ dl, mi = std::move(masterIndex_r) ]( ProvideMediaHandle handle ) mutable {
351 return downloadMasterIndex( std::move(dl), std::move(handle), std::move(mi) );
352 });
353 }
354
355
356 namespace {
357 auto statusImpl ( repo::DownloadContextRef dlCtx, ProvideMediaHandle &&mediaHandle ) {
358 const auto finalizeStatus = [ dlCtx ]( zypp::RepoStatus status ){
359 return expected<zypp::RepoStatus>::success( zypp::RepoStatus( dlCtx->repoInfo()) && status );
360 };
361
362 switch( dlCtx->repoInfo().type().toEnum()) {
364 return RpmmdWorkflows::repoStatus( dlCtx, std::forward<ProvideMediaHandle>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
366 return SuseTagsWorkflows::repoStatus( dlCtx, std::forward<ProvideMediaHandle>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
368 return PlaindirWorkflows::repoStatus ( dlCtx, std::forward<ProvideMediaHandle>(mediaHandle) ) | and_then( std::move(finalizeStatus) );
370 break;
371 }
372
373 return makeReadyTask<expected<zypp::RepoStatus>>( expected<zypp::RepoStatus>::error( ZYPP_EXCPT_PTR (zypp::repo::RepoUnknownTypeException(dlCtx->repoInfo()))) );
374 }
375 }
376
377 MaybeAwaitable<expected<zypp::RepoStatus> > RepoDownloaderWorkflow::repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle) {
378 return statusImpl( dl, std::move(mediaHandle) );
379 }
380
381 MaybeAwaitable<expected<zypp::RepoStatus> > RepoDownloaderWorkflow::repoStatus( repo::DownloadContextRef dl, LazyMediaHandle<Provide> mediaHandle ) {
382 using namespace zyppng::operators;
383 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
384 | and_then([ dl ]( ProvideMediaHandle handle ) {
385 return repoStatus( dl, std::move(handle) );
386 });
387 }
388
389 namespace {
390 auto downloadImpl ( repo::DownloadContextRef dlCtx, ProvideMediaHandle &&mediaHandle, ProgressObserverRef &&progressObserver ) {
391 switch( dlCtx->repoInfo().type().toEnum()) {
393 return RpmmdWorkflows::download( std::move(dlCtx), std::forward<ProvideMediaHandle>(mediaHandle), std::move(progressObserver) );
395 return SuseTagsWorkflows::download( std::move(dlCtx), std::forward<ProvideMediaHandle>(mediaHandle), std::move(progressObserver) );
397 return PlaindirWorkflows::download ( std::move(dlCtx), std::forward<ProvideMediaHandle>(mediaHandle) );
399 break;
400 }
401
402 return makeReadyTask<expected<repo::DownloadContextRef> >( expected<repo::DownloadContextRef>::error( ZYPP_EXCPT_PTR (zypp::repo::RepoUnknownTypeException(dlCtx->repoInfo()))) );
403 }
404 }
405
406 MaybeAwaitable<expected<repo::DownloadContextRef> > RepoDownloaderWorkflow::download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
407 {
408 return downloadImpl( dl, std::move(mediaHandle), std::move(progressObserver) );
409 }
410
411 MaybeAwaitable<expected<repo::DownloadContextRef> > RepoDownloaderWorkflow::download(repo::DownloadContextRef dl, LazyMediaHandle<Provide> mediaHandle, ProgressObserverRef progressObserver)
412 {
413 using namespace zyppng::operators;
414 return dl->zyppContext()->provider()->attachMediaIfNeeded( mediaHandle )
415 | and_then([ dl, po = std::move(progressObserver) ]( ProvideMediaHandle handle ) mutable {
416 return downloadImpl( dl, std::move(handle), std::move(po) );
417 });
418 }
419}
#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 _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define WAR
Definition Logger.h:101
Interface of repomd.xml file reader.
Store and operate with byte count.
Definition ByteCount.h:32
static const Unit MB
1000^2 Byte
Definition ByteCount.h:61
Base class for Exception.
Definition Exception.h:153
std::string readSignatureKeyId(const Pathname &signature)
reads the public key id from a signature
Definition KeyRing.cc:195
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:358
static PublicKey noThrow(const Pathname &keyFile_r)
Static ctor returning an empty PublicKey rather than throwing.
Definition PublicKey.cc:634
What is known about a repository.
Definition RepoInfo.h:72
Track changing files or directories.
Definition RepoStatus.h:41
Interim helper class to collect global options and settings.
Definition ZConfig.h:82
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition ZConfig.cc:1011
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition ZConfig.cc:1106
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
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
I/O context for KeyRing::verifyFileSignatureWorkflow.
bool fileValidated() const
Whether the signature was actually successfully verified.
Reads through a repomd.xml file and collects type, location, checksum and other data about metadata f...
std::vector< std::pair< std::string, std::string > > keyhints() const
gpg key hits shipped in keywords (bsc#1184326)
thrown when it was impossible to determine this repo type.
bool warning(std::string msg_r, UserData userData_r=UserData())
send warning text
ProvideRes Res
Definition provide.h:111
static auto copyResultToDest(ProvideRef provider, const zypp::Pathname &targetPath)
Definition provide.h:139
ProvideMediaHandle MediaHandle
Definition provide.h:109
static expected success(ConsParams &&...params)
Definition expected.h:178
static expected error(ConsParams &&...params)
Definition expected.h:189
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition String.h:31
String related utilities and Regular expression matching.
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:338
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition ManagedFile.h:27
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
Definition plaindir.cc:75
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
Definition plaindir.cc:38
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver=nullptr)
MaybeAwaitable< expected< repo::DownloadContextRef > > downloadMasterIndex(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, zypp::filesystem::Pathname masterIndex_r)
MaybeAwaitable< expected< void > > fetchGpgKeys(ContextRef ctx, zypp::RepoInfo info)
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
Definition rpmmd.cc:155
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
Definition rpmmd.cc:68
MaybeAwaitable< expected< zypp::keyring::VerifyFileContext > > verifySignature(ContextRef ctx, zypp::keyring::VerifyFileContext context)
MaybeAwaitable< expected< repo::DownloadContextRef > > download(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle, ProgressObserverRef progressObserver)
Definition susetags.cc:312
MaybeAwaitable< expected< zypp::RepoStatus > > repoStatus(repo::DownloadContextRef dl, ProvideMediaHandle mediaHandle)
Definition susetags.cc:78
auto and_then(Fun &&function)
Definition expected.h:708
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition expected.h:470
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
auto mtry(F &&f, Args &&...args)
Definition mtry.h:50
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213