SourceManager.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <map>
00014 
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/base/Algorithm.h"
00017 #include "zypp/base/Gettext.h"
00018 
00019 #include "zypp/ZYpp.h"
00020 #include "zypp/ZYppFactory.h"
00021 #include "zypp/SourceManager.h"
00022 #include "zypp/SourceFactory.h"
00023 #include "zypp/Source.h"
00024 #include "zypp/source/SourceImpl.h"
00025 #include "zypp/target/store/PersistentStorage.h"
00026 #include "zypp/TmpPath.h"
00027 #include "zypp/Pathname.h"
00028 #include "zypp/PathInfo.h"
00029 
00031 #undef  ZYPP_BASE_LOGGER_LOGGROUP
00032 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::SourceManager"
00033 
00034 
00035 #define ZYPP_METADATA_PREFIX ( getZYpp()->homePath().asString()+"/cache/" )
00036 
00037 using std::endl;
00038 
00040 namespace zypp
00041 { 
00042 
00043   IMPL_PTR_TYPE(SourceManager)
00044 
00045   SourceManager_Ptr SourceManager::sourceManager()
00046   {
00047     static SourceManager_Ptr _source_manager( new SourceManager );
00048     return _source_manager;
00049   }
00050 
00051   namespace
00052   {
00053     typedef std::map<SourceManager::SourceId, Source_Ref> SourceMap;
00054 
00055     static SourceMap _sources;
00056     static SourceMap _deleted_sources;
00057     static std::set<std::string> _renamed_sources;
00058 
00059     struct PrintSourceMapEntry
00060     {
00061       void operator()( const SourceMap::value_type & el ) const
00062       {
00063         _str << endl << "    - " << el.second;
00064       }
00065       PrintSourceMapEntry( std::ostream & str )
00066           : _str( str )
00067       {}
00068       std::ostream & _str;
00069     };
00070 
00071     inline std::ostream & dumpSourceTableOn( std::ostream & str, bool trailingENDL = true )
00072     {
00073       str << "SourceManager: =========================" << endl
00074       << "  known Sources " << _sources.size();
00075       std::for_each( _sources.begin(), _sources.end(), PrintSourceMapEntry(str) );
00076 
00077       str << endl
00078       << "  deleted Sources " << _deleted_sources.size();
00079       std::for_each( _deleted_sources.begin(), _deleted_sources.end(), PrintSourceMapEntry(str) );
00080       str << endl
00081       << "========================================";
00082       if ( trailingENDL )
00083         str << endl;
00084       return str;
00085     }
00086 
00087     inline bool sourceTableRemove( SourceMap::iterator it )
00088     {
00089       if ( it == _sources.end() )
00090         return false;
00091 
00092       MIL << "SourceManager remove " << it->second << endl;
00093       _deleted_sources[it->second.numericId()] = it->second;
00094       _sources.erase(it);
00095 
00096       // release all media of this source, not needed anymore (#159754)
00097       it->second.release();
00098 
00099       dumpSourceTableOn( DBG );
00100       return true;
00101     }
00102 
00103     inline SourceManager::SourceId sourceTableAdd( Source_Ref source_r )
00104     {
00105       if ( source_r.numericId() )
00106       {
00107         MIL << "SourceManager add " << source_r << endl;
00108         if ( _sources[source_r.numericId()] != source_r )
00109         {
00110           // Not yet added: check and throw if alias is already in use.
00111           for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); ++it )
00112           {
00113             if ( it->second.alias() == source_r.alias() )
00114             {
00115               ERR << "Alias '" << source_r.alias() << "' already in use: " << it->second << endl;
00116               ZYPP_THROW( Exception( str::form( _("Source alias '%s' is already in use."),
00117                                                 source_r.alias().c_str() ) ) );
00118             }
00119           }
00120           _sources[source_r.numericId()] = source_r;
00121         }
00122         dumpSourceTableOn( DBG );
00123       }
00124       else
00125       {
00126         // Not worth an Exception. Request to add noSource, adds no Source,
00127         // and returns the noSource Id.
00128         WAR << "SourceManager does not add Source::noSource" << endl;
00129       }
00130       return source_r.numericId();
00131     }
00132 
00133   }
00134 
00136   //
00137   // METHOD NAME : SourceManager::SourceManager
00138   // METHOD TYPE : Ctor
00139   //
00140   SourceManager::SourceManager()
00141   {
00142     MIL << "Created SourceManager Singleton." << endl;
00143   }
00144 
00146   //
00147   // METHOD NAME : SourceManager::~SourceManager
00148   // METHOD TYPE : Dtor
00149   //
00150   SourceManager::~SourceManager()
00151   {
00152     MIL << "Deleted SourceManager Singleton." << endl;
00153   }
00154 
00155   SourceManager::const_iterator SourceManager::begin() const
00156   {
00157     return _sources.begin();
00158   }
00159 
00160   SourceManager::const_iterator SourceManager::end() const
00161   {
00162     return _sources.end();
00163   }
00164 
00165   SourceManager::SourceId_const_iterator SourceManager::SourceId_begin() const
00166   {
00167     return make_map_key_begin( _sources );
00168   }
00169 
00170   SourceManager::SourceId_const_iterator SourceManager::SourceId_end() const
00171   {
00172     return make_map_key_end( _sources );
00173   }
00174 
00175   SourceManager::Source_const_iterator SourceManager::Source_begin() const
00176   {
00177     return make_map_value_begin( _sources );
00178   }
00179 
00180   SourceManager::Source_const_iterator SourceManager::Source_end() const
00181   {
00182     return make_map_value_end( _sources );
00183   }
00184 
00185   void SourceManager::reset()
00186   {
00187     MIL << "SourceManager reset (forget all sources)" << endl;
00188     _sources.clear();
00189     _deleted_sources.clear();
00190   }
00191 
00192   SourceManager::SourceId SourceManager::addSource( Source_Ref source_r )
00193   {
00194     return sourceTableAdd( source_r );
00195   }
00196 
00197   void SourceManager::renameSource( SourceId id, const std::string & new_alias_r )
00198   {
00199     Source_Ref src = findSource(id);
00200 
00201     if ( src )
00202     {
00203       // delete the old entry in the storage
00204       // the new entry will appear when doing
00205       // store
00206       _renamed_sources.insert(src.alias());
00207       // set the new alias
00208       src.setAlias( new_alias_r );
00209     }
00210 
00211   }
00212 
00213   void SourceManager::removeSource(SourceManager::SourceId id)
00214   {
00215     if ( ! sourceTableRemove( _sources.find(id) ) )
00216     {
00217       WAR << "SourceManager remove: no source with SourceId " << id << endl;
00218     }
00219   }
00220 
00221   void SourceManager::removeSource( const std::string & alias_r )
00222   {
00223     SourceMap::iterator it = _sources.begin();
00224     for ( ; it != _sources.end() && it->second.alias() != alias_r; ++it )
00225       ; // empty body
00226 
00227     if ( ! sourceTableRemove( it ) )
00228     {
00229       WAR << "SourceManager remove: no source with alias " << alias_r << endl;
00230     }
00231   }
00232 
00233   void SourceManager::removeSourceByUrl( const Url & url_r )
00234   {
00235     SourceMap::iterator it = _sources.begin();
00236     for ( ; it != _sources.end() && it->second.url().asString() != url_r.asString(); ++it )
00237       ; // empty body
00238 
00239     if ( ! sourceTableRemove( it ) )
00240     {
00241       WAR << "SourceManager remove: no source with Url " << url_r << endl;
00242     }
00243   }
00244 
00245   void SourceManager::releaseAllSources()
00246   {
00247     MIL << "SourceManager releasing all sources ..." << endl;
00248     for (SourceMap::iterator it = _sources.begin();
00249          it != _sources.end(); it++)
00250     {
00251       it->second.release();
00252     }
00253     MIL << "SourceManager releasing all sources done." << endl;
00254   }
00255 
00256   void SourceManager::reattachSources(const Pathname &attach_point)
00257   {
00258     MIL << "SourceManager reattach all sources to '" << attach_point << " ..." << endl;
00259     for (SourceMap::iterator it = _sources.begin();
00260          it != _sources.end(); it++)
00261     {
00262       it->second.reattach(attach_point);
00263     }
00264     MIL << "SourceManager reattach all sources to '" << attach_point << " done." << endl;
00265   }
00266 
00267 
00268   void SourceManager::disableAllSources()
00269   {
00270     MIL << "SourceManager disable all sources ..." << endl;
00271     for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
00272     {
00273       it->second.disable();
00274     }
00275     MIL << "SourceManager disable all sources done." << endl;
00276   }
00277 
00278   std::list<SourceManager::SourceId> SourceManager::enabledSources() const
00279   {
00280     std::list<SourceManager::SourceId> res;
00281 
00282     for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
00283     {
00284       if ( it->second.enabled() )
00285         res.push_back(it->first);
00286     }
00287 
00288     return res;
00289   }
00290 
00291   std::list<SourceManager::SourceId> SourceManager::allSources() const
00292   {
00293     std::list<SourceManager::SourceId> res;
00294 
00295     for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
00296     {
00297       res.push_back(it->first);
00298     }
00299 
00300     return res;
00301   }
00302 
00303   void SourceManager::store(Pathname root_r, bool metadata_cache )
00304   {
00305     MIL << "SourceManager store '" << root_r << ( metadata_cache ? "' (metadata_cache)" : "'" )
00306     << " ..." << endl;
00307 
00308     storage::PersistentStorage store;
00309     store.init( root_r );
00310 
00311 
00312     // make sure to create the source metadata cache
00313     if ( metadata_cache )
00314     {
00315       // make sure our root exists
00316 
00317       filesystem::assert_dir( root_r / getZYpp()->homePath() );
00318       Pathname topdir( root_r / ZYPP_METADATA_PREFIX );
00319       filesystem::assert_dir( topdir );
00320       MIL << "Created..." << topdir << std::endl;
00321     }
00322 
00323     // delete renamed sources entries
00324     for ( std::set<std::string>::const_iterator it = _renamed_sources.begin(); it != _renamed_sources.end(); it++)
00325     {
00326       MIL << "removing source entry " << *it << " (renamed) from persistent store" << endl;
00327       store.deleteSource( *it );
00328     }
00329 
00330     _renamed_sources.clear();
00331 
00332     // delete before modifying and creating
00333     // so that we can recreate a deleted one (#174295)
00334     for ( SourceMap::iterator it = _deleted_sources.begin(); it != _deleted_sources.end(); it++)
00335     {
00336       MIL << "Deleting source " << it->second << " from persistent store" << endl;
00337       store.deleteSource( it->second.alias() );
00338       filesystem::recursive_rmdir( it->second.cacheDir() );
00339     }
00340 
00341     _deleted_sources.clear();
00342 
00343     for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
00344     {
00345       source::SourceInfo descr;
00346 
00347       descr.setUrl(it->second.url());
00348       descr.setEnabled( it->second.enabled() );
00349       descr.setAlias( it->second.alias() );
00350       descr.setAutorefresh( it->second.autorefresh() );
00351       descr.setType( it->second.type() );
00352       descr.setPath( it->second.path() );
00353 
00354       // WATCH OUT!
00355       // Source::cacheDir contains the root prefix.
00356       // Strip it from SourceInfo::CacheDir!
00357       if ( root_r.empty() || root_r == "/" )
00358       {
00359         descr.setCacheDir( it->second.cacheDir() );
00360       }
00361       else
00362       {
00363         descr.setCacheDir( str::stripPrefix( it->second.cacheDir().asString(), root_r.asString() ) );
00364       }
00365 
00366       if ( metadata_cache && descr.cacheDir().empty() )
00367       {
00368         if ( descr.cacheDir().empty() )
00369         {
00370           filesystem::TmpDir newCache( root_r /  ZYPP_METADATA_PREFIX, "Source." );
00371           descr.setCacheDir( ZYPP_METADATA_PREFIX + newCache.path().basename() );
00372         }
00373 
00374         filesystem::assert_dir ( root_r.asString() + descr.cacheDir() );
00375 
00376         MIL << "Storing metadata to (" << root_r.asString() << ")/" << descr.cacheDir() << endl;
00377 
00378         try
00379         {
00380           it->second.storeMetadata( root_r.asString() + descr.cacheDir() );
00381         }
00382         catch (const Exception &excp)
00383         {
00384           WAR << "Creating local metadata cache failed, not using cache" << endl;
00385           filesystem::clean_dir( root_r.asString() + descr.cacheDir() );
00386         }
00387       }
00388 
00389       store.storeSource( descr );
00390     }
00391 
00392     MIL << "SourceManager store done." << endl;
00393   }
00394 
00398   bool SourceManager::restore( Pathname root_r, bool use_caches, const std::string &alias_filter, const std::string &url_filter )
00399   {
00400     MIL << "SourceManager restore ('" << root_r << ( use_caches ? "' (use_caches)" : "'" ) << ", alias_filter '" << alias_filter << ", url_filter '" << url_filter << "')" << endl;
00401 
00402     if (! _sources.empty() )
00403     {
00404 
00405       // if we've already restored sources and this is an unfiltered call, reject it.
00406 
00407       if (alias_filter.empty()
00408           && url_filter.empty())
00409       {
00410         ZYPP_THROW(SourcesAlreadyRestoredException());
00411         //Exception ( N_("At least one source already registered, cannot restore sources from persistent store.") ) );
00412       }
00413 
00414       // check filters against already restore sources and check for duplicates.
00415       //
00416       for (SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); ++it)
00417       {
00418         if (!alias_filter.empty() && (alias_filter == it->second.alias()) )
00419         {
00420           MIL << "Source with alias '" << alias_filter << "' already restored.";
00421           return true;
00422         }
00423 
00424         if (!url_filter.empty() && (url_filter == it->second.url().asString()) )
00425         {
00426           MIL << "Source with url '" << url_filter << "' already restored.";
00427           return true;
00428         }
00429       }
00430     }
00431 
00432     FailedSourcesRestoreException report;
00433 
00434     storage::PersistentStorage store;
00435     store.init( root_r );
00436 
00437     std::list<source::SourceInfo> new_sources = store.storedSources();
00438 
00439     MIL << "Found sources: " << new_sources.size() << endl;
00440 
00441     for ( std::list<source::SourceInfo>::iterator it = new_sources.begin(); it != new_sources.end(); ++it)
00442     {
00443       if ( !alias_filter.empty()   // check alias filter, if set
00444            && (alias_filter != it->alias()) )
00445       {
00446         continue;
00447       }
00448 
00449       if ( !url_filter.empty()   // check url filter, if set
00450            && (url_filter != it->url().asString()) )
00451       {
00452         continue;
00453       }
00454 
00455       // Note: Url(it->url).asString() to hide password in logs
00456       MIL << "Restoring source: url:[" << it->url().asString()
00457           << "] product_dir:[" << it->path()
00458           << "] alias:[" << it->alias()
00459           << "] cache_dir:[" << it->cacheDir()
00460           << "] auto_refresh:[ " << it->autorefresh() << "]" << endl;
00461 
00462       if ( it->cacheDir().empty() )
00463       {
00464         WAR << "Empty cachedir: Going to assign some..." << endl;
00465         filesystem::TmpDir newCache( root_r /  ZYPP_METADATA_PREFIX, "Source." );
00466         it->setCacheDir( ZYPP_METADATA_PREFIX + newCache.path().basename() );
00467         filesystem::assert_dir ( root_r.asString() + it->cacheDir() );
00468         store.storeSource( *it );
00469       }
00470 
00471       SourceId id = 0;
00472 
00473       try
00474       {
00475         Source_Ref src = SourceFactory().createFrom( it->type(), it->url(), it->path(), it->alias(),
00476                                                      root_r / it->cacheDir(),
00477                                                      false, it->autorefresh() );
00478         id = addSource(src);
00479       }
00480       catch (const Exception &expt )
00481       {
00482         // Note: Url(it->url).asString() to hide password in logs
00483         ERR << "Unable to restore source from " << it->url().asString() << endl;
00484 
00485         id = 0;
00486         Url url2;
00487         try
00488         {
00489           url2 = it->url();
00490           std::string scheme( url2.getScheme());
00491 
00492           if ( (scheme == "cd" || scheme == "dvd") && !url2.getQueryParam("devices").empty())
00493           {
00494             url2.setQueryParam("devices", "");
00495             DBG << "CD/DVD devices changed - try again without a devices list" << std::endl;
00496 
00497             id = addSource( SourceFactory().createFrom( url2, it->path(), it->alias(),
00498                                                         root_r / it->cacheDir(),
00499                                                         false ) );
00500 
00501             // This worked ... update it->url ?
00502             //it->url = url2.asCompleteString();
00503           }
00504         }
00505         catch (const Exception &e2)
00506         {
00507           // Note: Url(it->url).asString() to hide password in logs
00508           ERR << "Unable to restore source from " << url2.asString()
00509           << endl;
00510           id = 0;
00511           ZYPP_CAUGHT(e2);
00512         }
00513 
00514         if ( id == 0)
00515         {
00516           report.append( it->url().asString() + it->path().asString(), it->alias(), expt );
00517           continue;
00518         }
00519       }
00520 
00521       DBG << "Added source as id " << id << endl;
00522       // should not throw, we've just created the source
00523       Source_Ref src = findSource( id );
00524 
00525       if ( it->enabled() )
00526       {
00527         DBG << "enable source" << endl;
00528         src.enable();
00529       }
00530       else
00531       {
00532         DBG << "disable source" << endl;
00533         src.disable();
00534       }
00535     }
00536 
00537     if ( !report.empty() )
00538     {
00539       ZYPP_THROW(report);
00540     }
00541 
00542     MIL << "SourceManager restore done." << endl;
00543     dumpSourceTableOn( DBG );
00544     return true;
00545   }
00546 
00547   void SourceManager::disableSourcesAt( const Pathname & root_r )
00548   {
00549     storage::PersistentStorage store;
00550     store.init( root_r );
00551 
00552     std::list<source::SourceInfo> new_sources = store.storedSources();
00553 
00554     MIL << "Disabling all sources in store at " << root_r << endl;
00555 
00556     for ( std::list<source::SourceInfo>::iterator it = new_sources.begin();
00557           it != new_sources.end(); ++it)
00558     {
00559       MIL << "Disabling source " << it->alias() << endl;
00560       it->setEnabled(false);
00561       store.storeSource( *it );
00562     }
00563   }
00564 
00565   source::SourceInfoList SourceManager::knownSourceInfos(const Pathname &root_r)
00566   {
00567     storage::PersistentStorage store;
00568     SourceInfoList result;
00569     store.init( root_r );
00570 
00571     source::SourceInfoList sources = store.storedSources();
00572     MIL << "Found sources: " << sources.size() << endl;
00573     return sources;
00574   }
00575 
00576   /******************************************************************
00577   **
00578   ** FUNCTION NAME : operator<<
00579   ** FUNCTION TYPE : std::ostream &
00580   */
00581   std::ostream & operator<<( std::ostream & str, const SourceManager & obj )
00582   {
00583     return dumpSourceTableOn( str, /*tailingENDL*/false );
00584   }
00585 
00586   Source_Ref SourceManager::findSource(SourceId id)
00587   {
00588     SourceMap::iterator it = _sources.find(id);
00589     if (it == _sources.end())
00590     {
00591       ZYPP_THROW(Exception("Unknown source ID"));
00592     }
00593     return it->second;
00594   }
00595 
00596   Source_Ref SourceManager::findSource(const std::string & alias_r)
00597   {
00598     SourceMap::iterator it;
00599     for (it = _sources.begin(); it != _sources.end(); ++it)
00600     {
00601       if (it->second.alias() == alias_r)
00602       {
00603         return it->second;
00604       }
00605     }
00606     ZYPP_THROW(Exception("Unknown source name '"+alias_r+"'"));
00607     /*NOTREACHED*/
00608     return it->second; // just to keep gcc happy
00609   }
00610 
00611   Source_Ref SourceManager::findSourceByUrl(const Url & url_r)
00612   {
00613     SourceMap::iterator it;
00614     for (it = _sources.begin(); it != _sources.end(); ++it)
00615     {
00616       if (it->second.url().asCompleteString() == url_r.asCompleteString())
00617       {
00618         return it->second;
00619       }
00620     }
00621     ZYPP_THROW(Exception("Unknown source URL '"+url_r.asString()+"'"));
00622     /*NOTREACHED*/
00623     return it->second; // just to keep gcc happy
00624   }
00625 
00627   // FailedSourcesRestoreException
00629 
00630   std::ostream & FailedSourcesRestoreException::dumpOn( std::ostream & str ) const
00631   {
00632     return str << _summary;
00633   }
00634 
00635   std::ostream & FailedSourcesRestoreException::dumpOnTranslated( std::ostream & str ) const
00636   {
00637     return str << Exception::asUserString() << endl << _translatedSummary;
00638   }
00639 
00640   bool FailedSourcesRestoreException::empty () const
00641   {
00642     return _summary.empty();
00643   }
00644 
00645   std::set<std::string> FailedSourcesRestoreException::aliases () const
00646     {
00647       return _aliases;
00648     }
00649 
00650   void FailedSourcesRestoreException::append( std::string source, std::string alias, const Exception& expt)
00651   {
00652     _summary = _summary + "\n" + source + ": " + expt.asString();
00653     _translatedSummary = _translatedSummary + "\n" + source + ": " + expt.asUserString();
00654     _aliases.insert( alias );
00655   }
00656 
00658 } // namespace zypp

Generated on Wed Feb 16 18:51:51 2011 for zypp by  doxygen 1.4.6