1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Fetcher.cc
15 #include "zypp/base/Easy.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/PtrTypes.h"
18 #include "zypp/base/DefaultIntegral.h"
19 #include "zypp/Fetcher.h"
20 #include "zypp/base/UserRequestException.h"
24 ///////////////////////////////////////////////////////////////////
26 { /////////////////////////////////////////////////////////////////
29 * Class to encapsulate the \ref OnMediaLocation object
30 * and the \ref FileChecker together
34 FetcherJob( const OnMediaLocation &loc )
39 //MIL << location << endl;
44 //MIL << location << " | * " << checkers.size() << endl;
47 OnMediaLocation location;
48 //CompositeFileChecker checkers;
49 list<FileChecker> checkers;
54 typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
56 ///////////////////////////////////////////////////////////////////
58 // CLASS NAME : Fetcher::Impl
60 /** Fetcher implementation. */
70 void enqueue( const OnMediaLocation &resource, const FileChecker &checker );
71 void enqueueDir( const OnMediaLocation &resource, bool recursive, const FileChecker &checker );
72 void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker );
73 void addCachePath( const Pathname &cache_dir );
75 void start( const Pathname &dest_dir,
76 MediaSetAccess &media,
77 const ProgressData::ReceiverFnc & progress_receiver );
79 /** Offer default Impl. */
80 static shared_ptr<Impl> nullimpl()
82 static shared_ptr<Impl> _nullimpl( new Impl );
87 * tries to provide the file represented by job into dest_dir by
88 * looking at the cache. If success, returns true, and the desired
89 * file should be available on dest_dir
91 bool provideFromCache( FetcherJob_Ptr job, const Pathname &dest_dir );
93 * Validates the job against is checkers, by using the file instance
97 void validate( FetcherJob_Ptr job, const Pathname &dest_dir );
99 friend Impl * rwcowClone<Impl>( const Impl * rhs );
100 /** clone for RWCOW_pointer */
102 { return new Impl( *this ); }
104 std::list<FetcherJob_Ptr> _resources;
105 std::list<Pathname> _caches;
107 ///////////////////////////////////////////////////////////////////
109 void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
112 job.reset(new FetcherJob(resource));
113 ChecksumFileChecker digest_check(resource.checksum());
114 job->checkers.push_back(digest_check);
116 job->checkers.push_back(checker);
117 _resources.push_back(job);
120 void Fetcher::Impl::enqueueDir( const OnMediaLocation &resource,
122 const FileChecker &checker )
125 job.reset(new FetcherJob(resource));
127 job->checkers.push_back(checker);
128 job->directory = true;
129 job->recursive = recursive;
130 _resources.push_back(job);
133 void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
136 job.reset(new FetcherJob(resource));
138 job->checkers.push_back(checker);
139 _resources.push_back(job);
142 void Fetcher::Impl::reset()
147 void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
149 PathInfo info(cache_dir);
150 if ( info.isExist() )
154 DBG << "Adding fetcher cache: '" << cache_dir << "'." << endl;
155 _caches.push_back(cache_dir);
159 // don't add bad cache directory, just log the error
160 ERR << "Not adding cache: '" << cache_dir << "'. Not a directory." << endl;
165 ERR << "Not adding cache '" << cache_dir << "'. Path does not exists." << endl;
170 bool Fetcher::Impl::provideFromCache( FetcherJob_Ptr job, const Pathname &dest_dir )
172 MIL << "start fetcher with " << _caches.size() << " cache directories." << endl;
173 for_ ( it_cache, _caches.begin(), _caches.end() )
175 // does the current file exists in the current cache?
176 Pathname cached_file = *it_cache + job->location.filename();
177 if ( PathInfo( cached_file ).isExist() )
179 DBG << "File '" << cached_file << "' exist, testing checksum " << job->location.checksum() << endl;
180 // check the checksum
181 if ( is_checksum( cached_file, job->location.checksum() ) && (! job->location.checksum().empty() ) )
184 MIL << "file " << job->location.filename() << " found in previous cache. Using cached copy." << endl;
185 // checksum is already checked.
186 // we could later implement double failover and try to download if file copy fails.
187 // replicate the complete path in the target directory
188 Pathname dest_full_path = dest_dir + job->location.filename();
189 if( dest_full_path != cached_file )
191 if ( assert_dir( dest_full_path.dirname() ) != 0 )
192 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
194 if ( filesystem::hardlink(cached_file, dest_full_path ) != 0 )
196 WAR << "Can't hardlink '" << cached_file << "' to '" << dest_dir << "'. Trying copying." << endl;
197 if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
199 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
209 } // iterate over caches
213 void Fetcher::Impl::validate( FetcherJob_Ptr job, const Pathname &dest_dir )
215 // no matter where did we got the file, try to validate it:
216 Pathname localfile = dest_dir + job->location.filename();
217 // call the checker function
219 MIL << "Checking job [" << localfile << "] (" << job->checkers.size() << " checkers )" << endl;
220 for ( list<FileChecker>::const_iterator it = job->checkers.begin();
221 it != job->checkers.end();
230 ERR << "Invalid checker for '" << localfile << "'" << endl;
235 catch ( const FileCheckException &e )
239 catch ( const Exception &e )
245 ZYPP_THROW(Exception("Unknown error while validating " + job->location.filename().asString()));
249 void Fetcher::Impl::start( const Pathname &dest_dir,
250 MediaSetAccess &media,
251 const ProgressData::ReceiverFnc & progress_receiver )
253 ProgressData progress(_resources.size());
254 progress.sendTo(progress_receiver);
256 for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
258 bool got_from_cache = false;
260 // start look in cache
261 got_from_cache = provideFromCache((*it_res), dest_dir);
263 if ( ! got_from_cache )
265 MIL << "Not found in cache, downloading" << endl;
267 // try to get the file from the net
270 Pathname tmp_file = media.provideFile((*it_res)->location);
271 Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
272 if ( assert_dir( dest_full_path.dirname() ) != 0 )
273 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
274 if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
276 ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
279 media.releaseFile((*it_res)->location); //not needed anymore, only eat space
281 catch (Exception & excpt_r)
283 ZYPP_CAUGHT(excpt_r);
284 excpt_r.remember("Can't provide " + (*it_res)->location.filename().asString() + " : " + excpt_r.msg());
285 ZYPP_RETHROW(excpt_r);
290 // We got the file from cache
291 // continue with next file
295 // validate job, this throws if not valid
296 validate(*it_res, dest_dir);
298 if ( ! progress.incr() )
299 ZYPP_THROW(AbortRequestException());
303 /** \relates Fetcher::Impl Stream output */
304 inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
306 return str << "Fetcher::Impl";
309 ///////////////////////////////////////////////////////////////////
311 // CLASS NAME : Fetcher
313 ///////////////////////////////////////////////////////////////////
315 ///////////////////////////////////////////////////////////////////
317 // METHOD NAME : Fetcher::Fetcher
318 // METHOD TYPE : Ctor
321 : _pimpl( new Impl() )
324 ///////////////////////////////////////////////////////////////////
326 // METHOD NAME : Fetcher::~Fetcher
327 // METHOD TYPE : Dtor
332 void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
334 _pimpl->enqueueDigested(resource, checker);
337 void Fetcher::enqueueDir( const OnMediaLocation &resource,
339 const FileChecker &checker )
341 _pimpl->enqueueDir(resource, recursive, checker);
344 void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
346 _pimpl->enqueue(resource, checker);
349 void Fetcher::addCachePath( const Pathname &cache_dir )
351 _pimpl->addCachePath(cache_dir);
354 void Fetcher::reset()
359 void Fetcher::start( const Pathname &dest_dir,
360 MediaSetAccess &media,
361 const ProgressData::ReceiverFnc & progress_receiver )
363 _pimpl->start(dest_dir, media, progress_receiver);
367 /******************************************************************
369 ** FUNCTION NAME : operator<<
370 ** FUNCTION TYPE : std::ostream &
372 std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
374 return str << *obj._pimpl;
377 /////////////////////////////////////////////////////////////////
379 ///////////////////////////////////////////////////////////////////