Fetcher.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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       //MIL << location << endl;
00037     }
00038 
00039     ~FetcherJob()
00040     {
00041       //MIL << location << " | * " << checkers.size() << endl;
00042     }
00043 
00044     OnMediaLocation location;
00045     //CompositeFileChecker checkers;
00046     list<FileChecker> checkers;
00047   };
00048 
00049   typedef shared_ptr<FetcherJob> FetcherJob_Ptr;
00050 
00052   //
00053   //    CLASS NAME : Fetcher::Impl
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   }
00112 
00113   void Fetcher::Impl::addCachePath( const Pathname &cache_dir )
00114   {
00115     PathInfo info(cache_dir);
00116     if ( info.isDir() )
00117     {
00118       _caches.push_back(cache_dir);
00119     }
00120     else
00121     {
00122       // don't add bad cache directory, just log the error
00123       ERR << "Not adding cache: '" << cache_dir << "'. Not a direcotry." << endl;
00124     }
00125   }
00126 
00127   void Fetcher::Impl::start( const Pathname &dest_dir,
00128                              MediaSetAccess &media,
00129                              const ProgressData::ReceiverFnc & progress_receiver )
00130   {
00131     ProgressData progress(_resources.size());
00132     progress.sendTo(progress_receiver);
00133 
00134     for ( list<FetcherJob_Ptr>::const_iterator it_res = _resources.begin(); it_res != _resources.end(); ++it_res )
00135     {
00136       bool got_from_cache = false;
00137       for ( list<Pathname>::const_iterator it_cache = _caches.begin(); it_cache != _caches.end(); ++it_cache )
00138       {
00139         // does the current file exists in the current cache?
00140         Pathname cached_file = *it_cache + (*it_res)->location.filename();
00141         if ( PathInfo( cached_file ).isExist() )
00142         {
00143           // check the checksum
00144           if ( is_checksum( cached_file, (*it_res)->location.checksum() ) && (! (*it_res)->location.checksum().empty() ) )
00145           {
00146             // cached
00147             MIL << "file " << (*it_res)->location.filename() << " found in previous cache. Using cached copy." << endl;
00148             // checksum is already checked.
00149             // we could later implement double failover and try to download if file copy fails.
00150 
00151             // replicate the complete path in the target directory
00152             Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
00153             if ( assert_dir( dest_full_path.dirname() ) != 0 )
00154               ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00155 
00156             if ( filesystem::copy(cached_file, dest_full_path ) != 0 )
00157             { //copy_file2dir
00158               //ZYPP_THROW(SourceIOException("Can't copy " + cached_file.asString() + " to " + destination.asString()));
00159               ERR << "Can't copy " << cached_file + " to " + dest_dir << endl;
00160               // try next cache
00161               continue;
00162             }
00163 
00164             got_from_cache = true;
00165             break;
00166           }
00167         }
00168       }
00169 
00170       if ( ! got_from_cache )
00171       {
00172         // try to get the file from the net
00173         try
00174         {
00175           Pathname tmp_file = media.provideFile((*it_res)->location);
00176           Pathname dest_full_path = dest_dir + (*it_res)->location.filename();
00177           if ( assert_dir( dest_full_path.dirname() ) != 0 )
00178                 ZYPP_THROW( Exception("Can't create " + dest_full_path.dirname().asString()));
00179           if ( filesystem::copy(tmp_file, dest_full_path ) != 0 )
00180           {
00181             ZYPP_THROW( Exception("Can't copy " + tmp_file.asString() + " to " + dest_dir.asString()));
00182           }
00183 
00184 
00185         }
00186         catch (const Exception & excpt_r)
00187         {
00188           ZYPP_CAUGHT(excpt_r);
00189           Exception nexcpt("Can't provide " + (*it_res)->location.filename().asString() + " : " + excpt_r.msg());
00190           nexcpt.remember(excpt_r);
00191           ZYPP_THROW(nexcpt);
00192         }
00193       }
00194       else
00195       {
00196         // We got the file from cache
00197         // continue with next file
00198         continue;
00199       }
00200 
00201       // no matter where did we got the file, try to validate it:
00202       Pathname localfile = dest_dir + (*it_res)->location.filename();
00203       // call the checker function
00204       try {
00205         MIL << "Checking job [" << localfile << "] (" << (*it_res)->checkers.size() << " checkers )" << endl;
00206         for ( list<FileChecker>::const_iterator it = (*it_res)->checkers.begin();
00207               it != (*it_res)->checkers.end();
00208               ++it )
00209         {
00210           if (*it)
00211           {
00212             (*it)(localfile);
00213           }
00214           else
00215           {
00216             ERR << "Invalid checker for '" << localfile << "'" << endl;
00217           }
00218         }
00219         
00220       }
00221       catch ( const FileCheckException &e )
00222       {
00223         ZYPP_RETHROW(e);
00224       }
00225       catch ( const Exception &e )
00226       {
00227         ZYPP_RETHROW(e);
00228       }
00229       catch (...)
00230       {
00231         ZYPP_THROW(Exception("Unknown error while validating " + (*it_res)->location.filename().asString()));
00232       }
00233 
00234       if ( ! progress.incr() )
00235         ZYPP_THROW(AbortRequestException());
00236     } // for each job
00237   }
00238 
00240   inline std::ostream & operator<<( std::ostream & str, const Fetcher::Impl & obj )
00241   {
00242     return str << "Fetcher::Impl";
00243   }
00244 
00246   //
00247   //    CLASS NAME : Fetcher
00248   //
00250 
00252   //
00253   //    METHOD NAME : Fetcher::Fetcher
00254   //    METHOD TYPE : Ctor
00255   //
00256   Fetcher::Fetcher()
00257   : _pimpl( Impl::nullimpl() )
00258   {}
00259 
00261   //
00262   //    METHOD NAME : Fetcher::~Fetcher
00263   //    METHOD TYPE : Dtor
00264   //
00265   Fetcher::~Fetcher()
00266   {}
00267 
00268   void Fetcher::enqueueDigested( const OnMediaLocation &resource, const FileChecker &checker )
00269   {
00270     _pimpl->enqueueDigested(resource, checker);
00271   }
00272 
00273   void Fetcher::enqueue( const OnMediaLocation &resource, const FileChecker &checker  )
00274   {
00275     _pimpl->enqueue(resource, checker);
00276   }
00277 
00278   void Fetcher::addCachePath( const Pathname &cache_dir )
00279   {
00280     _pimpl->addCachePath(cache_dir);
00281   }
00282 
00283   void Fetcher::reset()
00284   {
00285     _pimpl->reset();
00286   }
00287 
00288   void Fetcher::start( const Pathname &dest_dir,
00289                        MediaSetAccess &media,
00290                        const ProgressData::ReceiverFnc & progress_receiver )
00291   {
00292     _pimpl->start(dest_dir, media, progress_receiver);
00293   }
00294 
00295 
00296   /******************************************************************
00297   **
00298   **    FUNCTION NAME : operator<<
00299   **    FUNCTION TYPE : std::ostream &
00300   */
00301   std::ostream & operator<<( std::ostream & str, const Fetcher & obj )
00302   {
00303     return str << *obj._pimpl;
00304   }
00305 
00307 } // namespace zypp
00309 

Generated on Tue Oct 21 02:32:57 2008 for libzypp by  doxygen 1.5.3