libzypp  17.36.7
downloadwf.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
9 
10 #include "downloadwf.h"
12 
13 #include <utility>
14 #include <zypp/ng/Context>
17 
18 
19 #include <zypp-core/fs/PathInfo.h>
20 #include <zypp-core/zyppng/pipelines/Algorithm>
21 
22 #include <zypp-media/ng/Provide>
23 #include <zypp-media/ng/ProvideSpec>
24 
25 namespace zyppng {
26 
27  template<typename ZyppContextRefType>
28  CacheProviderContext<ZyppContextRefType>::CacheProviderContext( ZYPP_PRIVATE_CONSTR_ARG, ZyppContextRefType zyppContext, zypp::Pathname destDir )
29  : _zyppContext( std::move(zyppContext) )
30  , _destDir( std::move(destDir) )
31  { }
32 
33 
34  template<typename ZyppContextRefType>
36  {
37  return _zyppContext;
38  }
39 
40 
41  template<typename ZyppContextRefType>
43  {
44  return _destDir;
45  }
46 
47  template<typename ZyppContextRefType>
49  {
50  _cacheDirs.push_back ( p );
51  }
52 
53  template<typename ZyppContextRefType>
54  const std::vector<zypp::Pathname> &CacheProviderContext<ZyppContextRefType>::cacheDirs() const
55  {
56  return _cacheDirs;
57  }
58 
59 
60  template class CacheProviderContext<ContextRef>;
62 
63 
64  namespace {
65 
66  using namespace zyppng::operators;
67 
68  class CacheMissException : public zypp::Exception
69  {
70  public:
71  CacheMissException( const zypp::Pathname &filename )
72  : zypp::Exception( zypp::str::Str() << filename << " not found in target cache" ) { }
73  };
74 
75  template <class T>
76  struct showme;
77 
78  template <class Executor, class OpType>
79  struct ProvideFromCacheOrMediumLogic : public LogicBase<Executor, OpType> {
80  protected:
81 
82  ZYPP_ENABLE_LOGIC_BASE(Executor, OpType);
83 
84  using CacheProviderContextRefType = std::conditional_t<detail::is_async_op_v<OpType>, AsyncCacheProviderContextRef, SyncCacheProviderContextRef>;
85  using ContextType = typename remove_smart_ptr_t<CacheProviderContextRefType>::ContextType;
86  using ProvideType = typename ContextType::ProvideType;
87  using MediaHandle = typename ProvideType::MediaHandle;
88  using ProvideRes = typename ProvideType::Res;
89 
90  public:
91  ProvideFromCacheOrMediumLogic( CacheProviderContextRefType cacheContext, MediaHandle &&medium, zypp::Pathname &&file, ProvideFileSpec &&filespec )
92  : _ctx( std::move(cacheContext) )
93  , _medium( std::move(medium) )
94  , _file(std::move( file ))
95  , _filespec( std::move(filespec) ) {}
96 
97  MaybeAsyncRef<expected<zypp::ManagedFile>> execute() {
98 
99  return findFileInCache( )
100  | [this]( expected<zypp::ManagedFile> cached ) -> MaybeAsyncRef<expected<zypp::ManagedFile>> {
101  if ( !cached ) {
102  MIL << "Didn't find " << _file << " in the caches, providing from medium" << std::endl;
103 
104  // we didn't find it in the caches or the lookup failed, lets provide and check it
105  std::shared_ptr<ProvideType> provider = _ctx->zyppContext()->provider();
106  return provider->provide( _medium, _file, _filespec )
107  | and_then( [this]( ProvideRes res ) {
108  return verifyFile( res.file() )
109  | and_then( [res = res]() {
110  return expected<ProvideRes>::success( std::move(res) );
111  });
112  })
113  | and_then( ProvideType::copyResultToDest( _ctx->zyppContext()->provider(), _ctx->destDir() / _file ) )
114  | and_then( []( zypp::ManagedFile &&file ){
115  file.resetDispose ();
116  return make_expected_success (std::move(file));
117  }) ;
118 
119  } else {
120 
121  return verifyFile ( cached.get() )
122  | and_then([ this, cachedFile = cached.get() ]() mutable {
123  if ( cachedFile == _ctx->destDir() / _file ) {
124  cachedFile.resetDispose(); // make sure dispose is reset
125  return makeReadyResult( expected<zypp::ManagedFile>::success(std::move(cachedFile) ));
126  }
127 
128  const auto &targetPath = _ctx->destDir() / _file;
129  zypp::filesystem::assert_dir( targetPath.dirname () );
130 
131  return _ctx->zyppContext()->provider()->copyFile( cachedFile, _ctx->destDir() / _file )
132  | and_then( [cachedFile]( zypp::ManagedFile &&f) { f.resetDispose(); return make_expected_success (std::move(f)); });
133  });
134  }
135  };
136  }
137 
138  protected:
143  MaybeAsyncRef<expected<zypp::ManagedFile>> findFileInCache( ) {
144 
145  // No checksum - no match
146  if ( _filespec.checksum().empty() )
147  return makeReadyResult( expected<zypp::ManagedFile>::error(std::make_exception_ptr( CacheMissException(_file) )) );
148 
149  const auto &confDirs = _ctx->cacheDirs();
150  const auto targetFile = _ctx->destDir() / _file ;
151  std::vector<zypp::Pathname> caches;
152  caches.push_back( _ctx->destDir() );
153  caches.insert( caches.end(), confDirs.begin(), confDirs.end() );
154 
155  auto makeSearchPipeline = [this, targetFile]( zypp::Pathname cachePath ){
156  zypp::Pathname cacheFilePath( cachePath / _file );
157  zypp::PathInfo cacheFileInfo( cacheFilePath );
158  if ( !cacheFileInfo.isExist () ) {
159  return makeReadyResult(expected<zypp::ManagedFile>::error( std::make_exception_ptr (CacheMissException(_file)) ));
160  } else {
161  auto provider = _ctx->zyppContext()->provider();
162 
163  // calc checksum, but do not use the workflow. Here we don't want to ask the user if a wrong checksum should
164  // be accepted
165  return provider->checksumForFile( cacheFilePath, _filespec.checksum().type() )
166  | and_then([this, cacheFilePath, targetFile]( zypp::CheckSum sum ) {
167 
168  auto mgdFile = zypp::ManagedFile( cacheFilePath );
169 
170  // if the file is in the target dir, make sure to release it if its not used
171  if ( cacheFilePath == targetFile )
172  mgdFile.setDispose ( zypp::filesystem::unlink );
173 
174  if ( sum == _filespec.checksum () ) {
175  // we found the file!
176  return expected<zypp::ManagedFile>::success( std::move(mgdFile) );
177  }
178 
179  return expected<zypp::ManagedFile>::error( std::make_exception_ptr (CacheMissException(_file)) );
180  });
181  }
182  };
183 
184  auto defVal = expected<zypp::ManagedFile>::error( std::make_exception_ptr (CacheMissException(_file) ) );
185  return std::move(caches) | firstOf( std::move(makeSearchPipeline), std::move(defVal), detail::ContinueUntilValidPredicate() );
186  }
187 
188  MaybeAsyncRef<expected<void>> verifyFile ( const zypp::Pathname &dlFilePath ) {
189 
190  return zypp::Pathname( dlFilePath )
191  | [this]( zypp::Pathname &&dlFilePath ) {
192  if ( !_filespec.checksum().empty () ) {
193  return CheckSumWorkflow::verifyChecksum( _ctx->zyppContext(), _filespec.checksum (), std::move(dlFilePath) );
194  }
196  };
197  // add other verifier here via and_then(), like a signature based one
198  }
199 
200  CacheProviderContextRefType _ctx;
201  MediaHandle _medium;
203  ProvideFileSpec _filespec;
204  };
205  }
206 
207  namespace DownloadWorkflow {
208 
209  AsyncOpRef<expected<zypp::ManagedFile> > provideToCacheDir( AsyncCacheProviderContextRef cacheContext, ProvideMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec )
210  {
211  return SimpleExecutor<ProvideFromCacheOrMediumLogic, AsyncOp<expected<zypp::ManagedFile>>>::run( std::move(cacheContext), std::move(medium), std::move(file), std::move(filespec) );
212  }
213 
214  expected<zypp::ManagedFile> provideToCacheDir(SyncCacheProviderContextRef cacheContext, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec )
215  {
216  return SimpleExecutor<ProvideFromCacheOrMediumLogic, SyncOp<expected<zypp::ManagedFile>>>::run( std::move(cacheContext), std::move(medium), std::move(file), std::move(filespec) );
217  }
218 
219  }
220 
221 }
#define MIL
Definition: Logger.h:100
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:324
CacheProviderContextRefType _ctx
Definition: downloadwf.cc:200
String related utilities and Regular expression matching.
Definition: Arch.h:363
static expected< std::decay_t< Type >, Err > make_expected_success(Type &&t)
Definition: expected.h:397
expected< zypp::ManagedFile > provideToCacheDir(SyncCacheProviderContextRef cacheContext, SyncMediaHandle medium, zypp::Pathname file, ProvideFileSpec filespec)
Definition: downloadwf.cc:214
ZyppContextRefType _zyppContext
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
auto firstOf(Transformation &&transformFunc, DefaultType &&def, Predicate &&predicate=detail::ContinueUntilValidPredicate())
Definition: algorithm.h:149
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition: logichelpers.h:223
typename conditional< B, T, F >::type conditional_t
Definition: TypeTraits.h:39
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition: asyncop.h:297
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:705
static expected success(ConsParams &&...params)
Definition: expected.h:115
std::shared_ptr< AsyncOp< T > > AsyncOpRef
Definition: asyncop.h:255
#define ZYPP_PRIVATE_CONSTR_ARG
Definition: zyppglobal.h:160
Base class for Exception.
Definition: Exception.h:146
auto and_then(Fun &&function)
Definition: expected.h:623
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
MediaHandle _medium
Definition: downloadwf.cc:201
expected< void > verifyChecksum(SyncContextRef zyppCtx, zypp::CheckSum checksum, zypp::Pathname file)
Definition: checksumwf.cc:115
ZyppContextRefType ContextRefType
Definition: downloadwf.h:32
ProvideFileSpec _filespec
Definition: downloadwf.cc:203
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
zypp::Pathname _file
Definition: downloadwf.cc:202