580c1d84f3a28a9a2596c890f288b6ab2bdf3a29
[platform/upstream/libzypp.git] / zypp / VendorAttr.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/VendorAttr.cc
10 */
11 #include <iostream>
12 #include <fstream>
13 #include <set>
14 #include <map>
15 #include <vector>
16
17 #include <zypp/base/LogTools.h>
18 #include <zypp/base/IOStream.h>
19 #include <zypp/base/StringV.h>
20
21 #include <zypp/PathInfo.h>
22 #include <zypp/VendorAttr.h>
23 #include <zypp/ZYppFactory.h>
24
25 #include <zypp/ZConfig.h>
26 #include <zypp/PathInfo.h>
27 #include <zypp/parser/IniDict.h>
28
29 #undef  ZYPP_BASE_LOGGER_LOGGROUP
30 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::VendorAttr"
31
32 ///////////////////////////////////////////////////////////////////
33 namespace zypp
34 { /////////////////////////////////////////////////////////////////
35
36   ///////////////////////////////////////////////////////////////////
37   /// \class VendorAttr::Impl
38   /// \brief VendorAttr implementation.
39   ///////////////////////////////////////////////////////////////////
40   class VendorAttr::Impl // : private base::NonCopyable
41   {
42     friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
43   public:
44     /** Ctor.
45      * bsc#1030686: The legacy default equivalence of 'suse' and 'opensuse'
46      * has been removed.
47      * bnc#812608: No prefix compare in opensuse namespace, so just create
48      * a class for 'suse*'
49      */
50     Impl()
51     { _vendorGroupMap["suse"] = ++_vendorGroupId; }
52
53   public:
54     /** Add a new equivalent vendor set. */
55     void addVendorList( VendorList && vendorList_r );
56
57     /** Return whether two vendor strings should be treated as equivalent.*/
58     bool equivalent( IdString lVendor, IdString rVendor ) const
59     { return lVendor == rVendor || vendorMatchId( lVendor ) == vendorMatchId( rVendor ); }
60
61   private:
62     using VendorGroupMap = std::map<std::string,unsigned>;
63     VendorGroupMap _vendorGroupMap;     ///< Vendor group definition. Equivalent groups share the same ID.
64     unsigned _vendorGroupId = 0;        ///< Highest group ID in use (incremented).
65
66   private:
67     typedef DefaultIntegral<unsigned,0>                         VendorMatchEntry;
68     typedef std::unordered_map<IdString, VendorMatchEntry>      VendorMatch;
69     mutable VendorMatch _vendorMatch;   ///< Cache mapping vendor strings to equivalence class ID
70     mutable unsigned _nextId = 0;       ///< Least equivalence class ID in use (decremented).
71
72     /** Reset vendor match cache if _vendorGroupMap was changed. */
73     void vendorMatchIdReset()
74     {
75       _nextId = 0;
76       _vendorMatch.clear();
77     }
78
79     /** Helper mapping a vendor string to it's eqivalence class ID.
80      *
81      * \li Return the vendor strings eqivalence class ID stored in _vendorMatch.
82      * \li If not found, assign and return the eqivalence class ID of the lowercased string.
83      * \li If not found, assign and return a new ID (look into the predefined VendorGroupMap (id>0),
84      *     otherwise create a new ID (<0)).
85      */
86     unsigned vendorMatchId( IdString vendor ) const;
87
88   private:
89     friend Impl * rwcowClone<Impl>( const Impl * rhs );
90     /** clone for RWCOW_pointer */
91     Impl * clone() const
92     { return new Impl( *this ); }
93   };
94
95   unsigned VendorAttr::Impl::vendorMatchId( IdString vendor ) const
96   {
97     VendorMatchEntry & ent { _vendorMatch[vendor] };
98     if ( ! ent )
99     {
100       IdString lcvendor { str::toLower( vendor.asString() ) };
101       VendorMatchEntry & lcent( _vendorMatch[lcvendor] );
102       if ( ! lcent )
103       {
104         // Cache miss - check whether it belongs to a vendor group.
105         // Otherwise assign a new class ID to it.
106         unsigned myid = 0;
107
108         // bnc#812608: no prefix compare in opensuse namespace
109         if ( str::hasPrefix( lcvendor.c_str(), "opensuse" ) )
110         {
111           if ( auto it = _vendorGroupMap.find( lcvendor.c_str() ); it != _vendorGroupMap.end() )
112             myid = it->second;
113         }
114         else
115         {
116           // Compare this entry with the global vendor map.
117           // Reversed to get the longest prefix.
118           for ( VendorGroupMap::const_reverse_iterator it = _vendorGroupMap.rbegin(); it != _vendorGroupMap.rend(); ++it )
119           {
120             if ( str::hasPrefix( lcvendor.c_str(), it->first ) ) {
121               myid = it->second;
122               break; // found
123             }
124           }
125         }
126
127         if ( ! myid )
128           myid = --_nextId; // get a new class ID
129
130         ent = lcent = myid; // remember the new DI
131       }
132       else
133         ent = lcent; // take the ID from the lowercased vendor string
134     }
135     return ent;
136   }
137
138   void VendorAttr::Impl::addVendorList( VendorList && vendorList_r )
139   {
140     // Will add a new equivalence group unless we merge with existing groups.
141     unsigned targetId = _vendorGroupId + 1;
142
143     // (!) Convert the group strings in place to lowercase before adding/checking.
144     // Extend/join already existing groups if they are referenced.
145     for ( std::string & vendor : vendorList_r )
146     {
147       vendor = str::toLower( std::move(vendor) );
148
149       if ( _vendorGroupMap.count( vendor ) )
150       {
151         unsigned joinId = _vendorGroupMap[vendor];
152         if ( targetId == _vendorGroupId + 1 ) {
153           targetId = joinId;    // will extend the existing group
154         }
155         else if ( targetId != joinId ) {
156           // yet another existing group -> join it into the target group
157           for ( auto & el : _vendorGroupMap ) {
158             if ( el.second == joinId )
159               el.second = targetId;
160           }
161         }
162         vendor.clear(); // no need to add it later
163       }
164     }
165
166     // Now add the new entries
167     for ( std::string & vendor : vendorList_r ) {
168       if ( ! vendor.empty() )
169         _vendorGroupMap[vendor] = targetId;
170     }
171
172     if ( targetId == _vendorGroupId + 1 )
173       ++_vendorGroupId;
174
175     // invalidate any match cache
176     vendorMatchIdReset();
177   }
178
179   /** \relates VendorAttr::Impl Stream output */
180   inline std::ostream & operator<<( std::ostream & str, const VendorAttr::Impl & obj )
181   {
182     str << "Equivalent vendors:";
183     for( const auto & p : obj._vendorGroupMap ) {
184       str << endl << "   [" << p.second << "] " << p.first;
185     }
186     return str;
187   }
188
189   ///////////////////////////////////////////////////////////////////
190   //
191   //    CLASS NAME : VendorAttr
192   //
193   ///////////////////////////////////////////////////////////////////
194
195   const VendorAttr & VendorAttr::instance()
196   {
197     Target_Ptr trg { getZYpp()->getTarget() };
198     return trg ? trg->vendorAttr() : noTargetInstance();
199   }
200
201   VendorAttr & VendorAttr::noTargetInstance()
202   {
203     static VendorAttr _val { ZConfig::instance().vendorPath() };
204     return _val;
205   }
206
207   VendorAttr::VendorAttr()
208   : _pimpl( new Impl )
209   {
210     MIL << "Initial: " << *this << endl;
211   }
212
213   VendorAttr::VendorAttr( const Pathname & initial_r )
214   : _pimpl( new Impl )
215   {
216     addVendorDirectory( initial_r );
217     MIL << "Initial " << initial_r << ": " << *this << endl;
218   }
219
220   VendorAttr::~VendorAttr()
221   {}
222
223   bool VendorAttr::addVendorDirectory( const Pathname & dirname_r )
224   {
225     if ( PathInfo pi { dirname_r }; ! pi.isDir() ) {
226       MIL << "Not a directory " << pi << endl;
227       return false;
228     }
229
230     filesystem::dirForEach( dirname_r, filesystem::matchNoDots(),
231                             [this]( const Pathname & dir_r, const std::string & str_r )->bool
232                             {
233                               this->addVendorFile( dir_r/str_r );
234                               return true;
235                             }
236     );
237     return true;
238   }
239
240   bool VendorAttr::addVendorFile( const Pathname & filename_r )
241   {
242     if ( PathInfo pi { filename_r }; ! pi.isFile() ) {
243       MIL << "Not a file " << pi << endl;
244       return false;
245     }
246
247     parser::IniDict dict { InputStream(filename_r) };
248     for ( const auto & el : dict.entries("main") )
249     {
250       if ( el.first == "vendors" )
251       {
252         VendorList tmp;
253         strv::split( el.second, ",", strv::Trim::trim,
254                      [&tmp]( std::string_view word ) {
255                        if ( ! word.empty() )
256                          tmp.push_back( std::string(word) );
257                      } );
258         _addVendorList( std::move(tmp) );
259         break;
260       }
261     }
262     return true;
263   }
264
265   void VendorAttr::_addVendorList( VendorList && vendorList_r )
266   { _pimpl->addVendorList( std::move(vendorList_r) ); }
267
268 #if LEGACY(1722)
269   bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
270   { return const_cast<VendorAttr*>(this)->addVendorDirectory( dirname ); }
271
272   bool VendorAttr::addVendorFile( const Pathname & filename ) const
273   { return const_cast<VendorAttr*>(this)->addVendorFile( filename ); }
274
275   void VendorAttr::_addVendorList( std::vector<std::string> & vendorList_r ) const
276   { return const_cast<VendorAttr*>(this)->_addVendorList( VendorList( vendorList_r.begin(), vendorList_r.end() ) ); }
277
278   void VendorAttr::_addVendorList( std::vector<IdString> && list_r )
279   {
280     VendorList tmp;
281     for ( const auto & el : list_r )
282       tmp.push_back( std::string(el) );
283     _addVendorList( std::move(tmp) );
284   }
285 #endif
286   //////////////////////////////////////////////////////////////////
287   // vendor equivalence:
288   //////////////////////////////////////////////////////////////////
289
290   bool VendorAttr::equivalent( IdString lVendor, IdString rVendor ) const
291   { return _pimpl->equivalent( lVendor, rVendor );}
292
293   bool VendorAttr::equivalent( const Vendor & lVendor, const Vendor & rVendor ) const
294   { return _pimpl->equivalent( IdString( lVendor ), IdString( rVendor ) ); }
295
296   bool VendorAttr::equivalent( sat::Solvable lVendor, sat::Solvable rVendor ) const
297   { return _pimpl->equivalent( lVendor.vendor(), rVendor.vendor() ); }
298
299   bool VendorAttr::equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const
300   { return _pimpl->equivalent( lVendor.satSolvable().vendor(), rVendor.satSolvable().vendor() ); }
301
302   //////////////////////////////////////////////////////////////////
303
304   std::ostream & operator<<( std::ostream & str, const VendorAttr & obj )
305   { return str << *obj._pimpl; }
306
307   /////////////////////////////////////////////////////////////////
308 } // namespace zypp
309 ///////////////////////////////////////////////////////////////////
310