- Create the cache directly from the schema (installed) file.
[platform/upstream/libzypp.git] / zypp / SourceFactory.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/SourceFactory.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Exception.h"
16 #include "zypp/base/String.h"
17
18 #include "zypp/SourceFactory.h"
19 #include "zypp/source/Builtin.h"
20 #include "zypp/media/MediaAccess.h"
21 #include "zypp/ZYppCallbacks.h"
22
23 using std::endl;
24 using namespace zypp::source;
25
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 { /////////////////////////////////////////////////////////////////
29
30   static media::MediaManager & media_mgr()
31   {
32           static media::MediaManager _v;
33           return _v;
34   }
35
36   ///////////////////////////////////////////////////////////////////
37   //
38   //    CLASS NAME : SourceFactory::Impl
39   //
40   /** SourceFactory implementation. */
41   struct SourceFactory::Impl
42   {
43     /** Try to create a \a _SourceImpl kind of Source.
44      * \throw EXCEPTION if creation fails
45     */
46     template<class _SourceImpl>
47       static Source_Ref::Impl_Ptr createSourceImpl( const media::MediaId & media_r,
48                                                     const SourceInfo &context )
49       {
50         Source_Ref::Impl_Ptr impl( new _SourceImpl );
51         // note, base_source is a tribool, if indeterminate we fallback to false
52         //MIL << "Going to call factory ctor:" << endl;
53         //MIL << context << endl;
54         impl->factoryCtor( media_r, context.path(), context.alias(), context.cacheDir(), context.baseSource(), context.autorefresh() );
55         return impl;
56       }
57   };
58   ///////////////////////////////////////////////////////////////////
59
60   ///////////////////////////////////////////////////////////////////
61   //
62   //    CLASS NAME : SourceFactory
63   //
64   ///////////////////////////////////////////////////////////////////
65
66   ///////////////////////////////////////////////////////////////////
67   //
68   //    METHOD NAME : SourceFactory::SourceFactory
69   //    METHOD TYPE : Ctor
70   //
71   SourceFactory::SourceFactory()
72   {}
73
74   ///////////////////////////////////////////////////////////////////
75   //
76   //    METHOD NAME : SourceFactory::~SourceFactory
77   //    METHOD TYPE : Dtor
78   //
79   SourceFactory::~SourceFactory()
80   {}
81
82   ///////////////////////////////////////////////////////////////////
83   //
84   //    METHOD NAME : SourceFactory::createFrom
85   //    METHOD TYPE : Source
86   //
87   Source_Ref SourceFactory::createFrom( const Source_Ref::Impl_Ptr & impl_r )
88   {
89     return impl_r ? Source_Ref( impl_r ) : Source_Ref::noSource;
90   }
91
92   void SourceFactory::listProducts( const Url & url_r, ProductSet & products_r )
93   {
94     if (! url_r.isValid())
95       ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
96
97     // open the media
98     media::MediaId id = media_mgr().open(url_r);
99     media_mgr().attach(id);
100     Pathname products_file = Pathname("media.1/products");
101
102     try  {
103       media_mgr().provideFile (id, products_file);
104       products_file = media_mgr().localPath (id, products_file);
105       scanProductsFile (products_file, products_r);
106     }
107     catch ( const Exception & excpt ) {
108       ZYPP_CAUGHT(excpt);
109       MIL << "No products description found on the Url" << endl;
110     }
111
112     media_mgr().release(id);
113   }
114
115   Source_Ref SourceFactory::createFrom( const source::SourceInfo &context )
116   {
117     if ( context.type().empty() )
118       {
119         return createFrom( context.url(),
120                            context.path(),
121                            context.alias(),
122                            context.cacheDir(),
123                            context.baseSource() );
124       }
125     else
126       {
127         return createFrom( context.type(),
128                            context.url(),
129                            context.path(),
130                            context.alias(),
131                            context.cacheDir(),
132                            context.baseSource(),
133                            context.autorefresh() );
134       }
135   }
136
137   template<typename _SourceImpl>
138   static bool probeSource(const Url &url_r, const Pathname &path_r, media::MediaId id, const std::string &type, callback::SendReport<ProbeSourceReport> &report )
139   {
140       boost::function<bool()> probe = typename _SourceImpl::Prober( id, path_r );
141
142       if ( probe() )
143       {
144         report->successProbe(url_r, type);
145         return true;
146       }
147       else
148       {
149         report->failedProbe(url_r, type);
150         return false;
151       }
152     return false;
153   }
154
155   template<class _SourceImpl>
156   Source_Ref SourceFactory::createSourceImplWorkflow( media::MediaId id, const SourceInfo &context )
157   {
158       //MIL << "Trying (pre) to create source of type " << _SourceImpl::typeString() << endl;
159       callback::SendReport<SourceCreateReport> report;
160       bool retry = true;
161       while (retry)
162       {
163         report->start( context.url() );
164           try
165           {
166             MIL << "Trying to create source of type " << _SourceImpl::typeString() << endl;
167             Source_Ref::Impl_Ptr impl( Impl::createSourceImpl<_SourceImpl>( id, context ) );
168             MIL << "Created source " << impl->type() << endl;
169             report->finish( context.url(), SourceCreateReport::NO_ERROR, std::string() );
170             return Source_Ref(impl);
171           }
172           catch (const SourceUserRejectedException & excpt_r)
173           {
174             ZYPP_CAUGHT(excpt_r);
175             report->problem( context.url(), SourceCreateReport::REJECTED, "Source rejected by the user" );
176             report->finish( context.url(), SourceCreateReport::NO_ERROR, "" );
177             ZYPP_THROW(Exception( "Source Rejected: " + excpt_r.asUserString() ));
178           }
179           catch ( const SourceMetadataException & excpt_r )
180           {
181             ZYPP_CAUGHT(excpt_r);
182             report->problem( context.url(), SourceCreateReport::REJECTED, "Source metadata is invalid: " + excpt_r.asUserString() );
183             report->finish( context.url(), SourceCreateReport::REJECTED, ""  );
184             ZYPP_THROW(Exception( "Invalid Source: " + excpt_r.asUserString() ));
185           }
186           catch (const Exception & excpt_r)
187           {
188             ZYPP_CAUGHT(excpt_r);
189             if ( report->problem( context.url(), SourceCreateReport::UNKNOWN, "Unknown Error: " + excpt_r.asUserString() ) != SourceCreateReport::RETRY )
190             {
191               report->finish( context.url(), SourceCreateReport::UNKNOWN, std::string("Unknown Error: ") + excpt_r.asUserString() );
192               ZYPP_THROW(Exception( "Unknown Error: " + excpt_r.asUserString() ));
193             }
194           }
195       }
196       // never reached
197       return Source_Ref();
198   }
199
200   Source_Ref SourceFactory::createFrom( const Url & url_r, const Pathname & path_r, const std::string & alias_r, const Pathname & cache_dir_r, bool base_source )
201   {
202     if (! url_r.isValid())
203       ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
204
205 #warning if cache_dir is provided, no need to open the original url
206     // open the media
207     media::MediaId id = media_mgr().open(url_r);
208
209     // add dummy verifier
210     media_mgr().addVerifier(id, media::MediaVerifierRef(new media::NoVerifier()));
211     // attach only if initializing from media and not from cache (#153073)
212     if (cache_dir_r == "")
213     {
214       media_mgr().attach(id);
215     }
216     else
217     {
218       MIL << "Initializing from cache" << endl;
219     }
220
221     bool auto_refresh = media::MediaAccess::canBeVolatile( url_r );
222
223     SourceInfo context( url_r, path_r, alias_r, cache_dir_r, auto_refresh );
224     context.setBaseSource( base_source );
225
226     callback::SendReport<ProbeSourceReport> report;
227     bool probeYUM = false;
228     bool probeYaST = false;
229
230     report->start(url_r);
231     try
232     {
233       if ( (probeYUM = probeSource<yum::YUMSourceImpl>( url_r, path_r, id, "YUM", report )) )
234       {
235         // nothing
236       }
237       else if ( (probeYaST = probeSource<susetags::SuseTagsImpl>( url_r, path_r, id, "YaST", report )) )
238       {
239         // nohing
240       }
241       report->finish(url_r, ProbeSourceReport::NO_ERROR, "");
242
243       if ( probeYUM )
244       {
245         Source_Ref source(createSourceImplWorkflow<source::yum::YUMSourceImpl>( id, context ));
246         return source;
247       }
248       else if ( probeYaST )
249       {
250         Source_Ref source(createSourceImplWorkflow<susetags::SuseTagsImpl>( id, context ));
251         return source;
252       }
253       else
254       {
255         ZYPP_THROW( SourceUnknownTypeException("Unknown source type for " + url_r.asString() ) );
256       }
257     }
258     catch ( const Exception &e )
259     {
260       report->finish(url_r, ProbeSourceReport::IO, e.asUserString());
261       ZYPP_RETHROW(e);
262     }
263     //////////////////////////////////////////////////////////////////
264     // TRY PLAINDIR
265     //////////////////////////////////////////////////////////////////
266     //FIXME disabled
267
268     return Source_Ref(); // not reached!!
269   }
270
271   Source_Ref SourceFactory::createFrom( const std::string & type, const Url & url_r, const Pathname & path_r, const std::string & alias_r, const Pathname & cache_dir_r, bool base_source, tribool auto_refresh )
272   {
273     if (! url_r.isValid())
274       ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
275
276     //callback::SendReport<CreateSourceReport> report;
277
278     //report->startProbe (url_r);
279
280 #warning if cache_dir is provided, no need to open the original url
281     // open the media
282     media::MediaId id = media_mgr().open(url_r);
283
284     // add dummy verifier
285     media_mgr().addVerifier(id, media::MediaVerifierRef(new media::NoVerifier()));
286     // attach only if initializing from media and not from cache (#153073)
287     if (cache_dir_r == "")
288     {
289       media_mgr().attach(id);
290     }
291     else
292     {
293       MIL << "Initializing from cache" << endl;
294     }
295
296     bool calculated_autorefresh = auto_refresh;
297     // Sane default for unknown autorefresh
298     if ( auto_refresh == indeterminate )
299       calculated_autorefresh = media::MediaAccess::canBeVolatile( url_r );
300
301     //SourceInfo( url, path, alias, cache_dir, autorefresh );
302     SourceInfo context( url_r, path_r, alias_r, cache_dir_r, calculated_autorefresh );
303     context.setBaseSource( base_source );
304     context.setType( type );
305
306     try
307     {
308       Source_Ref::Impl_Ptr impl;
309
310       if( type == yum::YUMSourceImpl::typeString() )
311       {
312         MIL << "Trying the YUM source" << endl;
313         impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<yum::YUMSourceImpl>(id, context ) );
314         MIL << "YUM source created" << endl;
315       }
316       else if ( type == susetags::SuseTagsImpl::typeString() )
317       {
318         MIL << "Trying the SUSE tags source" << endl;
319         impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<susetags::SuseTagsImpl>(id, context ) );
320         MIL << "YaST source created" << endl;
321       }
322       else if ( type == PlaindirImpl::typeString() )
323       {
324         MIL << "Trying the Plaindir source" << endl;
325         impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<PlaindirImpl>(id, context ) );
326         MIL << "Plaindir source created" << endl;
327       }
328       else
329       {
330         ZYPP_THROW( Exception ("Cannot create source of unknown type '" + type + "'"));
331       }
332
333       // never reached
334       return Source_Ref(impl);
335     }
336     catch (const Exception & excpt_r)
337     {
338       ZYPP_CAUGHT(excpt_r);
339       MIL << "Creating a source of type " << type << " failed " << endl;
340       ZYPP_RETHROW(excpt_r);
341     }
342
343     return Source_Ref(); // not reached!!
344   }
345
346
347   /******************************************************************
348   **
349   **    FUNCTION NAME : operator<<
350   **    FUNCTION TYPE : std::ostream &
351   */
352   std::ostream & operator<<( std::ostream & str, const SourceFactory & obj )
353   {
354     return str << "SourceFactory";
355   }
356
357   void SourceFactory::scanProductsFile( const Pathname & file_r, ProductSet & pset_r ) const
358   {
359     std::ifstream pfile( file_r.asString().c_str() );
360     while ( pfile.good() ) {
361
362       std::string value = str::getline( pfile, str::TRIM );
363       if ( pfile.bad() ) {
364         ERR << "Error parsing " << file_r << endl;
365         ZYPP_THROW(Exception("Error parsing " + file_r.asString()));
366       }
367       if ( pfile.fail() ) {
368         break; // no data on last line
369       }
370       std::string tag = str::stripFirstWord( value, true );
371
372       if ( tag.size() ) {
373         pset_r.insert( ProductEntry( tag, value ) );
374       }
375     }
376   }
377
378
379
380   /////////////////////////////////////////////////////////////////
381 } // namespace zypp
382 ///////////////////////////////////////////////////////////////////