ignore
[platform/upstream/libzypp.git] / zypp / SourceManager.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/SourceManager.cc
10  *
11 */
12 #include <iostream>
13 #include <map>
14
15 #include "zypp/base/Logger.h"
16 #include "zypp/base/Algorithm.h"
17 #include "zypp/base/Gettext.h"
18
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"
29
30 ///////////////////////////////////////////////////////////////////
31 #undef  ZYPP_BASE_LOGGER_LOGGROUP
32 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::SourceManager"
33 ///////////////////////////////////////////////////////////////////
34
35 #define ZYPP_METADATA_PREFIX ( getZYpp()->homePath().asString()+"/cache/" )
36
37 using std::endl;
38
39 ///////////////////////////////////////////////////////////////////
40 namespace zypp
41 { /////////////////////////////////////////////////////////////////
42
43   IMPL_PTR_TYPE(SourceManager)
44
45   SourceManager_Ptr SourceManager::sourceManager()
46   {
47     static SourceManager_Ptr _source_manager( new SourceManager );
48     return _source_manager;
49   }
50
51   namespace
52   {
53     typedef std::map<SourceManager::SourceId, Source_Ref> SourceMap;
54
55     static SourceMap _sources;
56     static SourceMap _deleted_sources;
57     static std::set<std::string> _renamed_sources;
58
59     struct PrintSourceMapEntry
60     {
61       void operator()( const SourceMap::value_type & el ) const
62       {
63         _str << endl << "    - " << el.second;
64       }
65       PrintSourceMapEntry( std::ostream & str )
66           : _str( str )
67       {}
68       std::ostream & _str;
69     };
70
71     inline std::ostream & dumpSourceTableOn( std::ostream & str, bool trailingENDL = true )
72     {
73       str << "SourceManager: =========================" << endl
74       << "  known Sources " << _sources.size();
75       std::for_each( _sources.begin(), _sources.end(), PrintSourceMapEntry(str) );
76
77       str << endl
78       << "  deleted Sources " << _deleted_sources.size();
79       std::for_each( _deleted_sources.begin(), _deleted_sources.end(), PrintSourceMapEntry(str) );
80       str << endl
81       << "========================================";
82       if ( trailingENDL )
83         str << endl;
84       return str;
85     }
86
87     inline bool sourceTableRemove( SourceMap::iterator it )
88     {
89       if ( it == _sources.end() )
90         return false;
91
92       MIL << "SourceManager remove " << it->second << endl;
93       _deleted_sources[it->second.numericId()] = it->second;
94       _sources.erase(it);
95
96       // release all media of this source, not needed anymore (#159754)
97       it->second.release();
98
99       dumpSourceTableOn( DBG );
100       return true;
101     }
102
103     inline SourceManager::SourceId sourceTableAdd( Source_Ref source_r )
104     {
105       if ( source_r.numericId() )
106       {
107         MIL << "SourceManager add " << source_r << endl;
108         _sources[source_r.numericId()] = source_r;
109
110         dumpSourceTableOn( DBG );
111       }
112       else
113       {
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;
117       }
118       return source_r.numericId();
119     }
120
121   }
122
123   ///////////////////////////////////////////////////////////////////
124   //
125   // METHOD NAME : SourceManager::SourceManager
126   // METHOD TYPE : Ctor
127   //
128   SourceManager::SourceManager()
129   {
130     MIL << "Created SourceManager Singleton." << endl;
131   }
132
133   ///////////////////////////////////////////////////////////////////
134   //
135   // METHOD NAME : SourceManager::~SourceManager
136   // METHOD TYPE : Dtor
137   //
138   SourceManager::~SourceManager()
139   {
140     MIL << "Deleted SourceManager Singleton." << endl;
141   }
142
143   SourceManager::const_iterator SourceManager::begin() const
144   {
145     return _sources.begin();
146   }
147
148   SourceManager::const_iterator SourceManager::end() const
149   {
150     return _sources.end();
151   }
152
153   SourceManager::SourceId_const_iterator SourceManager::SourceId_begin() const
154   {
155     return make_map_key_begin( _sources );
156   }
157
158   SourceManager::SourceId_const_iterator SourceManager::SourceId_end() const
159   {
160     return make_map_key_end( _sources );
161   }
162
163   SourceManager::Source_const_iterator SourceManager::Source_begin() const
164   {
165     return make_map_value_begin( _sources );
166   }
167
168   SourceManager::Source_const_iterator SourceManager::Source_end() const
169   {
170     return make_map_value_end( _sources );
171   }
172
173   void SourceManager::reset()
174   {
175     MIL << "SourceManager reset (forget all sources)" << endl;
176     _sources.clear();
177     _deleted_sources.clear();
178   }
179
180   SourceManager::SourceId SourceManager::addSource( Source_Ref source_r )
181   {
182     return sourceTableAdd( source_r );
183   }
184
185   void SourceManager::renameSource( SourceId id, const std::string & new_alias_r )
186   {
187     Source_Ref src = findSource(id);
188     
189     if ( src )
190     {
191       // delete the old entry in the storage
192       // the new entry will appear when doing
193       // store
194       _renamed_sources.insert(src.alias());
195       // set the new alias
196       src.setAlias( new_alias_r );
197     }
198     
199   }
200   
201   void SourceManager::removeSource(SourceManager::SourceId id)
202   {
203     if ( ! sourceTableRemove( _sources.find(id) ) )
204     {
205       WAR << "SourceManager remove: no source with SourceId " << id << endl;
206     }
207   }
208
209   void SourceManager::removeSource( const std::string & alias_r )
210   {
211     SourceMap::iterator it = _sources.begin();
212     for ( ; it != _sources.end() && it->second.alias() != alias_r; ++it )
213       ; // empty body
214
215     if ( ! sourceTableRemove( it ) )
216     {
217       WAR << "SourceManager remove: no source with alias " << alias_r << endl;
218     }
219   }
220
221   void SourceManager::removeSourceByUrl( const Url & url_r )
222   {
223     SourceMap::iterator it = _sources.begin();
224     for ( ; it != _sources.end() && it->second.url().asString() != url_r.asString(); ++it )
225       ; // empty body
226
227     if ( ! sourceTableRemove( it ) )
228     {
229       WAR << "SourceManager remove: no source with Url " << url_r << endl;
230     }
231   }
232
233   void SourceManager::releaseAllSources()
234   {
235     MIL << "SourceManager releasing all sources ..." << endl;
236     for (SourceMap::iterator it = _sources.begin();
237          it != _sources.end(); it++)
238     {
239       it->second.release();
240     }
241     MIL << "SourceManager releasing all sources done." << endl;
242   }
243
244   void SourceManager::reattachSources(const Pathname &attach_point)
245   {
246     MIL << "SourceManager reattach all sources to '" << attach_point << " ..." << endl;
247     for (SourceMap::iterator it = _sources.begin();
248          it != _sources.end(); it++)
249     {
250       it->second.reattach(attach_point);
251     }
252     MIL << "SourceManager reattach all sources to '" << attach_point << " done." << endl;
253   }
254
255
256   void SourceManager::disableAllSources()
257   {
258     MIL << "SourceManager disable all sources ..." << endl;
259     for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
260     {
261       it->second.disable();
262     }
263     MIL << "SourceManager disable all sources done." << endl;
264   }
265
266   std::list<SourceManager::SourceId> SourceManager::enabledSources() const
267   {
268     std::list<SourceManager::SourceId> res;
269
270     for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
271     {
272       if ( it->second.enabled() )
273         res.push_back(it->first);
274     }
275
276     return res;
277   }
278
279   std::list<SourceManager::SourceId> SourceManager::allSources() const
280   {
281     std::list<SourceManager::SourceId> res;
282
283     for ( SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); it++)
284     {
285       res.push_back(it->first);
286     }
287
288     return res;
289   }
290
291   void SourceManager::store(Pathname root_r, bool metadata_cache )
292   {
293     MIL << "SourceManager store '" << root_r << ( metadata_cache ? "' (metadata_cache)" : "'" )
294     << " ..." << endl;
295
296     storage::PersistentStorage store;
297     store.init( root_r );
298
299
300     // make sure to create the source metadata cache
301     if ( metadata_cache )
302     {
303       // make sure our root exists
304
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;
309     }
310
311     // delete renamed sources entries
312     for ( std::set<std::string>::const_iterator it = _renamed_sources.begin(); it != _renamed_sources.end(); it++)
313     {
314       MIL << "removing source entry " << *it << " (renamed) from persistent store" << endl;
315       store.deleteSource( *it );
316     }
317
318     _renamed_sources.clear();
319     
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++)
323     {
324       MIL << "Deleting source " << it->second << " from persistent store" << endl;
325       store.deleteSource( it->second.alias() );
326       filesystem::recursive_rmdir( it->second.cacheDir() );
327     }
328
329     _deleted_sources.clear();
330
331     for ( SourceMap::iterator it = _sources.begin(); it != _sources.end(); it++)
332     {
333       source::SourceInfo descr;
334
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() );
341
342       descr.setCacheDir( it->second.cacheDir() );
343
344       if ( metadata_cache && descr.cacheDir().empty() )
345       {
346         if ( descr.cacheDir().empty() )
347         {
348           filesystem::TmpDir newCache( root_r /  ZYPP_METADATA_PREFIX, "Source." );
349           descr.setCacheDir( ZYPP_METADATA_PREFIX + newCache.path().basename() );
350         }
351
352         filesystem::assert_dir ( root_r.asString() + descr.cacheDir() );
353
354         MIL << "Storing metadata to (" << root_r.asString() << ")/" << descr.cacheDir() << endl;
355
356         try
357         {
358           it->second.storeMetadata( root_r.asString() + descr.cacheDir() );
359         }
360         catch (const Exception &excp)
361         {
362           WAR << "Creating local metadata cache failed, not using cache" << endl;
363           descr.setCacheDir("");
364         }
365       }
366
367       store.storeSource( descr );
368     }
369
370     MIL << "SourceManager store done." << endl;
371   }
372
373   /** \todo Broken design: either use return value or Exception to
374   * indicate errors, not both.
375   */
376   bool SourceManager::restore( Pathname root_r, bool use_caches, const std::string &alias_filter, const std::string &url_filter )
377   {
378     MIL << "SourceManager restore ('" << root_r << ( use_caches ? "' (use_caches)" : "'" ) << ", alias_filter '" << alias_filter << ", url_filter '" << url_filter << "')" << endl;
379
380     if (! _sources.empty() )
381     {
382
383       // if we've already restored sources and this is an unfiltered call, reject it.
384
385       if (alias_filter.empty()
386           && url_filter.empty())
387       {
388         ZYPP_THROW(SourcesAlreadyRestoredException());
389         //Exception ( N_("At least one source already registered, cannot restore sources from persistent store.") ) );
390       }
391
392       // check filters against already restore sources and check for duplicates.
393       //
394       for (SourceMap::const_iterator it = _sources.begin(); it != _sources.end(); ++it)
395       {
396         if (!alias_filter.empty() && (alias_filter == it->second.alias()) )
397         {
398           MIL << "Source with alias '" << alias_filter << "' already restored.";
399           return true;
400         }
401
402         if (!url_filter.empty() && (url_filter == it->second.url().asString()) )
403         {
404           MIL << "Source with url '" << url_filter << "' already restored.";
405           return true;
406         }
407       }
408     }
409
410     FailedSourcesRestoreException report;
411
412     storage::PersistentStorage store;
413     store.init( root_r );
414
415     std::list<source::SourceInfo> new_sources = store.storedSources();
416
417     MIL << "Found sources: " << new_sources.size() << endl;
418
419     for ( std::list<source::SourceInfo>::iterator it = new_sources.begin(); it != new_sources.end(); ++it)
420     {
421       if ( !alias_filter.empty()   // check alias filter, if set
422            && (alias_filter != it->alias()) )
423       {
424         continue;
425       }
426
427       if ( !url_filter.empty()   // check url filter, if set
428            && (url_filter != it->url().asString()) )
429       {
430         continue;
431       }
432
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;
435
436       SourceId id = 0;
437
438       try
439       {
440         Source_Ref src = SourceFactory().createFrom(it->type(), it->url(), it->path(), it->alias(), it->cacheDir(), false, it->autorefresh());
441         id = addSource(src);
442       }
443       catch (const Exception &expt )
444       {
445         // Note: Url(it->url).asString() to hide password in logs
446         ERR << "Unable to restore source from " << it->url().asString() << endl;
447
448         id = 0;
449         Url url2;
450         try
451         {
452           url2 = it->url();
453           std::string scheme( url2.getScheme());
454
455           if ( (scheme == "cd" || scheme == "dvd") && !url2.getQueryParam("devices").empty())
456           {
457             url2.setQueryParam("devices", "");
458             DBG << "CD/DVD devices changed - try again without a devices list" << std::endl;
459
460             id = addSource( SourceFactory().createFrom(url2, it->path(), it->alias(), it->cacheDir(), false ) );
461
462             // This worked ... update it->url ?
463             //it->url = url2.asCompleteString();
464           }
465         }
466         catch (const Exception &e2)
467         {
468           // Note: Url(it->url).asString() to hide password in logs
469           ERR << "Unable to restore source from " << url2.asString()
470           << endl;
471           id = 0;
472           ZYPP_CAUGHT(e2);
473         }
474
475         if ( id == 0)
476         {
477           report.append( it->url().asString() + it->path().asString(), it->alias(), expt );
478           continue;
479         }
480       }
481
482       DBG << "Added source as id " << id << endl;
483       // should not throw, we've just created the source
484       Source_Ref src = findSource( id );
485
486       if ( it->enabled() )
487       {
488         DBG << "enable source" << endl;
489         src.enable();
490       }
491       else
492       {
493         DBG << "disable source" << endl;
494         src.disable();
495       }
496     }
497
498     if ( !report.empty() )
499     {
500       ZYPP_THROW(report);
501     }
502
503     MIL << "SourceManager restore done." << endl;
504     dumpSourceTableOn( DBG );
505     return true;
506   }
507
508   void SourceManager::disableSourcesAt( const Pathname & root_r )
509   {
510     storage::PersistentStorage store;
511     store.init( root_r );
512
513     std::list<source::SourceInfo> new_sources = store.storedSources();
514
515     MIL << "Disabling all sources in store at " << root_r << endl;
516
517     for ( std::list<source::SourceInfo>::iterator it = new_sources.begin();
518           it != new_sources.end(); ++it)
519     {
520       MIL << "Disabling source " << it->alias() << endl;
521       it->setEnabled(false);
522       store.storeSource( *it );
523     }
524   }
525
526   source::SourceInfoList SourceManager::knownSourceInfos(const Pathname &root_r)
527   {
528     storage::PersistentStorage store;
529     SourceInfoList result;
530     store.init( root_r );
531
532     source::SourceInfoList sources = store.storedSources();
533     MIL << "Found sources: " << sources.size() << endl;
534     return sources;
535   }
536
537   /******************************************************************
538   **
539   ** FUNCTION NAME : operator<<
540   ** FUNCTION TYPE : std::ostream &
541   */
542   std::ostream & operator<<( std::ostream & str, const SourceManager & obj )
543   {
544     return dumpSourceTableOn( str, /*tailingENDL*/false );
545   }
546
547   Source_Ref SourceManager::findSource(SourceId id)
548   {
549     SourceMap::iterator it = _sources.find(id);
550     if (it == _sources.end())
551     {
552       ZYPP_THROW(Exception("Unknown source ID"));
553     }
554     return it->second;
555   }
556
557   Source_Ref SourceManager::findSource(const std::string & alias_r)
558   {
559     SourceMap::iterator it;
560     for (it = _sources.begin(); it != _sources.end(); ++it)
561     {
562       if (it->second.alias() == alias_r)
563       {
564         return it->second;
565       }
566     }
567     ZYPP_THROW(Exception("Unknown source name '"+alias_r+"'"));
568     /*NOTREACHED*/
569     return it->second; // just to keep gcc happy
570   }
571
572   Source_Ref SourceManager::findSourceByUrl(const Url & url_r)
573   {
574     SourceMap::iterator it;
575     for (it = _sources.begin(); it != _sources.end(); ++it)
576     {
577       if (it->second.url().asCompleteString() == url_r.asCompleteString())
578       {
579         return it->second;
580       }
581     }
582     ZYPP_THROW(Exception("Unknown source URL '"+url_r.asString()+"'"));
583     /*NOTREACHED*/
584     return it->second; // just to keep gcc happy
585   }
586
587   /////////////////////////////////////////////////////////////////
588   // FailedSourcesRestoreException
589   ///////////////////////////////////////////////////////////////////
590
591   std::ostream & FailedSourcesRestoreException::dumpOn( std::ostream & str ) const
592   {
593     return str << _summary;
594   }
595
596   std::ostream & FailedSourcesRestoreException::dumpOnTranslated( std::ostream & str ) const
597   {
598     return str << Exception::asUserString() << endl << _translatedSummary;
599   }
600
601   bool FailedSourcesRestoreException::empty () const
602   {
603     return _summary.empty();
604   }
605
606   std::set<std::string> FailedSourcesRestoreException::aliases () const
607     {
608       return _aliases;
609     }
610
611   void FailedSourcesRestoreException::append( std::string source, std::string alias, const Exception& expt)
612   {
613     _summary = _summary + "\n" + source + ": " + expt.asString();
614     _translatedSummary = _translatedSummary + "\n" + source + ": " + expt.asUserString();
615     _aliases.insert( alias );
616   }
617
618   /////////////////////////////////////////////////////////////////
619 } // namespace zypp
620 ///////////////////////////////////////////////////////////////////