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