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             capability::ModaliasCap::constPtr 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       //return;
00143       CapSet provides;
00144       CapSet languages;
00145 
00146       FilterExtraDependency flp( to, languages );
00147 
00148       std::remove_copy_if( from[Dep::PROVIDES].begin(), from[Dep::PROVIDES].end(),
00149                            std::inserter( provides, provides.end() ),
00150                            flp );
00151       to[Dep::PROVIDES] = provides;
00152 
00153       // There are language dependencies without a triggering package (e.G. locale(de) ).
00154       // So if there is no supplement, the language will be inserted in the supplements too.
00155       // (Not only in the freshens). Bug 178721 and 240617
00156       if (languages.size() > 0
00157           && to[Dep::SUPPLEMENTS].size() == 0) {
00158           to[Dep::SUPPLEMENTS] = languages;
00159       }
00160     }
00161 
00162     void filterExtraSupplements( const Dependencies & from, Dependencies & to )
00163     {
00164       //return;
00165       CapSet supplements;
00166       CapSet dummy;
00167       to[Dep::SUPPLEMENTS].clear();
00168 
00169       FilterExtraDependency flp( to, dummy );
00170 
00171       std::remove_copy_if( from[Dep::SUPPLEMENTS].begin(), from[Dep::SUPPLEMENTS].end(),
00172                            std::inserter( supplements, supplements.end() ),
00173                            flp );
00174       to[Dep::SUPPLEMENTS].insert(supplements.begin(), supplements.end());
00175     }
00176 
00177     // rewrite dependencies from
00178     //   kernel(xxx) = yyy
00179     // to
00180     //   kernel($FLAVOR:xxx) = yyy
00181     // $flavor is determined by searching through
00182     //   PROVIDES (for kernel-$flavor, by kernel package)
00183     // or
00184     //   REQUIRES (for kernel-$flavor, by kmp package)
00185     // see bugzilla #190163
00186     //
00187 
00188     std::string findKernelFlavor( const CapSet & cset, const Dep & dep )
00189     {
00190       for ( CapSet::iterator it = cset.begin(); it != cset.end(); ++it )
00191       {
00192         // check for "kernel-" in deps
00193         // if its a requires, take it as is
00194         // if its a provides, check for non-empty edition since
00195         //   kernels provide "kernel-flavor-nongpl" (empty edition)
00196         //     and "kernel-flavor = x.y" (non-empty edition)
00197         capability::NamedCap::constPtr cap = capability::asKind<capability::NamedCap>(*it);
00198         if ( cap
00199              && cap->name().substr( 0, 7 ) == "kernel-"
00200              && ( dep == Dep::REQUIRES || cap->edition() != Edition::noedition ) )
00201         {
00202           std::string s( cap->name() );
00203           return s.erase(0,7); // erase "kernel-"
00204         }
00205       }
00206       return "";
00207     }
00208 
00209     void rewriteKernelDeps( Dependencies & deps )
00210     {
00211       // check the smaller set (requires) first
00212       Dep dep = Dep::REQUIRES;
00213       CapSet cset = deps[dep];
00214       std::string flavor( findKernelFlavor( cset, dep ) );
00215       if (flavor.empty()) {
00216         dep = Dep::PROVIDES;
00217         cset = deps[dep];
00218         flavor = findKernelFlavor( cset, dep );
00219       }
00220 
00221       if (flavor.empty())               // not a kernel / kmp package
00222         return;
00223 
00224       // flavor == kernel flavor
00225       // cset == CapSet to be rewritten (provides for kernel, requires for kmp)
00226       // dep == deps to be set in 'to'
00227 
00228       flavor.append( ":" );
00229       CapFactory factory;
00230       deps[dep].clear();
00231       for (CapSet::const_iterator it = cset.begin(); it != cset.end(); ++it) {
00232         std::string idx( it->index() );
00233         if ( idx.substr( 0, 7 ) == "kernel("            // capability is "kernel(..."
00234              && idx.find( ":" ) == std::string::npos )  //  without a colon
00235         {
00236            capability::VersionedCap::constPtr vercap = capability::asKind<capability::VersionedCap>(*it);
00237           if ( vercap )
00238               deps[dep].insert( factory.parse( vercap->refers(), idx.insert( 7, flavor ), vercap->op(), vercap->edition() ) );
00239         }
00240         else {
00241           deps[dep].insert( *it );
00242         }
00243       }
00244       return;
00245     }
00246 
00247   }
00248 
00250   //
00251   //    METHOD NAME : Resolvable::Impl::Impl
00252   //    METHOD TYPE : Ctor
00253   //
00254   Resolvable::Impl::Impl( const Kind & kind_r,
00255                           const NVRAD & nvrad_r )
00256   : _kind( kind_r )
00257   , _name( nvrad_r.name )
00258   , _edition( nvrad_r.edition )
00259   , _arch( nvrad_r.arch )
00260   , _deps( nvrad_r )
00261   {
00262     // check if we provide/supplements any extra ('locale(...)', 'modalias(...)', ...) tags
00263     //  and split them up to freshens/supplements (except for SystemResObject)
00264     if ( _kind != ResTraits<SystemResObject>::kind )
00265       {
00266         filterExtraSupplements( nvrad_r, _deps );
00267         filterExtraProvides( nvrad_r, _deps );
00268       }
00269 
00270     // remove malicious self provides
00271     CapSet::iterator it = _deps[Dep::PROVIDES].find( CapFactory().parse( _kind, _name ) );
00272       if ( it != _deps[Dep::PROVIDES].end() )
00273         {
00274           dumpOn( WAR << "Strip self provides without edition in " ) << endl;
00275           _deps[Dep::PROVIDES].erase( it );
00276         }
00277 
00278     // assert self provides
00279     _deps[Dep::PROVIDES].insert( CapFactory()
00280                                  .parse( _kind, _name, Rel::EQ, _edition ) );
00281 
00282     // Filter 'rpmlib(...)' requirements (refill from nvrad_r)
00283     filterUnwantedReq( nvrad_r[Dep::PREREQUIRES], _deps[Dep::PREREQUIRES] );
00284     filterUnwantedReq( nvrad_r[Dep::REQUIRES], _deps[Dep::REQUIRES] );
00285 
00286     // check for kernel(xxx) and rewrite them to kernel(flavor:xxx)
00287     if ( _kind == ResTraits<Package>::kind )
00288       {
00289         rewriteKernelDeps( _deps );
00290       }
00291 
00292     // assert all prerequires are in requires too
00293     _deps[Dep::REQUIRES].insert( _deps[Dep::PREREQUIRES].begin(),
00294                                  _deps[Dep::PREREQUIRES].end() );
00295 
00296     if ( _arch.empty() )
00297       dumpOn( WAR << "Has empty Arch: " ) << std::endl;
00298   }
00299 
00300   std::ostream & Resolvable::Impl::dumpOn( std::ostream & str ) const
00301   {
00302     return str << '[' << kind() << ']'
00303                << name() << '-' << edition() << '.' << arch();
00304   }
00305 
00307 } // namespace zypp

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3