libzypp  10.5.0
VendorAttr.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00009 /*
00010   File:       VendorAttr.cc
00011 
00012   Author:     Michael Andres <ma@suse.de>
00013   Maintainer: Michael Andres <ma@suse.de>
00014 
00015   Purpose: Manage vendor attributes
00016 
00017 /-*/
00018 
00019 #include <iostream>
00020 #include <fstream>
00021 #include <set>
00022 #include <map>
00023 #include <vector>
00024 
00025 #include "zypp/base/LogTools.h"
00026 #include "zypp/base/IOStream.h"
00027 #include "zypp/base/String.h"
00028 
00029 #include "zypp/PathInfo.h"
00030 #include "zypp/VendorAttr.h"
00031 #include "zypp/ZYppFactory.h"
00032 
00033 #include "zypp/ZConfig.h"
00034 #include "zypp/PathInfo.h"
00035 #include "zypp/parser/IniDict.h"
00036 
00037 using namespace std;
00038 
00039 #undef  ZYPP_BASE_LOGGER_LOGGROUP
00040 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::VendorAttr"
00041 
00043 namespace zypp
00044 { 
00045 
00047   namespace
00048   { 
00049 
00050     typedef map<Vendor,unsigned int> VendorMap;
00051     VendorMap _vendorMap;
00052     unsigned int vendorGroupCounter;
00053 
00055   } // namespace
00057 
00059   namespace
00060   { 
00061     typedef DefaultIntegral<int,0>                              VendorMatchEntry;
00062     typedef std::tr1::unordered_map<IdString, VendorMatchEntry> VendorMatch;
00063     int         _nextId = -1;
00064     VendorMatch _vendorMatch;
00065 
00067     inline void vendorMatchIdReset()
00068     {
00069       _nextId = -1;
00070       _vendorMatch.clear();
00071     }
00072 
00081     inline unsigned vendorMatchId( IdString vendor )
00082     {
00083       VendorMatchEntry & ent( _vendorMatch[vendor] );
00084       if ( ! ent )
00085       {
00086         IdString lcvendor( str::toLower( vendor.asString() ) );
00087         VendorMatchEntry & lcent( _vendorMatch[lcvendor] );
00088         if ( ! lcent )
00089         {
00090           unsigned myid = 0;
00091           // Compare this entry with the global vendor map.
00092           // Reversed to get the longes prefix.
00093           for ( VendorMap::reverse_iterator it = _vendorMap.rbegin(); it != _vendorMap.rend(); ++it )
00094           {
00095             if ( str::hasPrefix( lcvendor.c_str(), it->first ) )
00096             {
00097               myid = it->second;
00098               break; // found
00099             }
00100           }
00101           if ( ! myid )
00102           {
00103             myid = --_nextId; // get a new class ID
00104           }
00105           ent = lcent = myid; // remember the new DI
00106         }
00107         else
00108         {
00109           ent = lcent; // take the ID from the lowercased vendor string
00110         }
00111       }
00112       return ent;
00113     }
00115   } // namespace
00117 
00118   const VendorAttr & VendorAttr::instance()
00119   {
00120       static VendorAttr _val;
00121       return _val;
00122   }
00123 
00124   VendorAttr::VendorAttr ()
00125   {
00126       vendorGroupCounter = 1;
00127       Pathname vendorPath (ZConfig::instance().vendorPath());
00128       try
00129       {
00130           Target_Ptr trg( getZYpp()->target() );
00131           if ( trg )
00132               vendorPath = trg->root() / vendorPath;
00133       }
00134       catch ( ... )
00135       {
00136           // noop: Someone decided to let target() throw if the ptr is NULL ;(
00137       }
00138 
00139       // creating entries
00140       addVendorDirectory (vendorPath);
00141 
00142       // Checking if suse,opensuse has been defined, else create entries:
00143       // - if both are defined we leve them as thay are.
00144       // - if only one of them is defined, we add the other to the same group.
00145       // - if both are undefined they make up a new group
00146       VendorMap::const_iterator suseit( _vendorMap.find("suse") );
00147       VendorMap::const_iterator opensuseit( _vendorMap.find("opensuse") );
00148       if ( suseit == _vendorMap.end() )
00149       {
00150         if ( opensuseit == _vendorMap.end() )
00151         {
00152           // both are undefined
00153           _vendorMap["suse"] = _vendorMap["opensuse"] = ++vendorGroupCounter;
00154         }
00155         else
00156         {
00157           // add suse to opensuse
00158           _vendorMap["suse"] = opensuseit->second;
00159         }
00160       }
00161       else if ( opensuseit == _vendorMap.end() )
00162       {
00163         // add opensuse to suse
00164         _vendorMap["opensuse"] = suseit->second;
00165       }
00166 
00167       // Take care 'opensuse build service' gets it's own class.
00168       VendorMap::const_iterator obsit( _vendorMap.find("opensuse build service") );
00169       if ( obsit == _vendorMap.end() )
00170       {
00171         _vendorMap["opensuse build service"] = ++vendorGroupCounter;
00172       }
00173 
00174 
00175       MIL << *this << endl;
00176   }
00177 
00178   void VendorAttr::_addVendorList( VendorList & vendorList_r ) const
00179   {
00180     unsigned int nextId = vendorGroupCounter + 1;
00181         // convert to lowercase and check if a vendor is already defined
00182         // in an existing group.
00183 
00184     for_( it, vendorList_r.begin(), vendorList_r.end() )
00185     {
00186       *it = str::toLower( *it );
00187       if (_vendorMap.find(*it) != _vendorMap.end())
00188       {
00189         if (nextId != vendorGroupCounter + 1 &&
00190             nextId != _vendorMap[*it])
00191         {
00192                     // We have at least 3 groups which has to be mixed --> mix the third group to the first
00193           unsigned int moveID = _vendorMap[*it];
00194           for_( itMap, _vendorMap.begin(), _vendorMap.end() )
00195           {
00196             if (itMap->second == moveID)
00197               itMap->second = nextId;
00198           }
00199         }
00200         else
00201         {
00202           nextId = _vendorMap[*it];
00203           WAR << "Vendor " << *it << " is already used in another vendor group. --> mixing these groups" << endl;
00204         }
00205       }
00206     }
00207         // add new entries
00208     for_( it, vendorList_r.begin(), vendorList_r.end() )
00209     {
00210       _vendorMap[*it] = nextId;
00211     }
00212 
00213     if (nextId == vendorGroupCounter + 1)
00214       ++vendorGroupCounter;
00215 
00216     // invalidate any match cache
00217     vendorMatchIdReset();
00218   }
00219 
00220   bool VendorAttr::addVendorFile( const Pathname & filename ) const
00221   {
00222       parser::IniDict dict;
00223 
00224       if ( PathInfo(filename).isExist())
00225       {
00226           InputStream is(filename);
00227           dict.read(is);
00228       }
00229       else
00230       {
00231           MIL << filename << " not found." << endl;
00232           return false;
00233       }
00234 
00235       for ( parser::IniDict::section_const_iterator sit = dict.sectionsBegin();
00236             sit != dict.sectionsEnd();
00237             ++sit )
00238       {
00239           string section(*sit);
00240           //MIL << section << endl;
00241           for ( parser::IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
00242                 it != dict.entriesEnd(*sit);
00243                 ++it )
00244           {
00245               string entry(it->first);
00246               string value(it->second);
00247               if ( section == "main" )
00248               {
00249                   if ( entry == "vendors" )
00250                   {
00251                       VendorList vendorlist;
00252                       str::split( value, back_inserter(vendorlist), "," );
00253                       _addVendorList (vendorlist);
00254                       break;
00255                   }
00256               }
00257           }
00258       }
00259 
00260       return true;
00261   }
00262 
00263   bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
00264   {
00265       parser::IniDict dict;
00266 
00267       if ( PathInfo(dirname).isExist())
00268       {
00269           InputStream is(dirname);
00270           dict.read(is);
00271       }
00272       else
00273       {
00274           MIL << dirname << " not found." << endl;
00275           return false;
00276       }
00277 
00278       list<Pathname> filenames;
00279 
00280       filesystem::readdir( filenames,
00281                            dirname, false );
00282       for (list<Pathname>::iterator it = filenames.begin();
00283            it != filenames.end(); ++it) {
00284           MIL << "Adding file " << *it << endl;
00285           addVendorFile( *it );
00286       }
00287       return true;
00288   }
00289 
00291   // vendor equivalence:
00293 
00294   bool VendorAttr::equivalent( IdString lVendor, IdString rVendor ) const
00295   {
00296     if ( lVendor == rVendor )
00297       return true;
00298     return vendorMatchId( lVendor ) == vendorMatchId( rVendor );
00299   }
00300 
00301   bool VendorAttr::equivalent( const Vendor & lVendor, const Vendor & rVendor ) const
00302   { return equivalent( IdString( lVendor ), IdString( rVendor ) );
00303   }
00304 
00305   bool VendorAttr::equivalent( sat::Solvable lVendor, sat::Solvable rVendor ) const
00306   { return equivalent( lVendor.vendor(), rVendor.vendor() ); }
00307 
00308   bool VendorAttr::equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const
00309   { return equivalent( lVendor.satSolvable().vendor(), rVendor.satSolvable().vendor() ); }
00310 
00312 
00313   std::ostream & operator<<( std::ostream & str, const VendorAttr & /*obj*/ )
00314   {
00315     str << "Equivalent vendors:";
00316     for_( it, _vendorMap.begin(), _vendorMap.end() )
00317     {
00318       str << endl << "   [" << it->second << "] " << it->first;
00319     }
00320     return str;
00321   }
00322 
00324 } // namespace zypp
00326