- fixed some typos
[platform/upstream/libzypp.git] / zypp / Fetcher.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/Fetcher.cc
10  *
11 */
12 #include <iostream>
13 #include <list>
14
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/DefaultIntegral.h"
17 #include "zypp/Fetcher.h"
18 #include "zypp/base/UserRequestException.h"
19
20 using namespace std;
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 { /////////////////////////////////////////////////////////////////
25
26   /**
27    * Class to encapsulate the \ref OnMediaLocation object
28    * and the \ref FileChecker together
29    */
30   struct FetcherJob
31   {
32     FetcherJob( const OnMediaLocation &loc )
33       : location(loc)
34     {
35
36     }
37
38     OnMediaLocation location;
39     CompositeFileChecker checkers;
40   };
41
42   ///////////////////////////////////////////////////////////////////
43   //
44   //    CLASS NAME : Fetcher::Impl
45   //
46   /** Fetcher implementation. */
47   struct Fetcher::Impl
48   {
49
50   public:
51
52     void enqueue( const OnMediaLocation &resource, const FileChecker &checker  );
53     void enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker );
54     void addCachePath( const Pathname &cache_dir );
55     void reset();
56     void start( const Pathname &dest_dir,
57                 MediaSetAccess &media,
58                 const ProgressData::ReceiverFnc & progress_receiver );
59
60     /** Offer default Impl. */
61     static shared_ptr<Impl> nullimpl()
62     {
63       static shared_ptr<Impl> _nullimpl( new Impl );
64       return _nullimpl;
65     }
66
67   private:
68     friend Impl * rwcowClone<Impl>( const Impl * rhs );
69     /** clone for RWCOW_pointer */
70     Impl * clone() const
71     { return new Impl( *this ); }
72
73     std::list<FetcherJob> _resources;
74     std::list<Pathname> _caches;
75   };
76   ///////////////////////////////////////////////////////////////////
77
78
79   void Fetcher::Impl::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
80   {
81     CompositeFileChecker composite;
82     composite.add(ChecksumFileChecker(resource.checksum()));
83     composite.add(checker);
84     enqueue(resource, composite);
85   }
86   
87   void Fetcher::Impl::enqueue( const OnMediaLocation &resource, const FileChecker &checker )
88   {
89     FetcherJob job(resource);
90     job.checkers.add(checker);
91     _resources.push_back(resource);
92   }
93
94   void Fetcher::Impl::reset()
95   {
96     _resources.clear();
97     _caches.clear();
98   }
99   
100   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
101   {
102     _caches.push_back(cache_dir);
103   }
104   
105   void Fetcher::Impl::start( const Pathname &dest_dir,
106                              MediaSetAccess &media,
107                              const ProgressData::ReceiverFnc & progress_receiver )
108   {
109     ProgressData progress(_resources.size());
110     progress.sendTo(progress_receiver);
111
112     for ( list<FetcherJob>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
113     {
114       bool got_from_cache = false;
115       for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
116       {
117         // Pathinfos could be cached to avoid too many stats?
118         PathInfo info(*it_cache);
119         if ( info.isDir() )
120         {
121           // does the current file exists in the current cache?
122           Pathname cached_file = *it_cache + (*it_res).location.filename();
123           if ( PathInfo( cached_file ).isExist() )
124           {
125             // check the checksum
126             if ( is_checksum( cached_file, (*it_res).location.checksum() ) )
127             {
128               // cached
129               MIL << "file " << (*it_res).location.filename() << " found in previous cache. Using cached copy." << endl;
130               // checksum is already checked.
131               // we could later implement double failover and try to download if file copy fails.
132   
133               // replicate the complete path in the target directory
134               Pathname dest_full_path = dest_dir + (*it_res).location.filename();
135               if ( assert_dir( dest_full_path.dirname() ) != 0 )
136                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
137   
138               if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
139               { //copy_file2dir
140                 //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
141                 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
142                 // try next cache
143                 continue;
144               }
145   
146               got_from_cache = true;
147               break;
148             }
149           }
150           else
151           {
152             // File exists in cache but with a different checksum
153             // so just try next cache
154             continue;
155           }
156         }
157         else
158         {
159           // skip bad cache directory and try with next one
160           ERR << "Skipping cache : " << *it_cache << endl;
161           continue;
162         }
163       }
164   
165       if ( ! got_from_cache )
166       {
167         // try to get the file from the net
168         try
169         {
170           Pathname tmp_file = media.provideFile((*it_res).location);
171           Pathname dest_full_path = dest_dir + (*it_res).location.filename();
172           if ( assert_dir( dest_full_path.dirname() ) != 0 )
173                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
174           if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
175           {
176             ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
177           }
178           
179           
180         }
181         catch (const Exception & excpt_r)
182         {
183           ZYPP_CAUGHT(excpt_r);
184           ZYPP_THROW(Exception("Can't provide " + (*it_res).location.filename().asString() + " : " + excpt_r.msg() ));
185         }
186       }
187       else
188       {
189         // We got the file from cache
190         // continue with next file
191         continue;
192       }
193       
194       // no matter where did we got the file, try to validate it:
195        Pathname localfile = dest_dir + (*it_res).location.filename();
196        // call the checker function
197        try {
198          (*it_res).checkers(localfile);
199        }
200        catch ( const FileCheckException &e )
201        {
202           ZYPP_RETHROW(e);
203        }
204        catch ( const Exception &e )
205        {
206           ZYPP_RETHROW(e);
207        }
208        catch (...)
209        {
210           ZYPP_THROW(Exception("Unknown error while validating " + (*it_res).location.filename().asString()));
211        }
212
213        if ( ! progress.incr() )
214         ZYPP_THROW(AbortRequestException());
215     } // for each job
216   }
217
218   /** \relates Fetcher::Impl Stream output */
219   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
220   {
221     return str << "Fetcher::Impl";
222   }
223
224   ///////////////////////////////////////////////////////////////////
225   //
226   //    CLASS NAME : Fetcher
227   //
228   ///////////////////////////////////////////////////////////////////
229
230   ///////////////////////////////////////////////////////////////////
231   //
232   //    METHOD NAME : Fetcher::Fetcher
233   //    METHOD TYPE : Ctor
234   //
235   Fetcher::Fetcher()
236   : _pimpl( Impl::nullimpl() )
237   {}
238
239   ///////////////////////////////////////////////////////////////////
240   //
241   //    METHOD NAME : Fetcher::~Fetcher
242   //    METHOD TYPE : Dtor
243   //
244   Fetcher::~Fetcher()
245   {}
246
247   void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
248   {
249     _pimpl->enqueue(resource, checker);
250   }
251   
252   void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker  )
253   {
254     _pimpl->enqueue(resource, checker);
255   }
256   
257   void Fetcher::addCachePath( const Pathname &cache_dir )
258   {
259     _pimpl->addCachePath(cache_dir);
260   }
261   
262   void Fetcher::reset()
263   {
264     _pimpl->reset();
265   }
266
267   void Fetcher::start( const Pathname &dest_dir,
268                        MediaSetAccess &media,
269                        const ProgressData::ReceiverFnc & progress_receiver )
270   {
271     _pimpl->start(dest_dir, media, progress_receiver);
272   }
273
274
275   /******************************************************************
276   **
277   **    FUNCTION NAME : operator<<
278   **    FUNCTION TYPE : std::ostream &
279   */
280   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
281   {
282     return str << *obj._pimpl;
283   }
284
285   /////////////////////////////////////////////////////////////////
286 } // namespace zypp
287 ///////////////////////////////////////////////////////////////////
288