hide fetcher implementation in order to operate over jobs
[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
19
20 using namespace std;
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 { /////////////////////////////////////////////////////////////////
25
26   struct FetcherJob
27   {
28     FetcherJob( const OnMediaLocation &loc )
29       : location(loc)
30     {
31
32     }
33
34     OnMediaLocation location;
35   };
36
37   ///////////////////////////////////////////////////////////////////
38   //
39   //    CLASS NAME : Fetcher::Impl
40   //
41   /** Fetcher implementation. */
42   struct Fetcher::Impl
43   {
44
45   public:
46
47     void enqueue( const OnMediaLocation &resource );    
48     void addCachePath( const Pathname &cache_dir );
49     void reset();
50     void start( const Pathname &dest_dir, MediaSetAccess &media );
51
52     /** Offer default Impl. */
53     static shared_ptr<Impl> nullimpl()
54     {
55       static shared_ptr<Impl> _nullimpl( new Impl );
56       return _nullimpl;
57     }
58
59   private:
60     friend Impl * rwcowClone<Impl>( const Impl * rhs );
61     /** clone for RWCOW_pointer */
62     Impl * clone() const
63     { return new Impl( *this ); }
64
65     std::list<FetcherJob> _resources;
66     std::list<Pathname> _caches;
67   };
68   ///////////////////////////////////////////////////////////////////
69
70
71   void Fetcher::Impl::enqueue( const OnMediaLocation &resource )
72   {
73     _resources.push_back(FetcherJob(resource));
74   }
75   
76   void Fetcher::Impl::reset()
77   {
78     _resources.clear();
79     _caches.clear();
80   }
81   
82   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
83   {
84     _caches.push_back(cache_dir);
85   }
86   
87   void Fetcher::Impl::start( const Pathname &dest_dir, MediaSetAccess &media )
88   {
89     for ( list<FetcherJob>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
90     {
91       bool got_from_cache = false;
92       for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
93       {
94         // Pathinfos could be cached to avoid too many stats?
95         PathInfo info(*it_cache);
96         if ( info.isDir() )
97         {
98           // does the current file exists in the current cache?
99           Pathname cached_file = *it_cache + (*it_res).location.filename();
100           if ( PathInfo( cached_file ).isExist() )
101           {
102             // check the checksum
103             if ( is_checksum( cached_file, (*it_res).location.checksum() ) )
104             {
105               // cached
106               MIL << "file " << (*it_res).location.filename() << " found in previous cache. Using cached copy." << endl;
107               // checksum is already checked.
108               // we could later implement double failover and try to download if file copy fails.
109   
110               // replicate the complete path in the target directory
111               Pathname dest_full_path = dest_dir + (*it_res).location.filename();
112               if ( assert_dir( dest_full_path.dirname() ) != 0 )
113                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
114   
115               if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
116               { //copy_file2dir
117                 //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
118                 ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
119                 // try next cache
120                 continue;
121               }
122   
123               got_from_cache = true;
124               break;
125             }
126           }
127           else
128           {
129             // File exists in cache but with a different checksum
130             // so just try next cache
131             continue;
132           }
133         }
134         else
135         {
136           // skip bad cache directory and try with next one
137           ERR << "Skipping cache : " << *it_cache << endl;
138           continue;
139         }
140       }
141   
142       if ( ! got_from_cache )
143       {
144         // try to get the file from the net
145         try
146         {
147           Pathname tmp_file = media.provideFile((*it_res).location);
148           Pathname dest_full_path = dest_dir + (*it_res).location.filename();
149           if ( assert_dir( dest_full_path.dirname() ) != 0 )
150                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
151           if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
152           {
153             ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
154           }
155         }
156         catch (const Exception & excpt_r)
157         {
158           ZYPP_CAUGHT(excpt_r);
159           ZYPP_THROW(Exception("Can't provide " + (*it_res).location.filename().asString() + " : " + excpt_r.msg() ));
160         }
161       }
162       else
163       {
164         // We got the file from cache
165         // continue with next file
166         continue;
167       }
168     }
169   }
170
171   /** \relates Fetcher::Impl Stream output */
172   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
173   {
174     return str << "Fetcher::Impl";
175   }
176
177   ///////////////////////////////////////////////////////////////////
178   //
179   //    CLASS NAME : Fetcher
180   //
181   ///////////////////////////////////////////////////////////////////
182
183   ///////////////////////////////////////////////////////////////////
184   //
185   //    METHOD NAME : Fetcher::Fetcher
186   //    METHOD TYPE : Ctor
187   //
188   Fetcher::Fetcher()
189   : _pimpl( Impl::nullimpl() )
190   {}
191
192   ///////////////////////////////////////////////////////////////////
193   //
194   //    METHOD NAME : Fetcher::~Fetcher
195   //    METHOD TYPE : Dtor
196   //
197   Fetcher::~Fetcher()
198   {}
199
200   void Fetcher::enqueue( const OnMediaLocation &resource )
201   {
202     _pimpl->enqueue(resource);
203   }
204   
205   void Fetcher::addCachePath( const Pathname &cache_dir )
206   {
207     _pimpl->addCachePath(cache_dir);
208   }
209   
210   void Fetcher::reset()
211   {
212     _pimpl->reset();
213   }
214
215   void Fetcher::start( const Pathname &dest_dir, MediaSetAccess &media )
216   {
217     _pimpl->start(dest_dir, media);
218   }
219
220
221   /******************************************************************
222   **
223   **    FUNCTION NAME : operator<<
224   **    FUNCTION TYPE : std::ostream &
225   */
226   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
227   {
228     return str << *obj._pimpl;
229   }
230
231   /////////////////////////////////////////////////////////////////
232 } // namespace zypp
233 ///////////////////////////////////////////////////////////////////
234
235 //       callback::SendReport<DigestReport> report;
236 //       if ( checksum.empty() )
237 //       {
238 //         MIL << "File " <<  file_url << " has no checksum available." << std::endl;
239 //         if ( report->askUserToAcceptNoDigest(file_to_download) )
240 //         {
241 //           MIL << "User accepted " <<  file_url << " with no checksum." << std::endl;
242 //           return;
243 //         }
244 //         else
245 //         {
246 //           ZYPP_THROW(SourceMetadataException( file_url.asString() + " " + N_(" miss checksum.") ));
247 //         }
248 //       }
249 //       else
250 //       {
251 //         if (! is_checksum( destination, checksum))
252 //           ZYPP_THROW(SourceMetadataException( file_url.asString() + " " + N_(" fails checksum verification.") ));
253 //       }
254