zypper port starts. zypp2 to zypp
[platform/upstream/libzypp.git] / zypp / RepoManager.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/RepoManager.cc
10  *
11 */
12
13 #include <iostream>
14 #include <list>
15 #include <algorithm>
16 #include "zypp/base/InputStream.h"
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/Function.h"
19 #include "zypp/PathInfo.h"
20 #include "zypp/TmpPath.h"
21
22 #include "zypp/repo/RepoException.h"
23 #include "zypp/RepoManager.h"
24
25 #include "zypp/cache/CacheStore.h"
26 #include "zypp/repo/cached/RepoImpl.h"
27 #include "zypp/MediaSetAccess.h"
28
29 #include "zypp/parser/RepoFileReader.h"
30 #include "zypp/source/yum/YUMDownloader.h"
31 #include "zypp/parser/yum/RepoParser.h"
32
33 #include "zypp/source/susetags/SUSETagsDownloader.h"
34 #include "zypp/parser/susetags/RepoParser.h"
35
36 using namespace std;
37 using namespace zypp;
38 using namespace zypp::repo;
39 using namespace zypp::filesystem;
40
41 using zypp::source::yum::YUMDownloader;
42 using zypp::source::susetags::SUSETagsDownloader;
43
44 ///////////////////////////////////////////////////////////////////
45 namespace zypp
46 { /////////////////////////////////////////////////////////////////
47
48   ///////////////////////////////////////////////////////////////////
49   //
50   //    CLASS NAME : RepoManagerOptions
51   //
52   ///////////////////////////////////////////////////////////////////
53   
54   RepoManagerOptions::RepoManagerOptions()
55   {
56     ZConfig globalConfig;
57     repoCachePath = globalConfig.defaultRepoCachePath();
58     repoRawCachePath = globalConfig.defaultRepoRawCachePath();
59     knownReposPath = globalConfig.defaultKnownReposPath();
60   }
61   
62   /**
63     * \short Simple callback to collect the results
64     */
65   struct RepoCollector
66   {
67     RepoCollector()
68     {
69       MIL << endl;
70     }
71     
72     ~RepoCollector()
73     {
74       MIL << endl;
75     }
76     
77     bool collect( const RepoInfo &repo )
78     {
79       //MIL << "here in collector: " << repo.alias() << endl;
80       repos.push_back(repo);
81       //MIL << "added: " << repo.alias() << endl;
82       return true;
83     }
84   
85     RepoInfoList repos;
86   };
87    
88   ////////////////////////////////////////////////////////////////////////////
89   
90   /**
91    * \short List of RepoInfo's from a directory
92    *
93    * Goes trough every file in a directory and adds all
94    * RepoInfo's contained in that file.
95    *
96    * \param file pathname of the file to read.
97    */
98   static std::list<RepoInfo> repositories_in_path( const Pathname &dir )
99   {
100     MIL << " " << dir << endl;
101     RepoCollector collector;
102     std::list<RepoInfo> repos;
103     list<Pathname> entries;
104     if ( filesystem::readdir( entries, Pathname(dir), false ) != 0 )
105       ZYPP_THROW(Exception("failed to read directory"));
106     
107     for ( list<Pathname>::const_iterator it = entries.begin(); it != entries.end(); ++it )
108     {
109       Pathname file = *it;
110       parser::RepoFileReader parser( file, bind( &RepoCollector::collect, &collector, _1 ) );
111
112       //std::copy( collector.repos.begin(), collector.repos.end(), std::back_inserter(repos));
113       //MIL << "ok" << endl;
114     }
115     return collector.repos;
116   }
117   
118   ////////////////////////////////////////////////////////////////////////////
119   
120   static void assert_alias( const RepoInfo &info )
121   {
122     if (info.alias().empty())
123         ZYPP_THROW(RepoNoAliasException());
124   }
125   
126   ////////////////////////////////////////////////////////////////////////////
127   
128   static void assert_urls( const RepoInfo &info )
129   {
130     if (info.urls().empty())
131         ZYPP_THROW(RepoNoUrlException());
132   }
133   
134   ////////////////////////////////////////////////////////////////////////////
135   
136   /**
137    * \short Calculates the raw cache path for a repository
138    */
139   static Pathname rawcache_path_for_repoinfo( const RepoManagerOptions &opt, const RepoInfo &info )
140   {
141     assert_alias(info);
142     return opt.repoRawCachePath + info.alias();
143   }
144
145   ///////////////////////////////////////////////////////////////////
146   //
147   //    CLASS NAME : RepoManager::Impl
148   //
149   ///////////////////////////////////////////////////////////////////
150   
151   /**
152    * \short RepoManager implementation.
153    */
154   struct RepoManager::Impl
155   {
156     Impl( const RepoManagerOptions &opt )
157       : options(opt)
158     {
159     
160     }
161     
162     Impl()
163     {
164     
165     }
166     
167     RepoManagerOptions options;
168     
169   public:
170     /** Offer default Impl. */
171     static shared_ptr<Impl> nullimpl()
172     {
173       static shared_ptr<Impl> _nullimpl( new Impl );
174       return _nullimpl;
175     }
176
177   private:
178     friend Impl * rwcowClone<Impl>( const Impl * rhs );
179     /** clone for RWCOW_pointer */
180     Impl * clone() const
181     { return new Impl( *this ); }
182   };
183   ///////////////////////////////////////////////////////////////////
184
185   /** \relates RepoManager::Impl Stream output */
186   inline std::ostream & operator<<( std::ostream & str, const RepoManager::Impl & obj )
187   {
188     return str << "RepoManager::Impl";
189   }
190
191   ///////////////////////////////////////////////////////////////////
192   //
193   //    CLASS NAME : RepoManager
194   //
195   ///////////////////////////////////////////////////////////////////
196
197   RepoManager::RepoManager( const RepoManagerOptions &opt )
198   : _pimpl( new Impl(opt) )
199   {}
200
201   ////////////////////////////////////////////////////////////////////////////
202   
203   RepoManager::~RepoManager()
204   {}
205   
206   ////////////////////////////////////////////////////////////////////////////
207   
208   std::list<RepoInfo> RepoManager::knownRepositories() const
209   {
210     MIL << endl;
211     return repositories_in_path("/etc/zypp/repos.d");
212     MIL << endl;
213   }
214   
215   ////////////////////////////////////////////////////////////////////////////
216   
217   void RepoManager::refreshMetadata( const RepoInfo &info )
218   {
219     assert_alias(info);
220     assert_urls(info);
221     
222     // try urls one by one
223     for ( RepoInfo::urls_const_iterator it = info.urlsBegin(); it != info.urlsEnd(); ++it )
224     {
225       Url url(*it);
226       filesystem::TmpDir tmpdir;
227       
228       repo::RepoType repokind = info.type();
229       
230       // if the type is unknown, try probing.
231       switch ( repokind.toEnum() )
232       {
233         case RepoType::NONE_e:
234           // unknown, probe it
235           repokind = probe(*it);
236         break;
237         default:
238         break;
239       }
240       
241       switch ( repokind.toEnum() )
242       {
243         case RepoType::RPMMD_e :
244         {
245           YUMDownloader downloader( url, "/" );
246           downloader.download(tmpdir.path());
247            // no error
248         }
249         break;
250         case RepoType::YAST2_e :
251         {
252           SUSETagsDownloader downloader( url, "/" );
253           downloader.download(tmpdir.path());
254           // no error
255         }
256         break;
257         default:
258           ZYPP_THROW(RepoUnknownTypeException());
259       }
260       
261       // ok we have the metadata, now exchange
262       // the contents
263       Pathname rawpath = rawcache_path_for_repoinfo(_pimpl->options, info);
264       TmpDir oldmetadata;
265       filesystem::assert_dir(rawpath);
266       filesystem::rename( rawpath, oldmetadata.path() );
267       // move the just downloaded there
268       filesystem::rename( tmpdir.path(), rawpath );
269       
270       // we are done.
271     }
272   }
273   
274   ////////////////////////////////////////////////////////////////////////////
275   
276   void RepoManager::cleanMetadata( const RepoInfo &info )
277   {
278     filesystem::recursive_rmdir(rawcache_path_for_repoinfo(_pimpl->options, info));
279   }
280   
281   ////////////////////////////////////////////////////////////////////////////
282   
283   void RepoManager::buildCache( const RepoInfo &info )
284   {
285     assert_alias(info);
286     Pathname rawpath = rawcache_path_for_repoinfo(_pimpl->options, info);
287     
288     cache::CacheStore store(_pimpl->options.repoCachePath);
289     
290     if ( store.isCached( info.alias() ) )
291     {
292       MIL << info.alias() << " is already cached, cleaning..." << endl;
293       data::RecordId id = store.lookupRepository(info.alias());
294       store.cleanRepository(id);
295     }
296     
297     data::RecordId id = store.lookupOrAppendRepository(info.alias());
298     
299     // do we have type?
300     repo::RepoType repokind = info.type();
301       
302       // if the type is unknown, try probing.
303       switch ( repokind.toEnum() )
304       {
305         case RepoType::NONE_e:
306           // unknown, probe the local metadata
307           repokind = probe(Url(rawpath.asString()));
308         break;
309         default:
310         break;
311       }
312       
313       switch ( repokind.toEnum() )
314       {
315         case RepoType::RPMMD_e :
316         {
317           parser::yum::RepoParser parser(id, store);
318           parser.parse(rawpath);
319            // no error
320         }
321         break;
322         case RepoType::YAST2_e :
323         {
324           parser::susetags::RepoParser parser(id, store);
325           parser.parse(rawpath);
326           // no error
327         }
328         break;
329         default:
330           ZYPP_THROW(RepoUnknownTypeException());
331       }
332       
333       MIL << "Commit cache.." << endl;
334       store.commit();
335   }
336   
337   ////////////////////////////////////////////////////////////////////////////
338   
339   repo::RepoType RepoManager::probe( const Url &url )
340   {
341     MediaSetAccess access(url);
342     if ( access.doesFileExist("/repodata/repomd.xml") )
343       return repo::RepoType::RPMMD;
344     if ( access.doesFileExist("/content") )
345       return repo::RepoType::YAST2;
346     
347     return repo::RepoType("UNKNOWN");
348   }
349   
350   ////////////////////////////////////////////////////////////////////////////
351   
352   void RepoManager::cleanCache( const RepoInfo &info )
353   {
354     cache::CacheStore store(_pimpl->options.repoCachePath);
355
356     data::RecordId id = store.lookupRepository(info.alias());
357     store.cleanRepository(id);
358     store.commit();
359   }
360   
361   ////////////////////////////////////////////////////////////////////////////
362   
363   bool RepoManager::isCached( const RepoInfo &info ) const
364   {
365     cache::CacheStore store(_pimpl->options.repoCachePath);
366     return store.isCached(info.alias());
367   }
368   
369   Repository RepoManager::createFromCache( const RepoInfo &info )
370   {
371     cache::CacheStore store(_pimpl->options.repoCachePath);
372     
373     if ( ! store.isCached( info.alias() ) )
374       ZYPP_THROW(RepoNotCachedException());
375     
376     MIL << "Repository " << info.alias() << " is cached" << endl;
377     
378     data::RecordId id = store.lookupRepository(info.alias());
379     repo::cached::RepoImpl::Ptr repoimpl =
380         new repo::cached::RepoImpl( info, _pimpl->options.repoCachePath, id );
381     // read the resolvables from cache
382     repoimpl->createResolvables();
383     return Repository(repoimpl);
384   }
385  
386   ////////////////////////////////////////////////////////////////////////////
387   
388   void RepoManager::addRepository( const RepoInfo &info )
389   {
390   
391   }
392   
393   ////////////////////////////////////////////////////////////////////////////
394   
395   std::ostream & operator<<( std::ostream & str, const RepoManager & obj )
396   {
397     return str << *obj._pimpl;
398   }
399
400   /////////////////////////////////////////////////////////////////
401 } // namespace zypp
402 ///////////////////////////////////////////////////////////////////