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