00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <fstream>
00014 #include "zypp/base/Logger.h"
00015 #include "zypp/base/Exception.h"
00016 #include "zypp/base/String.h"
00017
00018 #include "zypp/SourceFactory.h"
00019 #include "zypp/source/Builtin.h"
00020 #include "zypp/media/MediaAccess.h"
00021 #include "zypp/ZYppCallbacks.h"
00022
00023 using std::endl;
00024 using namespace zypp::source;
00025
00027 namespace zypp
00028 {
00029
00030 media::MediaManager media_mgr;
00031
00033
00034
00035
00037 struct SourceFactory::Impl
00038 {
00042 template<class _SourceImpl>
00043 static Source_Ref::Impl_Ptr createSourceImpl( const media::MediaId & media_r,
00044 const SourceInfo &context )
00045 {
00046 Source_Ref::Impl_Ptr impl( new _SourceImpl );
00047
00048
00049
00050 impl->factoryCtor( media_r, context.path(), context.alias(), context.cacheDir(), context.baseSource(), context.autorefresh() );
00051 return impl;
00052 }
00053 };
00055
00057
00058
00059
00061
00063
00064
00065
00066
00067 SourceFactory::SourceFactory()
00068 {}
00069
00071
00072
00073
00074
00075 SourceFactory::~SourceFactory()
00076 {}
00077
00079
00080
00081
00082
00083 Source_Ref SourceFactory::createFrom( const Source_Ref::Impl_Ptr & impl_r )
00084 {
00085 return impl_r ? Source_Ref( impl_r ) : Source_Ref::noSource;
00086 }
00087
00088 void SourceFactory::listProducts( const Url & url_r, ProductSet & products_r )
00089 {
00090 if (! url_r.isValid())
00091 ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
00092
00093
00094 media::MediaId id = media_mgr.open(url_r);
00095 media_mgr.attach(id);
00096 Pathname products_file = Pathname("media.1/products");
00097
00098 try {
00099 media_mgr.provideFile (id, products_file);
00100 products_file = media_mgr.localPath (id, products_file);
00101 scanProductsFile (products_file, products_r);
00102 }
00103 catch ( const Exception & excpt ) {
00104 ZYPP_CAUGHT(excpt);
00105 MIL << "No products description found on the Url" << endl;
00106 }
00107
00108 media_mgr.release(id);
00109 }
00110
00111 Source_Ref SourceFactory::createFrom( const source::SourceInfo &context )
00112 {
00113 if ( context.type().empty() )
00114 {
00115 return createFrom( context.url(),
00116 context.path(),
00117 context.alias(),
00118 context.cacheDir(),
00119 context.baseSource() );
00120 }
00121 else
00122 {
00123 return createFrom( context.type(),
00124 context.url(),
00125 context.path(),
00126 context.alias(),
00127 context.cacheDir(),
00128 context.baseSource(),
00129 context.autorefresh() );
00130 }
00131 }
00132
00133 template<typename _SourceImpl>
00134 static bool probeSource(const Url &url_r, const Pathname &path_r, media::MediaId id, const std::string &type, callback::SendReport<ProbeSourceReport> &report )
00135 {
00136 boost::function<bool()> probe = typename _SourceImpl::Prober( id, path_r );
00137
00138 if ( probe() )
00139 {
00140 report->successProbe(url_r, type);
00141 return true;
00142 }
00143 else
00144 {
00145 report->failedProbe(url_r, type);
00146 return false;
00147 }
00148 return false;
00149 }
00150
00151 template<class _SourceImpl>
00152 Source_Ref SourceFactory::createSourceImplWorkflow( media::MediaId id, const SourceInfo &context )
00153 {
00154
00155 callback::SendReport<SourceCreateReport> report;
00156 bool retry = true;
00157 while (retry)
00158 {
00159 report->start( context.url() );
00160 try
00161 {
00162 MIL << "Trying to create source of type " << _SourceImpl::typeString() << endl;
00163 Source_Ref::Impl_Ptr impl( Impl::createSourceImpl<_SourceImpl>( id, context ) );
00164 MIL << "Created source " << impl->type() << endl;
00165 report->finish( context.url(), SourceCreateReport::NO_ERROR, std::string() );
00166 return Source_Ref(impl);
00167 }
00168 catch (const SourceUserRejectedException & excpt_r)
00169 {
00170 ZYPP_CAUGHT(excpt_r);
00171 report->problem( context.url(), SourceCreateReport::REJECTED, "Source rejected by the user" );
00172 report->finish( context.url(), SourceCreateReport::NO_ERROR, "" );
00173 ZYPP_THROW(Exception( "Source Rejected: " + excpt_r.asUserString() ));
00174 }
00175 catch ( const SourceMetadataException & excpt_r )
00176 {
00177 ZYPP_CAUGHT(excpt_r);
00178 report->problem( context.url(), SourceCreateReport::REJECTED, "Source metadata is invalid: " + excpt_r.asUserString() );
00179 report->finish( context.url(), SourceCreateReport::REJECTED, "" );
00180 ZYPP_THROW(Exception( "Invalid Source: " + excpt_r.asUserString() ));
00181 }
00182 catch (const Exception & excpt_r)
00183 {
00184 ZYPP_CAUGHT(excpt_r);
00185 if ( report->problem( context.url(), SourceCreateReport::UNKNOWN, "Unknown Error: " + excpt_r.asUserString() ) != SourceCreateReport::RETRY )
00186 {
00187 report->finish( context.url(), SourceCreateReport::UNKNOWN, std::string("Unknown Error: ") + excpt_r.asUserString() );
00188 ZYPP_THROW(Exception( "Unknown Error: " + excpt_r.asUserString() ));
00189 }
00190 }
00191 }
00192
00193 return Source_Ref();
00194 }
00195
00196 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 )
00197 {
00198 if (! url_r.isValid())
00199 ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
00200
00201 #warning if cache_dir is provided, no need to open the original url
00202
00203 media::MediaId id = media_mgr.open(url_r);
00204
00205
00206 media_mgr.addVerifier(id, media::MediaVerifierRef(new media::NoVerifier()));
00207
00208 if (cache_dir_r == "")
00209 {
00210 media_mgr.attach(id);
00211 }
00212 else
00213 {
00214 MIL << "Initializing from cache" << endl;
00215 }
00216
00217 bool auto_refresh = media::MediaAccess::canBeVolatile( url_r );
00218
00219 SourceInfo context( url_r, path_r, alias_r, cache_dir_r, auto_refresh );
00220 context.setBaseSource( base_source );
00221
00222 callback::SendReport<ProbeSourceReport> report;
00223 bool probeYUM = false;
00224 bool probeYaST = false;
00225
00226 report->start(url_r);
00227 try
00228 {
00229
00230 try {
00231 probeYUM = probeSource<yum::YUMSourceImpl>( url_r, path_r, id, "YUM", report );
00232 }
00233 catch ( const media::MediaException & e ) {
00234 ZYPP_CAUGHT(e);
00235 }
00236 if ( probeYUM )
00237 {
00238 report->finish(url_r, ProbeSourceReport::NO_ERROR, "");
00239 Source_Ref source(createSourceImplWorkflow<source::yum::YUMSourceImpl>( id, context ));
00240 return source;
00241 }
00242
00243
00244 try {
00245 probeYaST = probeSource<susetags::SuseTagsImpl>( url_r, path_r, id, "YaST", report );
00246 }
00247 catch ( const media::MediaException & e ) {
00248 ZYPP_CAUGHT(e);
00249 }
00250 if ( probeYaST )
00251 {
00252 report->finish(url_r, ProbeSourceReport::NO_ERROR, "");
00253 Source_Ref source(createSourceImplWorkflow<susetags::SuseTagsImpl>( id, context ));
00254 return source;
00255 }
00256
00257
00258 report->finish(url_r, ProbeSourceReport::NO_ERROR, "");
00259 ZYPP_THROW( SourceUnknownTypeException("Unknown source type for " + url_r.asString() ) );
00260 }
00261 catch ( const Exception &e )
00262 {
00263 report->finish(url_r, ProbeSourceReport::IO, e.asUserString());
00264 ZYPP_RETHROW(e);
00265 }
00267
00269
00270
00271 return Source_Ref();
00272 }
00273
00274 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 )
00275 {
00276 if (! url_r.isValid())
00277 ZYPP_THROW( Exception("Empty URL passed to SourceFactory") );
00278
00279
00280
00281
00282
00283 #warning if cache_dir is provided, no need to open the original url
00284
00285 media::MediaId id = media_mgr.open(url_r);
00286
00287
00288 media_mgr.addVerifier(id, media::MediaVerifierRef(new media::NoVerifier()));
00289
00290 if (cache_dir_r == "")
00291 {
00292 media_mgr.attach(id);
00293 }
00294 else
00295 {
00296 MIL << "Initializing from cache" << endl;
00297 }
00298
00299 bool calculated_autorefresh = auto_refresh;
00300
00301 if ( auto_refresh == indeterminate )
00302 calculated_autorefresh = media::MediaAccess::canBeVolatile( url_r );
00303
00304
00305 SourceInfo context( url_r, path_r, alias_r, cache_dir_r, calculated_autorefresh );
00306 context.setBaseSource( base_source );
00307 context.setType( type );
00308
00309 try
00310 {
00311 Source_Ref::Impl_Ptr impl;
00312
00313 if( type == yum::YUMSourceImpl::typeString() )
00314 {
00315 MIL << "Trying the YUM source" << endl;
00316 impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<yum::YUMSourceImpl>(id, context ) );
00317 MIL << "YUM source created" << endl;
00318 }
00319 else if ( type == susetags::SuseTagsImpl::typeString() )
00320 {
00321 MIL << "Trying the SUSE tags source" << endl;
00322 impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<susetags::SuseTagsImpl>(id, context ) );
00323 MIL << "YaST source created" << endl;
00324 }
00325 else if ( type == PlaindirImpl::typeString() )
00326 {
00327 MIL << "Trying the Plaindir source" << endl;
00328 impl = Source_Ref::Impl_Ptr( Impl::createSourceImpl<PlaindirImpl>(id, context ) );
00329 MIL << "Plaindir source created" << endl;
00330 }
00331 else
00332 {
00333 ZYPP_THROW( Exception ("Cannot create source of unknown type '" + type + "'"));
00334 }
00335
00336
00337 return Source_Ref(impl);
00338 }
00339 catch (const Exception & excpt_r)
00340 {
00341 ZYPP_CAUGHT(excpt_r);
00342 MIL << "Creating a source of type " << type << " failed " << endl;
00343 ZYPP_RETHROW(excpt_r);
00344 }
00345
00346 return Source_Ref();
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 std::ostream & operator<<( std::ostream & str, const SourceFactory & obj )
00356 {
00357 return str << "SourceFactory";
00358 }
00359
00360 void SourceFactory::scanProductsFile( const Pathname & file_r, ProductSet & pset_r ) const
00361 {
00362 std::ifstream pfile( file_r.asString().c_str() );
00363 while ( pfile.good() ) {
00364
00365 std::string value = str::getline( pfile, str::TRIM );
00366 if ( pfile.bad() ) {
00367 ERR << "Error parsing " << file_r << endl;
00368 ZYPP_THROW(Exception("Error parsing " + file_r.asString()));
00369 }
00370 if ( pfile.fail() ) {
00371 break;
00372 }
00373 std::string tag = str::stripFirstWord( value, true );
00374
00375 if ( tag.size() ) {
00376 pset_r.insert( ProductEntry( tag, value ) );
00377 }
00378 }
00379 }
00380
00381
00382
00384 }