Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / VendorAttr.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /*
10   File:       VendorAttr.cc
11
12   Author:     Michael Andres <ma@suse.de>
13   Maintainer: Michael Andres <ma@suse.de>
14
15   Purpose: Manage vendor attributes
16
17 /-*/
18
19 #include <iostream>
20 #include <fstream>
21 #include <set>
22 #include <map>
23 #include <vector>
24
25 #include "zypp/base/LogTools.h"
26 #include "zypp/base/IOStream.h"
27 #include "zypp/base/String.h"
28
29 #include "zypp/PathInfo.h"
30 #include "zypp/VendorAttr.h"
31 #include "zypp/ZYppFactory.h"
32
33 #include "zypp/ZConfig.h"
34 #include "zypp/PathInfo.h"
35 #include "zypp/parser/IniDict.h"
36
37 using namespace std;
38
39 #undef  ZYPP_BASE_LOGGER_LOGGROUP
40 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::VendorAttr"
41
42 ///////////////////////////////////////////////////////////////////
43 namespace zypp
44 { /////////////////////////////////////////////////////////////////
45
46   ///////////////////////////////////////////////////////////////////
47   namespace
48   { /////////////////////////////////////////////////////////////////
49
50     typedef map<Vendor,unsigned int> VendorMap;
51     VendorMap _vendorMap;
52     unsigned int vendorGroupCounter;
53
54     /////////////////////////////////////////////////////////////////
55   } // namespace
56   ///////////////////////////////////////////////////////////////////
57
58   ///////////////////////////////////////////////////////////////////
59   namespace
60   { /////////////////////////////////////////////////////////////////
61     typedef DefaultIntegral<int,0>                              VendorMatchEntry;
62     typedef std::tr1::unordered_map<IdString, VendorMatchEntry> VendorMatch;
63     int         _nextId = -1;
64     VendorMatch _vendorMatch;
65
66     /** Reset match cache if global VendorMap was changed. */
67     inline void vendorMatchIdReset()
68     {
69       _nextId = -1;
70       _vendorMatch.clear();
71     }
72
73     /**
74      * Helper mapping vendor string to eqivalence class ID.
75      *
76      * \li Return the vendor strings eqivalence class ID stored in _vendorMatch.
77      * \li If not found, assign and return the eqivalence class ID of the lowercased string.
78      * \li If not found, assign and return a new ID (look into the predefined VendorMap (id>0),
79      *     otherwise create a new ID (<0)).
80      */
81     inline unsigned vendorMatchId( IdString vendor )
82     {
83       VendorMatchEntry & ent( _vendorMatch[vendor] );
84       if ( ! ent )
85       {
86         IdString lcvendor( str::toLower( vendor.asString() ) );
87         VendorMatchEntry & lcent( _vendorMatch[lcvendor] );
88         if ( ! lcent )
89         {
90           unsigned myid = 0;
91           // bnc#812608: no pefix compare in opensuse namespace
92           static const IdString openSUSE( "opensuse" );
93           if ( lcvendor == openSUSE || ! str::hasPrefix( lcvendor.c_str(), openSUSE.c_str() ) )
94           {
95             // Compare this entry with the global vendor map.
96             // Reversed to get the longest prefix.
97             for ( VendorMap::reverse_iterator it = _vendorMap.rbegin(); it != _vendorMap.rend(); ++it )
98             {
99               if ( str::hasPrefix( lcvendor.c_str(), it->first ) )
100               {
101                 myid = it->second;
102                 break; // found
103               }
104             }
105           }
106           if ( ! myid )
107           {
108             myid = --_nextId; // get a new class ID
109           }
110           ent = lcent = myid; // remember the new DI
111         }
112         else
113         {
114           ent = lcent; // take the ID from the lowercased vendor string
115         }
116       }
117       return ent;
118     }
119     /////////////////////////////////////////////////////////////////
120   } // namespace
121   ///////////////////////////////////////////////////////////////////
122
123   const VendorAttr & VendorAttr::instance()
124   {
125       static VendorAttr _val;
126       return _val;
127   }
128
129   VendorAttr::VendorAttr ()
130   {
131       vendorGroupCounter = 1;
132       Pathname vendorPath (ZConfig::instance().vendorPath());
133       {
134         Target_Ptr trg( getZYpp()->getTarget() );
135         if ( trg )
136           vendorPath = trg->root() / vendorPath;
137       }
138       // creating entries
139       addVendorDirectory (vendorPath);
140
141       // Checking if suse,opensuse has been defined, else create entries:
142       // - if both are defined we leve them as thay are.
143       // - if only one of them is defined, we add the other to the same group.
144       // - if both are undefined they make up a new group
145       VendorMap::const_iterator suseit( _vendorMap.find("suse") );
146       VendorMap::const_iterator opensuseit( _vendorMap.find("opensuse") );
147       if ( suseit == _vendorMap.end() )
148       {
149         if ( opensuseit == _vendorMap.end() )
150         {
151           // both are undefined
152           _vendorMap["suse"] = _vendorMap["opensuse"] = ++vendorGroupCounter;
153         }
154         else
155         {
156           // add suse to opensuse
157           _vendorMap["suse"] = opensuseit->second;
158         }
159       }
160       else if ( opensuseit == _vendorMap.end() )
161       {
162         // add opensuse to suse
163         _vendorMap["opensuse"] = suseit->second;
164       }
165
166       MIL << *this << endl;
167   }
168
169   void VendorAttr::_addVendorList( VendorList & vendorList_r ) const
170   {
171     unsigned int nextId = vendorGroupCounter + 1;
172         // convert to lowercase and check if a vendor is already defined
173         // in an existing group.
174
175     for_( it, vendorList_r.begin(), vendorList_r.end() )
176     {
177       *it = str::toLower( *it );
178       if (_vendorMap.find(*it) != _vendorMap.end())
179       {
180         if (nextId != vendorGroupCounter + 1 &&
181             nextId != _vendorMap[*it])
182         {
183           // We have at least 3 groups which has to be mixed --> mix the third group to the first
184           unsigned int moveID = _vendorMap[*it];
185           for_( itMap, _vendorMap.begin(), _vendorMap.end() )
186           {
187             if (itMap->second == moveID)
188               itMap->second = nextId;
189           }
190         }
191         else
192         {
193           nextId = _vendorMap[*it];
194           WAR << "Vendor " << *it << " is already used in another vendor group. --> mixing these groups" << endl;
195         }
196       }
197     }
198         // add new entries
199     for_( it, vendorList_r.begin(), vendorList_r.end() )
200     {
201       _vendorMap[*it] = nextId;
202     }
203
204     if (nextId == vendorGroupCounter + 1)
205       ++vendorGroupCounter;
206
207     // invalidate any match cache
208     vendorMatchIdReset();
209   }
210
211   bool VendorAttr::addVendorFile( const Pathname & filename ) const
212   {
213       parser::IniDict dict;
214
215       if ( PathInfo(filename).isExist())
216       {
217           InputStream is(filename);
218           dict.read(is);
219       }
220       else
221       {
222           MIL << filename << " not found." << endl;
223           return false;
224       }
225
226       for ( parser::IniDict::section_const_iterator sit = dict.sectionsBegin();
227             sit != dict.sectionsEnd();
228             ++sit )
229       {
230           string section(*sit);
231           //MIL << section << endl;
232           for ( parser::IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
233                 it != dict.entriesEnd(*sit);
234                 ++it )
235           {
236               string entry(it->first);
237               string value(it->second);
238               if ( section == "main" )
239               {
240                   if ( entry == "vendors" )
241                   {
242                       VendorList vendorlist;
243                       str::split( value, back_inserter(vendorlist), "," );
244                       _addVendorList (vendorlist);
245                       break;
246                   }
247               }
248           }
249       }
250
251       return true;
252   }
253
254   bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
255   {
256       if ( ! PathInfo(dirname).isExist() )
257       {
258           MIL << dirname << " not found." << endl;
259           return false;
260       }
261
262       list<Pathname> filenames;
263
264       filesystem::readdir( filenames,
265                            dirname, false );
266       for (list<Pathname>::iterator it = filenames.begin();
267            it != filenames.end(); ++it) {
268           MIL << "Adding file " << *it << endl;
269           addVendorFile( *it );
270       }
271       return true;
272   }
273
274   //////////////////////////////////////////////////////////////////
275   // vendor equivalence:
276   //////////////////////////////////////////////////////////////////
277
278   bool VendorAttr::equivalent( IdString lVendor, IdString rVendor ) const
279   {
280     if ( lVendor == rVendor )
281       return true;
282     return vendorMatchId( lVendor ) == vendorMatchId( rVendor );
283   }
284
285   bool VendorAttr::equivalent( const Vendor & lVendor, const Vendor & rVendor ) const
286   { return equivalent( IdString( lVendor ), IdString( rVendor ) );
287   }
288
289   bool VendorAttr::equivalent( sat::Solvable lVendor, sat::Solvable rVendor ) const
290   { return equivalent( lVendor.vendor(), rVendor.vendor() ); }
291
292   bool VendorAttr::equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const
293   { return equivalent( lVendor.satSolvable().vendor(), rVendor.satSolvable().vendor() ); }
294
295   //////////////////////////////////////////////////////////////////
296
297   std::ostream & operator<<( std::ostream & str, const VendorAttr & /*obj*/ )
298   {
299     str << "Equivalent vendors:";
300     for_( it, _vendorMap.begin(), _vendorMap.end() )
301     {
302       str << endl << "   [" << it->second << "] " << it->first;
303     }
304     return str;
305   }
306
307   /////////////////////////////////////////////////////////////////
308 } // namespace zypp
309 ///////////////////////////////////////////////////////////////////
310