00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <list>
00014
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/base/PtrTypes.h"
00017 #include "zypp/base/DefaultIntegral.h"
00018 #include "zypp/Fetcher.h"
00019 #include "zypp/base/UserRequestException.h"
00020
00021 using namespace std;
00022
00024 namespace zypp
00025 {
00026
00031 struct FetcherJob
00032 {
00033 FetcherJob( const OnMediaLocation &loc )
00034 : location(loc)
00035 {
00036
00037 }
00038
00039 ~FetcherJob()
00040 {
00041
00042 }
00043
00044 OnMediaLocation location;
00045
00046 list<FileChecker> checkers;
00047 };
00048
00049 typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
00050
00052
00053
00054
00056 struct Fetcher::Impl
00057 {
00058
00059 public:
00060
00061 void enqueue( const OnMediaLocation &resource, const FileChecker &checker );
00062 void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker );
00063 void addCachePath( const Pathname &cache_dir );
00064 void reset();
00065 void start( const Pathname &dest_dir,
00066 MediaSetAccess &media,
00067 const ProgressData::ReceiverFnc & progress_receiver );
00068
00070 static shared_ptr<Impl> nullimpl()
00071 {
00072 static shared_ptr<Impl> _nullimpl( new Impl );
00073 return _nullimpl;
00074 }
00075
00076 private:
00077 friend Impl * rwcowClone<Impl>( const Impl * rhs );
00079 Impl * clone() const
00080 { return new Impl( *this ); }
00081
00082 std::list<FetcherJob_Ptr> _resources;
00083 std::list<Pathname> _caches;
00084 };
00086
00087
00088 void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
00089 {
00090 FetcherJob_Ptr job;
00091 job.reset(new FetcherJob(resource));
00092 ChecksumFileChecker digest_check(resource.checksum());
00093 job->checkers.push_back(digest_check);
00094 if ( checker )
00095 job->checkers.push_back(checker);
00096 _resources.push_back(job);
00097 }
00098
00099 void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
00100 {
00101 FetcherJob_Ptr job;
00102 job.reset(new FetcherJob(resource));
00103 if ( checker )
00104 job->checkers.push_back(checker);
00105 _resources.push_back(job);
00106 }
00107
00108 void Fetcher::Impl::reset()
00109 {
00110 _resources.clear();
00111 _caches.clear();
00112 }
00113
00114 void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
00115 {
00116 PathInfo info(cache_dir);
00117 if ( info.isDir() )
00118 {
00119 _caches.push_back(cache_dir);
00120 }
00121 else
00122 {
00123
00124 ERR << "Not adding cache: '" << cache_dir << "'. Not a direcotry." << endl;
00125 }
00126 }
00127
00128 void Fetcher::Impl::start( const Pathname &dest_dir,
00129 MediaSetAccess &media,
00130 const ProgressData::ReceiverFnc & progress_receiver )
00131 {
00132 ProgressData progress(_resources.size());
00133 progress.sendTo(progress_receiver);
00134
00135 for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
00136 {
00137 bool got_from_cache = false;
00138 for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
00139 {
00140
00141 Pathname cached_file = *it_cache + (*it_res)->location.filename();
00142 if ( PathInfo( cached_file ).isExist() )
00143 {
00144
00145 if ( is_checksum( cached_file, (*it_res)->location.checksum() ) && (! (*it_res)->location.checksum().empty() ) )
00146 {
00147
00148 MIL << "file " << (*it_res)->location.filename() << " found in previous cache. Using cached copy." << endl;
00149
00150
00151
00152
00153 Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
00154 if ( assert_dir( dest_full_path.dirname() ) != 0 )
00155 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00156
00157 if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
00158 {
00159
00160 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
00161
00162 continue;
00163 }
00164
00165 got_from_cache = true;
00166 break;
00167 }
00168 }
00169 }
00170
00171 if ( ! got_from_cache )
00172 {
00173
00174 try
00175 {
00176 Pathname tmp_file = media.provideFile((*it_res)->location);
00177 Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
00178 if ( assert_dir( dest_full_path.dirname() ) != 0 )
00179 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00180 if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
00181 {
00182 ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
00183 }
00184
00185
00186 }
00187 catch (const Exception & excpt_r)
00188 {
00189 ZYPP_CAUGHT(excpt_r);
00190 Exception nexcpt("Can't provide " + (*it_res)->location.filename().asString() + " : " + excpt_r.msg());
00191 nexcpt.remember(excpt_r);
00192 ZYPP_THROW(nexcpt);
00193 }
00194 }
00195 else
00196 {
00197
00198
00199 continue;
00200 }
00201
00202
00203 Pathname localfile = dest_dir + (*it_res)->location.filename();
00204
00205 try {
00206 MIL << "Checking job [" << localfile << "] (" << (*it_res)->checkers.size() << " checkers )" << endl;
00207 for ( list<FileChecker>::const_iterator it = (*it_res)->checkers.begin();
00208 it != (*it_res)->checkers.end();
00209 ++it )
00210 {
00211 if (*it)
00212 {
00213 (*it)(localfile);
00214 }
00215 else
00216 {
00217 ERR << "Invalid checker for '" << localfile << "'" << endl;
00218 }
00219 }
00220
00221 }
00222 catch ( const FileCheckException &e )
00223 {
00224 ZYPP_RETHROW(e);
00225 }
00226 catch ( const Exception &e )
00227 {
00228 ZYPP_RETHROW(e);
00229 }
00230 catch (...)
00231 {
00232 ZYPP_THROW(Exception("Unknown error while validating " + (*it_res)->location.filename().asString()));
00233 }
00234
00235 if ( ! progress.incr() )
00236 ZYPP_THROW(AbortRequestException());
00237 }
00238 }
00239
00241 inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
00242 {
00243 return str << "Fetcher::Impl";
00244 }
00245
00247
00248
00249
00251
00253
00254
00255
00256
00257 Fetcher::Fetcher()
00258 : _pimpl( Impl::nullimpl() )
00259 {}
00260
00262
00263
00264
00265
00266 Fetcher::~Fetcher()
00267 {}
00268
00269 void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
00270 {
00271 _pimpl->enqueueDigested(resource, checker);
00272 }
00273
00274 void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
00275 {
00276 _pimpl->enqueue(resource, checker);
00277 }
00278
00279 void Fetcher::addCachePath( const Pathname &cache_dir )
00280 {
00281 _pimpl->addCachePath(cache_dir);
00282 }
00283
00284 void Fetcher::reset()
00285 {
00286 _pimpl->reset();
00287 }
00288
00289 void Fetcher::start( const Pathname &dest_dir,
00290 MediaSetAccess &media,
00291 const ProgressData::ReceiverFnc & progress_receiver )
00292 {
00293 _pimpl->start(dest_dir, media, progress_receiver);
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
00303 {
00304 return str << *obj._pimpl;
00305 }
00306
00308 }
00310