ResolvableImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <string>
00014 #include <map>
00015 #include "zypp/base/Logger.h"
00016 
00017 #include "zypp/ZYpp.h"
00018 #include "zypp/ZYppFactory.h"
00019 
00020 #include "zypp/base/Algorithm.h"
00021 #include "zypp/base/Sysconfig.h"
00022 #include "zypp/detail/ResolvableImpl.h"
00023 #include "zypp/capability/CapabilityImpl.h"
00024 #include "zypp/capability/Capabilities.h"
00025 
00026 using std::endl;
00027 
00029 namespace zypp
00030 { 
00031 
00032   namespace
00033   {
00034     struct FilterUnwantedReq
00035     {
00036       bool operator()( const Capability & cap_r ) const
00037       {
00038         return cap_r.index().substr( 0, 7 ) == "rpmlib(";
00039       }
00040     };
00041 
00042     void filterUnwantedReq( const CapSet & from, CapSet & to )
00043     {
00044       to.clear();
00045       std::remove_copy_if( from.begin(), from.end(),
00046                            std::inserter( to, to.end() ),
00047                            FilterUnwantedReq() );
00048     }
00049   }
00050 
00051   namespace
00052   {
00053     struct FilterExtraDependency
00054     {
00055       Dependencies & deps;
00056         CapSet & languages;
00057 
00058       FilterExtraDependency( Dependencies & d , CapSet  & l)
00059           : deps( d ),
00060             languages( l )
00061       { }
00062 
00063       bool operator()( const Capability & cap_r ) const
00064       {
00065         if ( isKind<capability::ModaliasCap>(cap_r) )
00066           {
00067             // in case cap provides a packagename, inject a SUPPLEMENTS.
00068             // if modalias does not provide a packagename, default to "kernel" (#184840)
00069 
00070             intrusive_ptr<const capability::ModaliasCap> cap( capability::asKind<capability::ModaliasCap>(cap_r) );
00071             if ( cap ) {
00072               std::string pkgname( cap->pkgname() );
00073               if ( pkgname.empty() ) {
00074                 pkgname = "kernel";             // every kernel provides "kernel", so this triggers always
00075               }
00076               deps[Dep::SUPPLEMENTS].insert( CapFactory().parse( ResTraits<Package>::kind, pkgname ) );
00077               deps[Dep::FRESHENS].insert(cap_r);
00078             }
00079             return true;        // strip from original deps, we just splitted it to supplements/freshens
00080           }
00081 
00082         if ( isKind<capability::HalCap>(cap_r) )
00083           {
00084             deps[Dep::SUPPLEMENTS].insert( cap_r );
00085             return true;        // strip from provides
00086           }
00087 
00088         std::string capString = cap_r.index();
00089         
00090         if (capString.substr( 0, 11 ) == "packageand(") {
00091             // inject a supplement/freshen in order to simulate an AND dependency
00092             // Required kmp packges FOR EACH installed/to_be_installed kernel will be installed.
00093             // Bug 255011
00094             if (capString[capString.size()-1] == ')') {                 // trailing ")" given ?
00095                 CapFactory f;       
00096                 std::string andDep( capString, 11 );                    // strip "packageand("
00097                 std::string::size_type pos = andDep.find( ":" );        // colon given ?
00098                 if (pos != std::string::npos) {
00099                     deps[Dep::SUPPLEMENTS].insert( f.parse( ResTraits<Package>::kind, std::string( andDep, 0, pos ) ) );
00100                     pos++; // skip ":"
00101                     std::string depString( andDep, pos, andDep.size()-pos-1 );
00102                     deps[Dep::FRESHENS].insert( f.parse( ResTraits<Package>::kind, depString ) );                   
00103                 } else {
00104                     ERR << "wrong dependency (missing \":\") : " << capString <<endl;
00105                 }
00106             } else {
00107                 ERR << "wrong dependency (missing \")\"): " << capString <<endl;
00108             }
00109             return true;
00110         }
00111         
00112         if (capString.substr( 0, 7 ) != "locale(")
00113             return false;
00114 
00115         CapFactory f;
00116 
00117         std::string locales( capString, 7 );                    // strip "locale("
00118         std::string::size_type pos = locales.find( ":" );               // colon given ?
00119         if (pos != std::string::npos) {
00120             deps[Dep::SUPPLEMENTS].insert( f.parse( ResTraits<Package>::kind, std::string( locales, 0, pos ) ) );
00121             locales.erase( 0, pos+1 );
00122         }
00123         pos = 0;
00124         std::string::size_type next = pos;
00125         while (pos < locales.size()) {
00126             next = locales.find( ";", pos );                    // look for ; separator
00127             if (next == std::string::npos)
00128                 next = locales.size()-1;                        // none left, set next to end-1 (strip trailing ')' )
00129 
00130             std::string loc( locales, pos, next-pos );
00131             getZYpp()->availableLocale( Locale( loc ) );
00132             deps[Dep::FRESHENS].insert( f.parse( ResTraits<Language>::kind, loc ) );
00133             languages.insert( f.parse( ResTraits<Language>::kind, loc ) );
00134             pos = next + 1;
00135         }
00136         return true;
00137       }
00138     };
00139 
00140     void filterExtraProvides( const Dependencies & from, Dependencies & to )
00141     {
00142       CapSet provides;
00143       CapSet languages;
00144       
00145       FilterExtraDependency flp( to, languages );
00146 
00147       std::remove_copy_if( from[Dep::PROVIDES].begin(), from[Dep::PROVIDES].end(),
00148                            std::inserter( provides, provides.end() ),
00149                            flp );
00150       to[Dep::PROVIDES] = provides;
00151 
00152       // There are language dependencies without a triggering package (e.G. locale(de) ).
00153       // So if there is no supplement, the language will be inserted in the supplements too.
00154       // (Not only in the freshens). Bug 178721 and 240617
00155       if (languages.size() > 0
00156           && to[Dep::SUPPLEMENTS].size() == 0) {
00157           to[Dep::SUPPLEMENTS] = languages;
00158       }
00159     }
00160 
00161     void filterExtraSupplements( const Dependencies & from, Dependencies & to )
00162     {
00163       CapSet supplements;
00164       CapSet dummy;      
00165       to[Dep::SUPPLEMENTS].clear(); 
00166 
00167       FilterExtraDependency flp( to, dummy );
00168 
00169       std::remove_copy_if( from[Dep::SUPPLEMENTS].begin(), from[Dep::SUPPLEMENTS].end(),
00170                            std::inserter( supplements, supplements.end() ),
00171                            flp );
00172       to[Dep::SUPPLEMENTS].insert(supplements.begin(), supplements.end());
00173     }
00174 
00175     // rewrite dependencies from
00176     //   kernel(xxx) = yyy
00177     // to
00178     //   kernel($FLAVOR:xxx) = yyy
00179     // $flavor is determined by searching through
00180     //   PROVIDES (for kernel-$flavor, by kernel package)
00181     // or
00182     //   REQUIRES (for kernel-$flavor, by kmp package)
00183     // see bugzilla #190163
00184     //
00185 
00186     std::string findKernelFlavor( const CapSet & cset, const Dep & dep )
00187     {
00188       for (CapSet::iterator it = cset.begin(); it != cset.end(); ++it) {
00189 
00190         // check for "kernel-" in deps
00191         // if its a requires, take it as is
00192         // if its a provides, check for non-empty edition since
00193         //   kernels provide "kernel-flavor-nongpl" (empty edition)
00194         //     and "kernel-flavor = x.y" (non-empty edition)
00195 
00196         if ( it->index().substr( 0, 7 ) == "kernel-"
00197              && (dep == Dep::REQUIRES
00198                 || it->edition() != Edition::noedition ) )
00199         {
00200           return it->index().erase( 0, 7 );     // erase "kernel-"
00201         }
00202       }
00203       return "";
00204     }
00205 
00206     void rewriteKernelDeps( Dependencies & deps )
00207     {
00208       // check the smaller set (requires) first
00209       Dep dep = Dep::REQUIRES;
00210       CapSet cset = deps[dep];
00211       std::string flavor( findKernelFlavor( cset, dep ) );
00212       if (flavor.empty()) {
00213         dep = Dep::PROVIDES;
00214         cset = deps[dep];
00215         flavor = findKernelFlavor( cset, dep );
00216       }
00217 
00218       if (flavor.empty())               // not a kernel / kmp package
00219         return;
00220 
00221       // flavor == kernel flavor
00222       // cset == CapSet to be rewritten (provides for kernel, requires for kmp)
00223       // dep == deps to be set in 'to'
00224 
00225       flavor.append( ":" );
00226       CapFactory factory;
00227       deps[dep].clear();
00228       for (CapSet::iterator it = cset.begin(); it != cset.end(); ++it) {
00229         std::string idx( it->index() );
00230         if ( idx.substr( 0, 7 ) == "kernel("            // capability is "kernel(..."
00231              && idx.find( ":" ) == std::string::npos )  //  without a colon
00232         {
00233           deps[dep].insert( factory.parse( it->refers(), idx.insert( 7, flavor ), it->op(), it->edition() ) );
00234         }
00235         else {
00236           deps[dep].insert( *it );
00237         }
00238       }
00239       return;
00240     }
00241 
00242   }
00243 
00245   //
00246   //    METHOD NAME : Resolvable::Impl::Impl
00247   //    METHOD TYPE : Ctor
00248   //
00249   Resolvable::Impl::Impl( const Kind & kind_r,
00250                           const NVRAD & nvrad_r )
00251   : _kind( kind_r )
00252   , _name( nvrad_r.name )
00253   , _edition( nvrad_r.edition )
00254   , _arch( nvrad_r.arch )
00255   , _deps( nvrad_r )
00256   {
00257     // check if we provide/supplements any extra ('locale(...)', 'modalias(...)', ...) tags
00258     //  and split them up to freshens/supplements (except for SystemResObject)
00259     if ( _kind != ResTraits<SystemResObject>::kind )
00260       {
00261         filterExtraSupplements( nvrad_r, _deps );
00262         filterExtraProvides( nvrad_r, _deps );
00263       }
00264 
00265     // remove malicious self provides
00266     CapSet::iterator it = _deps[Dep::PROVIDES].find( CapFactory().parse( _kind, _name ) );
00267       if ( it != _deps[Dep::PROVIDES].end() )
00268         {
00269           dumpOn( WAR << "Strip self provides without edition in " ) << endl;
00270           _deps[Dep::PROVIDES].erase( it );
00271         }
00272 
00273     // assert self provides
00274     _deps[Dep::PROVIDES].insert( CapFactory()
00275                                  .parse( _kind, _name, Rel::EQ, _edition ) );
00276 
00277     // Filter 'rpmlib(...)' requirements (refill from nvrad_r)
00278     filterUnwantedReq( nvrad_r[Dep::PREREQUIRES], _deps[Dep::PREREQUIRES] );
00279     filterUnwantedReq( nvrad_r[Dep::REQUIRES], _deps[Dep::REQUIRES] );
00280 
00281     // check for kernel(xxx) and rewrite them to kernel(flavor:xxx)
00282     if ( _kind == ResTraits<Package>::kind )
00283       {
00284         rewriteKernelDeps( _deps );   
00285       }
00286 
00287     // assert all prerequires are in requires too
00288     _deps[Dep::REQUIRES].insert( _deps[Dep::PREREQUIRES].begin(),
00289                                  _deps[Dep::PREREQUIRES].end() );
00290 
00291     if ( _arch.empty() )
00292       dumpOn( WAR << "Has empty Arch: " ) << std::endl;
00293   }
00294 
00295   std::ostream & Resolvable::Impl::dumpOn( std::ostream & str ) const
00296   {
00297     return str << '[' << kind() << ']'
00298                << name() << '-' << edition() << '.' << arch();
00299   }
00300 
00302 } // namespace zypp

Generated on Thu Apr 24 02:24:48 2008 for zypp by  doxygen 1.4.6