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
00058 struct PrintSourceMapEntry
00059 {
00060 void operator()( const SourceMap::value_type & el ) const
00061 {
00062 _str << endl << " - " << el.second;
00063 }
00064 PrintSourceMapEntry( std::ostream & str )
00065 : _str( str )
00066 {}
00067 std::ostream & _str;
00068 };
00069
00070 inline std::ostream & dumpSourceTableOn( std::ostream & str, bool trailingENDL = true )
00071 {
00072 str << "SourceManager: =========================" << endl
00073 << " known Sources " << _sources.size();
00074 std::for_each( _sources.begin(), _sources.end(), PrintSourceMapEntry(str) );
00075
00076 str << endl
00077 << " deleted Sources " << _deleted_sources.size();
00078 std::for_each( _deleted_sources.begin(), _deleted_sources.end(), PrintSourceMapEntry(str) );
00079 str << endl
00080 << "========================================";
00081 if ( trailingENDL )
00082 str << endl;
00083 return str;
00084 }
00085
00086 inline bool sourceTableRemove( SourceMap::iterator it )
00087 {
00088 if ( it == _sources.end() )
00089 return false;
00090
00091 MIL << "SourceManager remove " << it->second << endl;
00092 _deleted_sources[it->second.numericId()] = it->second;
00093 _sources.erase(it);
00094
00095
00096 it->second.release();
00097
00098 dumpSourceTableOn( DBG );
00099 return true;
00100 }
00101
00102 inline SourceManager::SourceId sourceTableAdd( Source_Ref source_r )
00103 {
00104 if ( source_r.numericId() )
00105 {
00106 MIL << "SourceManager add " << source_r << endl;
00107 _sources[source_r.numericId()] = source_r;
00108
00109 dumpSourceTableOn( DBG );
00110 }
00111 else
00112 {
00113
00114
00115 WAR << "SourceManager does not add Source::noSource" << endl;
00116 }
00117 return source_r.numericId();
00118 }
00119
00120 }
00121
00123
00124
00125
00126
00127 SourceManager::SourceManager()
00128 {
00129 MIL << "Created SourceManager Singleton." << endl;
00130 }
00131
00133
00134
00135
00136
00137 SourceManager::~SourceManager()
00138 {
00139 MIL << "Deleted SourceManager Singleton." << endl;
00140 }
00141
00142 SourceManager::const_iterator SourceManager::begin() const
00143 { return _sources.begin(); }
00144
00145 SourceManager::const_iterator SourceManager::end() const
00146 { return _sources.end(); }
00147
00148 SourceManager::SourceId_const_iterator SourceManager::SourceId_begin() const
00149 { return make_map_key_begin( _sources ); }
00150
00151 SourceManager::SourceId_const_iterator SourceManager::SourceId_end() const
00152 { return make_map_key_end( _sources ); }
00153
00154 SourceManager::Source_const_iterator SourceManager::Source_begin() const
00155 { return make_map_value_begin( _sources ); }
00156
00157 SourceManager::Source_const_iterator SourceManager::Source_end() const
00158 { return make_map_value_end( _sources ); }
00159
00160 void SourceManager::reset()
00161 {
00162 MIL << "SourceManager reset (forget all sources)" << endl;
00163 _sources.clear();
00164 _deleted_sources.clear();
00165 }
00166
00167 SourceManager::SourceId SourceManager::addSource( Source_Ref source_r )
00168 {
00169 return sourceTableAdd( source_r );
00170 }
00171
00172 void SourceManager::removeSource(SourceManager::SourceId id)
00173 {
00174 if ( ! sourceTableRemove( _sources.find(id) ) )
00175 {
00176 WAR << "SourceManager remove: no source with SourceId " << id << endl;
00177 }
00178 }
00179
00180 void SourceManager::removeSource( const std::string & alias_r )
00181 {
00182 SourceMap::iterator it = _sources.begin();
00183 for ( ; it != _sources.end() && it->second.alias() != alias_r; ++it )
00184 ;
00185
00186 if ( ! sourceTableRemove( it ) )
00187 {
00188 WAR << "SourceManager remove: no source with alias " << alias_r << endl;
00189 }
00190 }
00191
00192 void SourceManager::removeSourceByUrl( const Url & url_r )
00193 {
00194 SourceMap::iterator it = _sources.begin();
00195 for ( ; it != _sources.end() && it->second.url().asString() != url_r.asString(); ++it )
00196 ;
00197
00198 if ( ! sourceTableRemove( it ) )
00199 {
00200 WAR << "SourceManager remove: no source with Url " << url_r << endl;
00201 }
00202 }
00203
00204 void SourceManager::releaseAllSources()
00205 {
00206 MIL << "SourceManager releasing all sources ..." << endl;
00207 for (SourceMap::iterator it = _sources.begin();
00208 it != _sources.end(); it++)
00209 {
00210 it->second.release();
00211 }
00212 MIL << "SourceManager releasing all sources done." << endl;
00213 }
00214
00215 void SourceManager::reattachSources(const Pathname &attach_point)
00216 {
00217 MIL << "SourceManager reattach all sources to '" << attach_point << " ..." << endl;
00218 for (SourceMap::iterator it = _sources.begin();
00219 it != _sources.end(); it++)
00220 {
00221 it->second.reattach(attach_point);
00222 }
00223 MIL << "SourceManager reattach all sources to '" << attach_point << " done." << endl;
00224 }
00225
00226
00227 void SourceManager::disableAllSources()
00228 {
00229 MIL << "SourceManager disable all sources ..." << endl;
00230 for( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
00231 {
00232 it->second.disable();
00233 }
00234 MIL << "SourceManager disable all sources done." << endl;
00235 }
00236
00237 std::list<SourceManager::SourceId> SourceManager::enabledSources() const
00238 {
00239 std::list<SourceManager::SourceId> res;
00240
00241 for( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
00242 {
00243 if( it->second.enabled() )
00244 res.push_back(it->first);
00245 }
00246
00247 return res;
00248 }
00249
00250 std::list<SourceManager::SourceId> SourceManager::allSources() const
00251 {
00252 std::list<SourceManager::SourceId> res;
00253
00254 for( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
00255 {
00256 res.push_back(it->first);
00257 }
00258
00259 return res;
00260 }
00261
00262 void SourceManager::store(Pathname root_r, bool metadata_cache )
00263 {
00264 MIL << "SourceManager store '" << root_r << ( metadata_cache ? "' (metadata_cache)" : "'" )
00265 << " ..." << endl;
00266
00267 storage::PersistentStorage store;
00268 store.init( root_r );
00269
00270
00271
00272 if( metadata_cache )
00273 {
00274
00275
00276 filesystem::assert_dir( root_r / getZYpp()->homePath() );
00277 Pathname topdir( root_r / ZYPP_METADATA_PREFIX );
00278 filesystem::assert_dir( topdir );
00279 MIL << "Created..." << topdir << std::endl;
00280 }
00281
00282
00283
00284 for( SourceMap::iterator it = _deleted_sources.begin(); it != _deleted_sources.end(); it++)
00285 {
00286 MIL << "Deleting source " << it->second << " from persistent store" << endl;
00287 store.deleteSource( it->second.alias() );
00288 filesystem::recursive_rmdir( it->second.cacheDir() );
00289 }
00290
00291 _deleted_sources.clear();
00292
00293 for( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
00294 {
00295 storage::PersistentStorage::SourceData descr;
00296
00297 descr.url = it->second.url().asCompleteString();
00298 descr.enabled = it->second.enabled();
00299 descr.alias = it->second.alias();
00300 descr.autorefresh = it->second.autorefresh();
00301 descr.type = it->second.type();
00302 descr.product_dir = it->second.path();
00303
00304 descr.cache_dir = it->second.cacheDir();
00305
00306 if( metadata_cache && descr.cache_dir.empty() )
00307 {
00308 if( descr.cache_dir.empty() )
00309 {
00310 filesystem::TmpDir newCache( root_r / ZYPP_METADATA_PREFIX, "Source." );
00311 descr.cache_dir = ZYPP_METADATA_PREFIX + newCache.path().basename();
00312 }
00313
00314 filesystem::assert_dir ( root_r.asString() + descr.cache_dir );
00315
00316 MIL << "Storing metadata to (" << root_r.asString() << ")/" << descr.cache_dir << endl;
00317
00318 try {
00319 it->second.storeMetadata( root_r.asString() + descr.cache_dir );
00320 }
00321 catch(const Exception &excp) {
00322 WAR << "Creating local metadata cache failed, not using cache" << endl;
00323 descr.cache_dir = "";
00324 }
00325 }
00326
00327 store.storeSource( descr );
00328 }
00329
00330 MIL << "SourceManager store done." << endl;
00331 }
00332
00336 bool SourceManager::restore( Pathname root_r, bool use_caches, const std::string &alias_filter, const std::string &url_filter )
00337 {
00338 MIL << "SourceManager restore ('" << root_r << ( use_caches ? "' (use_caches)" : "'" )
00339 << ", alias_filter '" << alias_filter
00340 << ", url_filter '" << url_filter << "')" << endl;
00341
00342 if (! _sources.empty() ) {
00343
00344
00345
00346 if (alias_filter.empty()
00347 && url_filter.empty())
00348 {
00349 ZYPP_THROW(SourcesAlreadyRestoredException());
00350
00351 }
00352
00353
00354
00355 for (SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); ++it) {
00356 if (!alias_filter.empty()
00357 && (alias_filter == it->second.alias()) )
00358 {
00359 MIL << "Source with alias '" << alias_filter << "' already restored.";
00360 return true;
00361 }
00362 if (!url_filter.empty()
00363 && (url_filter == it->second.url().asString()) )
00364 {
00365 MIL << "Source with url '" << url_filter << "' already restored.";
00366 return true;
00367 }
00368 }
00369 }
00370
00371 FailedSourcesRestoreException report;
00372
00373 storage::PersistentStorage store;
00374 store.init( root_r );
00375
00376 std::list<storage::PersistentStorage::SourceData> new_sources = store.storedSources();
00377
00378 MIL << "Found sources: " << new_sources.size() << endl;
00379
00380 for( std::list<storage::PersistentStorage::SourceData>::iterator it = new_sources.begin(); it != new_sources.end(); ++it)
00381 {
00382 if ( !alias_filter.empty()
00383 && (alias_filter != it->alias) )
00384 {
00385 continue;
00386 }
00387
00388 if ( !url_filter.empty()
00389 && (url_filter != it->url.asString()) )
00390 {
00391 continue;
00392 }
00393
00394
00395 MIL << "Restoring source: url:[" << Url(it->url).asString() << "] product_dir:[" << it->product_dir << "] alias:[" << it->alias << "] cache_dir:[" << it->cache_dir << "]" << endl;
00396
00397 SourceId id = 0;
00398
00399 try {
00400 id = addSource( SourceFactory().createFrom(it->type, it->url, it->product_dir, it->alias, it->cache_dir, false, it->autorefresh) );
00401 }
00402 catch (const Exception &expt )
00403 {
00404
00405 ERR << "Unable to restore source from " << Url(it->url).asString()
00406 << endl;
00407
00408 id = 0;
00409 Url url2;
00410 try {
00411 url2 = it->url;
00412 std::string scheme( url2.getScheme());
00413
00414 if( (scheme == "cd" || scheme == "dvd") &&
00415 !url2.getQueryParam("devices").empty())
00416 {
00417 url2.setQueryParam("devices", "");
00418
00419 DBG << "CD/DVD devices changed - try again without a devices list"
00420 << std::endl;
00421
00422 id = addSource( SourceFactory().createFrom(url2, it->product_dir, it->alias, it->cache_dir, false) );
00423
00424
00425
00426 }
00427 }
00428 catch (const Exception &e2)
00429 {
00430
00431 ERR << "Unable to restore source from " << url2.asString()
00432 << endl;
00433 id = 0;
00434 ZYPP_CAUGHT(e2);
00435 }
00436
00437 if( id == 0)
00438 {
00439 report.append( it->url.asString() + it->product_dir.asString(), it->alias, expt );
00440 continue;
00441 }
00442 }
00443
00444 DBG << "Added source as id " << id << endl;
00445
00446 Source_Ref src = findSource( id );
00447
00448 if ( it->enabled ) {
00449 DBG << "enable source" << endl;
00450 src.enable();
00451 }
00452 else {
00453 DBG << "disable source" << endl;
00454 src.disable();
00455 }
00456 }
00457
00458 if( !report.empty() )
00459 {
00460 ZYPP_THROW(report);
00461 }
00462
00463 MIL << "SourceManager restore done." << endl;
00464 dumpSourceTableOn( DBG );
00465 return true;
00466 }
00467
00468 void SourceManager::disableSourcesAt( const Pathname & root_r )
00469 {
00470 storage::PersistentStorage store;
00471 store.init( root_r );
00472
00473 std::list<storage::PersistentStorage::SourceData> new_sources = store.storedSources();
00474
00475 MIL << "Disabling all sources in store at " << root_r << endl;
00476
00477 for( std::list<storage::PersistentStorage::SourceData>::iterator it = new_sources.begin();
00478 it != new_sources.end(); ++it)
00479 {
00480 MIL << "Disabling source " << it->alias << endl;
00481 it->enabled = false;
00482 store.storeSource( *it );
00483 }
00484 }
00485
00486 SourceManager::SourceInfoList SourceManager::knownSourceInfos(const Pathname &root_r)
00487 {
00488 storage::PersistentStorage store;
00489 SourceInfoList result;
00490 store.init( root_r );
00491
00492 std::list<storage::PersistentStorage::SourceData> sources = store.storedSources();
00493
00494 MIL << "Found sources: " << sources.size() << endl;
00495
00496 for( std::list<storage::PersistentStorage::SourceData>::iterator it = sources.begin();
00497 it != sources.end(); ++it)
00498 {
00499 SourceInfo info = { it->alias, it->url, it->type, it->autorefresh };
00500 result.push_back( info );
00501 }
00502 return result;
00503 }
00504
00505
00506
00507
00508
00509
00510 std::ostream & operator<<( std::ostream & str, const SourceManager & obj )
00511 {
00512 return dumpSourceTableOn( str, false );
00513 }
00514
00515 Source_Ref SourceManager::findSource(SourceId id)
00516 {
00517 SourceMap::iterator it = _sources.find(id);
00518 if (it == _sources.end())
00519 {
00520 ZYPP_THROW(Exception("Unknown source ID"));
00521 }
00522 return it->second;
00523 }
00524
00525 Source_Ref SourceManager::findSource(const std::string & alias_r)
00526 {
00527 SourceMap::iterator it;
00528 for (it = _sources.begin(); it != _sources.end(); ++it)
00529 {
00530 if (it->second.alias() == alias_r) {
00531 return it->second;
00532 }
00533 }
00534 ZYPP_THROW(Exception("Unknown source name '"+alias_r+"'"));
00535
00536 return it->second;
00537 }
00538
00539 Source_Ref SourceManager::findSourceByUrl(const Url & url_r)
00540 {
00541 SourceMap::iterator it;
00542 for (it = _sources.begin(); it != _sources.end(); ++it)
00543 {
00544 if (it->second.url().asCompleteString() == url_r.asCompleteString()) {
00545 return it->second;
00546 }
00547 }
00548 ZYPP_THROW(Exception("Unknown source URL '"+url_r.asString()+"'"));
00549
00550 return it->second;
00551 }
00552
00554
00556
00557 std::ostream & FailedSourcesRestoreException::dumpOn( std::ostream & str ) const
00558 {
00559 return str << _summary;
00560 }
00561
00562 std::ostream & FailedSourcesRestoreException::dumpOnTranslated( std::ostream & str ) const
00563 {
00564 return str << Exception::asUserString() << endl << _translatedSummary;
00565 }
00566
00567 bool FailedSourcesRestoreException::empty () const
00568 {
00569 return _summary.empty();
00570 }
00571
00572 std::set<std::string> FailedSourcesRestoreException::aliases () const
00573 {
00574 return _aliases;
00575 }
00576
00577 void FailedSourcesRestoreException::append( std::string source, std::string alias, const Exception& expt)
00578 {
00579 _summary = _summary + "\n" + source + ": " + expt.asString();
00580 _translatedSummary = _translatedSummary + "\n" + source + ": " + expt.asUserString();
00581 _aliases.insert( alias );
00582 }
00583
00585 }