1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/SourceManager.cc
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/Algorithm.h"
17 #include "zypp/base/Gettext.h"
19 #include "zypp/ZYpp.h"
20 #include "zypp/ZYppFactory.h"
21 #include "zypp/SourceManager.h"
22 #include "zypp/SourceFactory.h"
23 #include "zypp/Source.h"
24 #include "zypp/source/SourceImpl.h"
25 #include "zypp/target/store/PersistentStorage.h"
26 #include "zypp/TmpPath.h"
27 #include "zypp/Pathname.h"
28 #include "zypp/PathInfo.h"
30 ///////////////////////////////////////////////////////////////////
31 #undef ZYPP_BASE_LOGGER_LOGGROUP
32 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::SourceManager"
33 ///////////////////////////////////////////////////////////////////
35 #define ZYPP_METADATA_PREFIX ( getZYpp()->homePath().asString()+"/cache/" )
39 ///////////////////////////////////////////////////////////////////
41 { /////////////////////////////////////////////////////////////////
43 IMPL_PTR_TYPE(SourceManager)
45 SourceManager_Ptr SourceManager::sourceManager()
47 static SourceManager_Ptr _source_manager( new SourceManager );
48 return _source_manager;
53 typedef std::map<SourceManager::SourceId, Source_Ref> SourceMap;
55 static SourceMap _sources;
56 static SourceMap _deleted_sources;
57 static std::set<std::string> _renamed_sources;
59 struct PrintSourceMapEntry
61 void operator()( const SourceMap::value_type & el ) const
63 _str << endl << " - " << el.second;
65 PrintSourceMapEntry( std::ostream & str )
71 inline std::ostream & dumpSourceTableOn( std::ostream & str, bool trailingENDL = true )
73 str << "SourceManager: =========================" << endl
74 << " known Sources " << _sources.size();
75 std::for_each( _sources.begin(), _sources.end(), PrintSourceMapEntry(str) );
78 << " deleted Sources " << _deleted_sources.size();
79 std::for_each( _deleted_sources.begin(), _deleted_sources.end(), PrintSourceMapEntry(str) );
81 << "========================================";
87 inline bool sourceTableRemove( SourceMap::iterator it )
89 if ( it == _sources.end() )
92 MIL << "SourceManager remove " << it->second << endl;
93 _deleted_sources[it->second.numericId()] = it->second;
96 // release all media of this source, not needed anymore (#159754)
99 dumpSourceTableOn( DBG );
103 inline SourceManager::SourceId sourceTableAdd( Source_Ref source_r )
105 if ( source_r.numericId() )
107 MIL << "SourceManager add " << source_r << endl;
108 _sources[source_r.numericId()] = source_r;
110 dumpSourceTableOn( DBG );
114 // Not worth an Exception. Request to add noSource, adds no Source,
115 // and returns the noSource Id.
116 WAR << "SourceManager does not add Source::noSource" << endl;
118 return source_r.numericId();
123 ///////////////////////////////////////////////////////////////////
125 // METHOD NAME : SourceManager::SourceManager
126 // METHOD TYPE : Ctor
128 SourceManager::SourceManager()
130 MIL << "Created SourceManager Singleton." << endl;
133 ///////////////////////////////////////////////////////////////////
135 // METHOD NAME : SourceManager::~SourceManager
136 // METHOD TYPE : Dtor
138 SourceManager::~SourceManager()
140 MIL << "Deleted SourceManager Singleton." << endl;
143 SourceManager::const_iterator SourceManager::begin() const
145 return _sources.begin();
148 SourceManager::const_iterator SourceManager::end() const
150 return _sources.end();
153 SourceManager::SourceId_const_iterator SourceManager::SourceId_begin() const
155 return make_map_key_begin( _sources );
158 SourceManager::SourceId_const_iterator SourceManager::SourceId_end() const
160 return make_map_key_end( _sources );
163 SourceManager::Source_const_iterator SourceManager::Source_begin() const
165 return make_map_value_begin( _sources );
168 SourceManager::Source_const_iterator SourceManager::Source_end() const
170 return make_map_value_end( _sources );
173 void SourceManager::reset()
175 MIL << "SourceManager reset (forget all sources)" << endl;
177 _deleted_sources.clear();
180 SourceManager::SourceId SourceManager::addSource( Source_Ref source_r )
182 return sourceTableAdd( source_r );
185 void SourceManager::renameSource( SourceId id, const std::string & new_alias_r )
187 Source_Ref src = findSource(id);
191 // delete the old entry in the storage
192 // the new entry will appear when doing
194 _renamed_sources.insert(src.alias());
196 src.setAlias( new_alias_r );
201 void SourceManager::removeSource(SourceManager::SourceId id)
203 if ( ! sourceTableRemove( _sources.find(id) ) )
205 WAR << "SourceManager remove: no source with SourceId " << id << endl;
209 void SourceManager::removeSource( const std::string & alias_r )
211 SourceMap::iterator it = _sources.begin();
212 for ( ; it != _sources.end() && it->second.alias() != alias_r; ++it )
215 if ( ! sourceTableRemove( it ) )
217 WAR << "SourceManager remove: no source with alias " << alias_r << endl;
221 void SourceManager::removeSourceByUrl( const Url & url_r )
223 SourceMap::iterator it = _sources.begin();
224 for ( ; it != _sources.end() && it->second.url().asString() != url_r.asString(); ++it )
227 if ( ! sourceTableRemove( it ) )
229 WAR << "SourceManager remove: no source with Url " << url_r << endl;
233 void SourceManager::releaseAllSources()
235 MIL << "SourceManager releasing all sources ..." << endl;
236 for (SourceMap::iterator it = _sources.begin();
237 it != _sources.end(); it++)
239 it->second.release();
241 MIL << "SourceManager releasing all sources done." << endl;
244 void SourceManager::reattachSources(const Pathname &attach_point)
246 MIL << "SourceManager reattach all sources to '" << attach_point << " ..." << endl;
247 for (SourceMap::iterator it = _sources.begin();
248 it != _sources.end(); it++)
250 it->second.reattach(attach_point);
252 MIL << "SourceManager reattach all sources to '" << attach_point << " done." << endl;
256 void SourceManager::disableAllSources()
258 MIL << "SourceManager disable all sources ..." << endl;
259 for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
261 it->second.disable();
263 MIL << "SourceManager disable all sources done." << endl;
266 std::list<SourceManager::SourceId> SourceManager::enabledSources() const
268 std::list<SourceManager::SourceId> res;
270 for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
272 if ( it->second.enabled() )
273 res.push_back(it->first);
279 std::list<SourceManager::SourceId> SourceManager::allSources() const
281 std::list<SourceManager::SourceId> res;
283 for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
285 res.push_back(it->first);
291 void SourceManager::store(Pathname root_r, bool metadata_cache )
293 MIL << "SourceManager store '" << root_r << ( metadata_cache ? "' (metadata_cache)" : "'" )
296 storage::PersistentStorage store;
297 store.init( root_r );
300 // make sure to create the source metadata cache
301 if ( metadata_cache )
303 // make sure our root exists
305 filesystem::assert_dir( root_r / getZYpp()->homePath() );
306 Pathname topdir( root_r / ZYPP_METADATA_PREFIX );
307 filesystem::assert_dir( topdir );
308 MIL << "Created..." << topdir << std::endl;
311 // delete renamed sources entries
312 for ( std::set<std::string>::const_iterator it = _renamed_sources.begin(); it != _renamed_sources.end(); it++)
314 MIL << "removing source entry " << *it << " (renamed) from persistent store" << endl;
315 store.deleteSource( *it );
318 _renamed_sources.clear();
320 // delete before modifying and creating
321 // so that we can recreate a deleted one (#174295)
322 for ( SourceMap::iterator it = _deleted_sources.begin(); it != _deleted_sources.end(); it++)
324 MIL << "Deleting source " << it->second << " from persistent store" << endl;
325 store.deleteSource( it->second.alias() );
326 filesystem::recursive_rmdir( it->second.cacheDir() );
329 _deleted_sources.clear();
331 for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
333 source::SourceInfo descr;
335 descr.setUrl(it->second.url());
336 descr.setEnabled( it->second.enabled() );
337 descr.setAlias( it->second.alias() );
338 descr.setAutorefresh( it->second.autorefresh() );
339 descr.setType( it->second.type() );
340 descr.setPath( it->second.path() );
342 descr.setCacheDir( it->second.cacheDir() );
344 if ( metadata_cache && descr.cacheDir().empty() )
346 if ( descr.cacheDir().empty() )
348 filesystem::TmpDir newCache( root_r / ZYPP_METADATA_PREFIX, "Source." );
349 descr.setCacheDir( ZYPP_METADATA_PREFIX + newCache.path().basename() );
352 filesystem::assert_dir ( root_r.asString() + descr.cacheDir() );
354 MIL << "Storing metadata to (" << root_r.asString() << ")/" << descr.cacheDir() << endl;
358 it->second.storeMetadata( root_r.asString() + descr.cacheDir() );
360 catch (const Exception &excp)
362 WAR << "Creating local metadata cache failed, not using cache" << endl;
363 descr.setCacheDir("");
367 store.storeSource( descr );
370 MIL << "SourceManager store done." << endl;
373 /** \todo Broken design: either use return value or Exception to
374 * indicate errors, not both.
376 bool SourceManager::restore( Pathname root_r, bool use_caches, const std::string &alias_filter, const std::string &url_filter )
378 MIL << "SourceManager restore ('" << root_r << ( use_caches ? "' (use_caches)" : "'" ) << ", alias_filter '" << alias_filter << ", url_filter '" << url_filter << "')" << endl;
380 if (! _sources.empty() )
383 // if we've already restored sources and this is an unfiltered call, reject it.
385 if (alias_filter.empty()
386 && url_filter.empty())
388 ZYPP_THROW(SourcesAlreadyRestoredException());
389 //Exception ( N_("At least one source already registered, cannot restore sources from persistent store.") ) );
392 // check filters against already restore sources and check for duplicates.
394 for (SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); ++it)
396 if (!alias_filter.empty() && (alias_filter == it->second.alias()) )
398 MIL << "Source with alias '" << alias_filter << "' already restored.";
402 if (!url_filter.empty() && (url_filter == it->second.url().asString()) )
404 MIL << "Source with url '" << url_filter << "' already restored.";
410 FailedSourcesRestoreException report;
412 storage::PersistentStorage store;
413 store.init( root_r );
415 std::list<source::SourceInfo> new_sources = store.storedSources();
417 MIL << "Found sources: " << new_sources.size() << endl;
419 for ( std::list<source::SourceInfo>::iterator it = new_sources.begin(); it != new_sources.end(); ++it)
421 if ( !alias_filter.empty() // check alias filter, if set
422 && (alias_filter != it->alias()) )
427 if ( !url_filter.empty() // check url filter, if set
428 && (url_filter != it->url().asString()) )
433 // Note: Url(it->url).asString() to hide password in logs
434 MIL << "Restoring source: url:[" << it->url().asString() << "] product_dir:[" << it->path() << "] alias:[" << it->alias() << "] cache_dir:[" << it->cacheDir() << "] auto_refresh:[ " << it->autorefresh() << "]" << endl;
440 Source_Ref src = SourceFactory().createFrom(it->type(), it->url(), it->path(), it->alias(), it->cacheDir(), false, it->autorefresh());
443 catch (const Exception &expt )
445 // Note: Url(it->url).asString() to hide password in logs
446 ERR << "Unable to restore source from " << it->url().asString() << endl;
453 std::string scheme( url2.getScheme());
455 if ( (scheme == "cd" || scheme == "dvd") && !url2.getQueryParam("devices").empty())
457 url2.setQueryParam("devices", "");
458 DBG << "CD/DVD devices changed - try again without a devices list" << std::endl;
460 id = addSource( SourceFactory().createFrom(url2, it->path(), it->alias(), it->cacheDir(), false ) );
462 // This worked ... update it->url ?
463 //it->url = url2.asCompleteString();
466 catch (const Exception &e2)
468 // Note: Url(it->url).asString() to hide password in logs
469 ERR << "Unable to restore source from " << url2.asString()
477 report.append( it->url().asString() + it->path().asString(), it->alias(), expt );
482 DBG << "Added source as id " << id << endl;
483 // should not throw, we've just created the source
484 Source_Ref src = findSource( id );
488 DBG << "enable source" << endl;
493 DBG << "disable source" << endl;
498 if ( !report.empty() )
503 MIL << "SourceManager restore done." << endl;
504 dumpSourceTableOn( DBG );
508 void SourceManager::disableSourcesAt( const Pathname & root_r )
510 storage::PersistentStorage store;
511 store.init( root_r );
513 std::list<source::SourceInfo> new_sources = store.storedSources();
515 MIL << "Disabling all sources in store at " << root_r << endl;
517 for ( std::list<source::SourceInfo>::iterator it = new_sources.begin();
518 it != new_sources.end(); ++it)
520 MIL << "Disabling source " << it->alias() << endl;
521 it->setEnabled(false);
522 store.storeSource( *it );
526 source::SourceInfoList SourceManager::knownSourceInfos(const Pathname &root_r)
528 storage::PersistentStorage store;
529 SourceInfoList result;
530 store.init( root_r );
532 source::SourceInfoList sources = store.storedSources();
533 MIL << "Found sources: " << sources.size() << endl;
537 /******************************************************************
539 ** FUNCTION NAME : operator<<
540 ** FUNCTION TYPE : std::ostream &
542 std::ostream & operator<<( std::ostream & str, const SourceManager & obj )
544 return dumpSourceTableOn( str, /*tailingENDL*/false );
547 Source_Ref SourceManager::findSource(SourceId id)
549 SourceMap::iterator it = _sources.find(id);
550 if (it == _sources.end())
552 ZYPP_THROW(Exception("Unknown source ID"));
557 Source_Ref SourceManager::findSource(const std::string & alias_r)
559 SourceMap::iterator it;
560 for (it = _sources.begin(); it != _sources.end(); ++it)
562 if (it->second.alias() == alias_r)
567 ZYPP_THROW(Exception("Unknown source name '"+alias_r+"'"));
569 return it->second; // just to keep gcc happy
572 Source_Ref SourceManager::findSourceByUrl(const Url & url_r)
574 SourceMap::iterator it;
575 for (it = _sources.begin(); it != _sources.end(); ++it)
577 if (it->second.url().asCompleteString() == url_r.asCompleteString())
582 ZYPP_THROW(Exception("Unknown source URL '"+url_r.asString()+"'"));
584 return it->second; // just to keep gcc happy
587 /////////////////////////////////////////////////////////////////
588 // FailedSourcesRestoreException
589 ///////////////////////////////////////////////////////////////////
591 std::ostream & FailedSourcesRestoreException::dumpOn( std::ostream & str ) const
593 return str << _summary;
596 std::ostream & FailedSourcesRestoreException::dumpOnTranslated( std::ostream & str ) const
598 return str << Exception::asUserString() << endl << _translatedSummary;
601 bool FailedSourcesRestoreException::empty () const
603 return _summary.empty();
606 std::set<std::string> FailedSourcesRestoreException::aliases () const
611 void FailedSourcesRestoreException::append( std::string source, std::string alias, const Exception& expt)
613 _summary = _summary + "\n" + source + ": " + expt.asString();
614 _translatedSummary = _translatedSummary + "\n" + source + ": " + expt.asUserString();
615 _aliases.insert( alias );
618 /////////////////////////////////////////////////////////////////
620 ///////////////////////////////////////////////////////////////////