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

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3