00001
00002
00003
00004
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
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
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
00127
00128 WAR << "SourceManager does not add Source::noSource" << endl;
00129 }
00130 return source_r.numericId();
00131 }
00132
00133 }
00134
00136
00137
00138
00139
00140 SourceManager::SourceManager()
00141 {
00142 MIL << "Created SourceManager Singleton." << endl;
00143 }
00144
00146
00147
00148
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
00204
00205
00206 _renamed_sources.insert(src.alias());
00207
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 ;
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 ;
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
00313 if ( metadata_cache )
00314 {
00315
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
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
00333
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
00355
00356
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 descr.setCacheDir("");
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
00406
00407 if (alias_filter.empty()
00408 && url_filter.empty())
00409 {
00410 ZYPP_THROW(SourcesAlreadyRestoredException());
00411
00412 }
00413
00414
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()
00444 && (alias_filter != it->alias()) )
00445 {
00446 continue;
00447 }
00448
00449 if ( !url_filter.empty()
00450 && (url_filter != it->url().asString()) )
00451 {
00452 continue;
00453 }
00454
00455
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 SourceId id = 0;
00463
00464 try
00465 {
00466 Source_Ref src = SourceFactory().createFrom( it->type(), it->url(), it->path(), it->alias(),
00467 root_r / it->cacheDir(),
00468 false, it->autorefresh() );
00469 id = addSource(src);
00470 }
00471 catch (const Exception &expt )
00472 {
00473
00474 ERR << "Unable to restore source from " << it->url().asString() << endl;
00475
00476 id = 0;
00477 Url url2;
00478 try
00479 {
00480 url2 = it->url();
00481 std::string scheme( url2.getScheme());
00482
00483 if ( (scheme == "cd" || scheme == "dvd") && !url2.getQueryParam("devices").empty())
00484 {
00485 url2.setQueryParam("devices", "");
00486 DBG << "CD/DVD devices changed - try again without a devices list" << std::endl;
00487
00488 id = addSource( SourceFactory().createFrom( url2, it->path(), it->alias(),
00489 root_r / it->cacheDir(),
00490 false ) );
00491
00492
00493
00494 }
00495 }
00496 catch (const Exception &e2)
00497 {
00498
00499 ERR << "Unable to restore source from " << url2.asString()
00500 << endl;
00501 id = 0;
00502 ZYPP_CAUGHT(e2);
00503 }
00504
00505 if ( id == 0)
00506 {
00507 report.append( it->url().asString() + it->path().asString(), it->alias(), expt );
00508 continue;
00509 }
00510 }
00511
00512 DBG << "Added source as id " << id << endl;
00513
00514 Source_Ref src = findSource( id );
00515
00516 if ( it->enabled() )
00517 {
00518 DBG << "enable source" << endl;
00519 src.enable();
00520 }
00521 else
00522 {
00523 DBG << "disable source" << endl;
00524 src.disable();
00525 }
00526 }
00527
00528 if ( !report.empty() )
00529 {
00530 ZYPP_THROW(report);
00531 }
00532
00533 MIL << "SourceManager restore done." << endl;
00534 dumpSourceTableOn( DBG );
00535 return true;
00536 }
00537
00538 void SourceManager::disableSourcesAt( const Pathname & root_r )
00539 {
00540 storage::PersistentStorage store;
00541 store.init( root_r );
00542
00543 std::list<source::SourceInfo> new_sources = store.storedSources();
00544
00545 MIL << "Disabling all sources in store at " << root_r << endl;
00546
00547 for ( std::list<source::SourceInfo>::iterator it = new_sources.begin();
00548 it != new_sources.end(); ++it)
00549 {
00550 MIL << "Disabling source " << it->alias() << endl;
00551 it->setEnabled(false);
00552 store.storeSource( *it );
00553 }
00554 }
00555
00556 source::SourceInfoList SourceManager::knownSourceInfos(const Pathname &root_r)
00557 {
00558 storage::PersistentStorage store;
00559 SourceInfoList result;
00560 store.init( root_r );
00561
00562 source::SourceInfoList sources = store.storedSources();
00563 MIL << "Found sources: " << sources.size() << endl;
00564 return sources;
00565 }
00566
00567
00568
00569
00570
00571
00572 std::ostream & operator<<( std::ostream & str, const SourceManager & obj )
00573 {
00574 return dumpSourceTableOn( str, false );
00575 }
00576
00577 Source_Ref SourceManager::findSource(SourceId id)
00578 {
00579 SourceMap::iterator it = _sources.find(id);
00580 if (it == _sources.end())
00581 {
00582 ZYPP_THROW(Exception("Unknown source ID"));
00583 }
00584 return it->second;
00585 }
00586
00587 Source_Ref SourceManager::findSource(const std::string & alias_r)
00588 {
00589 SourceMap::iterator it;
00590 for (it = _sources.begin(); it != _sources.end(); ++it)
00591 {
00592 if (it->second.alias() == alias_r)
00593 {
00594 return it->second;
00595 }
00596 }
00597 ZYPP_THROW(Exception("Unknown source name '"+alias_r+"'"));
00598
00599 return it->second;
00600 }
00601
00602 Source_Ref SourceManager::findSourceByUrl(const Url & url_r)
00603 {
00604 SourceMap::iterator it;
00605 for (it = _sources.begin(); it != _sources.end(); ++it)
00606 {
00607 if (it->second.url().asCompleteString() == url_r.asCompleteString())
00608 {
00609 return it->second;
00610 }
00611 }
00612 ZYPP_THROW(Exception("Unknown source URL '"+url_r.asString()+"'"));
00613
00614 return it->second;
00615 }
00616
00618
00620
00621 std::ostream & FailedSourcesRestoreException::dumpOn( std::ostream & str ) const
00622 {
00623 return str << _summary;
00624 }
00625
00626 std::ostream & FailedSourcesRestoreException::dumpOnTranslated( std::ostream & str ) const
00627 {
00628 return str << Exception::asUserString() << endl << _translatedSummary;
00629 }
00630
00631 bool FailedSourcesRestoreException::empty () const
00632 {
00633 return _summary.empty();
00634 }
00635
00636 std::set<std::string> FailedSourcesRestoreException::aliases () const
00637 {
00638 return _aliases;
00639 }
00640
00641 void FailedSourcesRestoreException::append( std::string source, std::string alias, const Exception& expt)
00642 {
00643 _summary = _summary + "\n" + source + ": " + expt.asString();
00644 _translatedSummary = _translatedSummary + "\n" + source + ": " + expt.asUserString();
00645 _aliases.insert( alias );
00646 }
00647
00649 }