1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Fetcher.cc
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/PtrTypes.h"
17 #include "zypp/base/DefaultIntegral.h"
18 #include "zypp/Fetcher.h"
19 #include "zypp/base/UserRequestException.h"
23 ///////////////////////////////////////////////////////////////////
25 { /////////////////////////////////////////////////////////////////
28 * Class to encapsulate the \ref OnMediaLocation object
29 * and the \ref FileChecker together
33 FetcherJob( const OnMediaLocation &loc )
36 //MIL << location << endl;
41 //MIL << location << " | * " << checkers.size() << endl;
44 OnMediaLocation location;
45 //CompositeFileChecker checkers;
46 list<FileChecker> checkers;
49 typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
51 ///////////////////////////////////////////////////////////////////
53 // CLASS NAME : Fetcher::Impl
55 /** Fetcher implementation. */
61 void enqueue( const OnMediaLocation &resource, const FileChecker &checker );
62 void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker );
63 void addCachePath( const Pathname &cache_dir );
65 void start( const Pathname &dest_dir,
66 MediaSetAccess &media,
67 const ProgressData::ReceiverFnc & progress_receiver );
69 /** Offer default Impl. */
70 static shared_ptr<Impl> nullimpl()
72 static shared_ptr<Impl> _nullimpl( new Impl );
77 friend Impl * rwcowClone<Impl>( const Impl * rhs );
78 /** clone for RWCOW_pointer */
80 { return new Impl( *this ); }
82 std::list<FetcherJob_Ptr> _resources;
83 std::list<Pathname> _caches;
85 ///////////////////////////////////////////////////////////////////
88 void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
91 job.reset(new FetcherJob(resource));
92 ChecksumFileChecker digest_check(resource.checksum());
93 job->checkers.push_back(digest_check);
95 job->checkers.push_back(checker);
96 _resources.push_back(job);
99 void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
102 job.reset(new FetcherJob(resource));
104 job->checkers.push_back(checker);
105 _resources.push_back(job);
108 void Fetcher::Impl::reset()
114 void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
116 PathInfo info(cache_dir);
119 _caches.push_back(cache_dir);
123 // don't add bad cache directory, just log the error
124 ERR << "Not adding cache: '" << cache_dir << "'. Not a direcotry." << endl;
128 void Fetcher::Impl::start( const Pathname &dest_dir,
129 MediaSetAccess &media,
130 const ProgressData::ReceiverFnc & progress_receiver )
132 ProgressData progress(_resources.size());
133 progress.sendTo(progress_receiver);
135 for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
137 bool got_from_cache = false;
138 for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
140 // does the current file exists in the current cache?
141 Pathname cached_file = *it_cache + (*it_res)->location.filename();
143 MIL << "Trying cached file: " << cached_file << endl;
145 if ( PathInfo( cached_file ).isExist() )
147 MIL << "File exist, testing checksum " << (*it_res)->location.checksum() << endl;
149 // check the checksum
150 if ( is_checksum( cached_file, (*it_res)->location.checksum() ) && (! (*it_res)->location.checksum().empty() ) )
153 MIL << "file " << (*it_res)->location.filename() << " found in previous cache. Using cached copy." << endl;
154 // checksum is already checked.
155 // we could later implement double failover and try to download if file copy fails.
157 // replicate the complete path in the target directory
158 Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
160 if( dest_full_path != cached_file )
162 if ( assert_dir( dest_full_path.dirname() ) != 0 )
163 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
165 if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
167 //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
168 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
174 got_from_cache = true;
180 if ( ! got_from_cache )
182 MIL << "Not found in cache, downloading" << endl;
184 // try to get the file from the net
187 Pathname tmp_file = media.provideFile((*it_res)->location);
188 Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
189 if ( assert_dir( dest_full_path.dirname() ) != 0 )
190 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
191 if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
193 ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
198 catch (const Exception & excpt_r)
200 ZYPP_CAUGHT(excpt_r);
201 Exception nexcpt("Can't provide " + (*it_res)->location.filename().asString() + " : " + excpt_r.msg());
202 nexcpt.remember(excpt_r);
208 // We got the file from cache
209 // continue with next file
213 // no matter where did we got the file, try to validate it:
214 Pathname localfile = dest_dir + (*it_res)->location.filename();
215 // call the checker function
217 MIL << "Checking job [" << localfile << "] (" << (*it_res)->checkers.size() << " checkers )" << endl;
218 for ( list<FileChecker>::const_iterator it = (*it_res)->checkers.begin();
219 it != (*it_res)->checkers.end();
228 ERR << "Invalid checker for '" << localfile << "'" << endl;
233 catch ( const FileCheckException &e )
237 catch ( const Exception &e )
243 ZYPP_THROW(Exception("Unknown error while validating " + (*it_res)->location.filename().asString()));
246 if ( ! progress.incr() )
247 ZYPP_THROW(AbortRequestException());
251 /** \relates Fetcher::Impl Stream output */
252 inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
254 return str << "Fetcher::Impl";
257 ///////////////////////////////////////////////////////////////////
259 // CLASS NAME : Fetcher
261 ///////////////////////////////////////////////////////////////////
263 ///////////////////////////////////////////////////////////////////
265 // METHOD NAME : Fetcher::Fetcher
266 // METHOD TYPE : Ctor
269 : _pimpl( Impl::nullimpl() )
272 ///////////////////////////////////////////////////////////////////
274 // METHOD NAME : Fetcher::~Fetcher
275 // METHOD TYPE : Dtor
280 void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
282 _pimpl->enqueueDigested(resource, checker);
285 void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
287 _pimpl->enqueue(resource, checker);
290 void Fetcher::addCachePath( const Pathname &cache_dir )
292 _pimpl->addCachePath(cache_dir);
295 void Fetcher::reset()
300 void Fetcher::start( const Pathname &dest_dir,
301 MediaSetAccess &media,
302 const ProgressData::ReceiverFnc & progress_receiver )
304 _pimpl->start(dest_dir, media, progress_receiver);
308 /******************************************************************
310 ** FUNCTION NAME : operator<<
311 ** FUNCTION TYPE : std::ostream &
313 std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
315 return str << *obj._pimpl;
318 /////////////////////////////////////////////////////////////////
320 ///////////////////////////////////////////////////////////////////