1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/VendorAttr.cc
17 #include <zypp/base/LogTools.h>
18 #include <zypp/base/IOStream.h>
19 #include <zypp/base/StringV.h>
21 #include <zypp/PathInfo.h>
22 #include <zypp/VendorAttr.h>
23 #include <zypp/ZYppFactory.h>
25 #include <zypp/ZConfig.h>
26 #include <zypp/PathInfo.h>
27 #include <zypp/parser/IniDict.h>
29 #undef ZYPP_BASE_LOGGER_LOGGROUP
30 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::VendorAttr"
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
36 ///////////////////////////////////////////////////////////////////
37 /// \class VendorAttr::Impl
38 /// \brief VendorAttr implementation.
39 ///////////////////////////////////////////////////////////////////
40 class VendorAttr::Impl // : private base::NonCopyable
42 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
45 * bsc#1030686: The legacy default equivalence of 'suse' and 'opensuse'
47 * bnc#812608: No prefix compare in opensuse namespace, so just create
51 { _vendorGroupMap["suse"] = ++_vendorGroupId; }
54 /** Add a new equivalent vendor set. */
55 void addVendorList( VendorList && vendorList_r );
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 ); }
61 unsigned foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
63 std::map<unsigned,VendorList> lists;
64 for( const auto & el : _vendorGroupMap )
65 lists[el.second].push_back( el.first );
68 for ( auto el : lists ) {
69 VendorList & vlist { el.second };
73 if ( fnc_r && !fnc_r( std::move(vlist) ) )
80 using VendorGroupMap = std::map<std::string,unsigned>;
81 VendorGroupMap _vendorGroupMap; ///< Vendor group definition. Equivalent groups share the same ID.
82 unsigned _vendorGroupId = 0; ///< Highest group ID in use (incremented).
85 typedef DefaultIntegral<unsigned,0> VendorMatchEntry;
86 typedef std::unordered_map<IdString, VendorMatchEntry> VendorMatch;
87 mutable VendorMatch _vendorMatch; ///< Cache mapping vendor strings to equivalence class ID
88 mutable unsigned _nextId = 0; ///< Least equivalence class ID in use (decremented).
90 /** Reset vendor match cache if _vendorGroupMap was changed. */
91 void vendorMatchIdReset()
97 /** Helper mapping a vendor string to it's eqivalence class ID.
99 * \li Return the vendor strings eqivalence class ID stored in _vendorMatch.
100 * \li If not found, assign and return the eqivalence class ID of the lowercased string.
101 * \li If not found, assign and return a new ID (look into the predefined VendorGroupMap (id>0),
102 * otherwise create a new ID (<0)).
104 unsigned vendorMatchId( IdString vendor ) const;
107 friend Impl * rwcowClone<Impl>( const Impl * rhs );
108 /** clone for RWCOW_pointer */
110 { return new Impl( *this ); }
113 unsigned VendorAttr::Impl::vendorMatchId( IdString vendor ) const
115 VendorMatchEntry & ent { _vendorMatch[vendor] };
118 IdString lcvendor { str::toLower( vendor.asString() ) };
119 VendorMatchEntry & lcent( _vendorMatch[lcvendor] );
122 // Cache miss - check whether it belongs to a vendor group.
123 // Otherwise assign a new class ID to it.
126 // bnc#812608: no prefix compare in opensuse namespace
127 if ( str::hasPrefix( lcvendor.c_str(), "opensuse" ) )
129 if ( auto it = _vendorGroupMap.find( lcvendor.c_str() ); it != _vendorGroupMap.end() )
134 // Compare this entry with the global vendor map.
135 // Reversed to get the longest prefix.
136 for ( VendorGroupMap::const_reverse_iterator it = _vendorGroupMap.rbegin(); it != _vendorGroupMap.rend(); ++it )
138 if ( str::hasPrefix( lcvendor.c_str(), it->first ) ) {
146 myid = --_nextId; // get a new class ID
148 ent = lcent = myid; // remember the new DI
151 ent = lcent; // take the ID from the lowercased vendor string
156 void VendorAttr::Impl::addVendorList( VendorList && vendorList_r )
158 // Will add a new equivalence group unless we merge with existing groups.
159 unsigned targetId = _vendorGroupId + 1;
161 // (!) Convert the group strings in place to lowercase before adding/checking.
162 // Extend/join already existing groups if they are referenced.
163 for ( std::string & vendor : vendorList_r )
165 vendor = str::toLower( std::move(vendor) );
167 if ( _vendorGroupMap.count( vendor ) )
169 unsigned joinId = _vendorGroupMap[vendor];
170 if ( targetId == _vendorGroupId + 1 ) {
171 targetId = joinId; // will extend the existing group
173 else if ( targetId != joinId ) {
174 // yet another existing group -> join it into the target group
175 for ( auto & el : _vendorGroupMap ) {
176 if ( el.second == joinId )
177 el.second = targetId;
180 vendor.clear(); // no need to add it later
184 // Now add the new entries
185 for ( std::string & vendor : vendorList_r ) {
186 if ( ! vendor.empty() )
187 _vendorGroupMap[vendor] = targetId;
190 if ( targetId == _vendorGroupId + 1 )
193 // invalidate any match cache
194 vendorMatchIdReset();
197 /** \relates VendorAttr::Impl Stream output */
198 inline std::ostream & operator<<( std::ostream & str, const VendorAttr::Impl & obj )
200 str << "Equivalent vendors:";
201 for( const auto & p : obj._vendorGroupMap ) {
202 str << endl << " [" << p.second << "] " << p.first;
207 ///////////////////////////////////////////////////////////////////
209 // CLASS NAME : VendorAttr
211 ///////////////////////////////////////////////////////////////////
213 const VendorAttr & VendorAttr::instance()
215 Target_Ptr trg { getZYpp()->getTarget() };
216 return trg ? trg->vendorAttr() : noTargetInstance();
219 VendorAttr & VendorAttr::noTargetInstance()
221 static VendorAttr _val { ZConfig::instance().vendorPath() };
225 VendorAttr::VendorAttr()
228 MIL << "Initial: " << *this << endl;
231 VendorAttr::VendorAttr( const Pathname & initial_r )
234 addVendorDirectory( initial_r );
235 MIL << "Initial " << initial_r << ": " << *this << endl;
238 VendorAttr::~VendorAttr()
241 bool VendorAttr::addVendorDirectory( const Pathname & dirname_r )
243 if ( PathInfo pi { dirname_r }; ! pi.isDir() ) {
244 MIL << "Not a directory " << pi << endl;
248 filesystem::dirForEach( dirname_r, filesystem::matchNoDots(),
249 [this]( const Pathname & dir_r, const std::string & str_r )->bool
251 this->addVendorFile( dir_r/str_r );
258 bool VendorAttr::addVendorFile( const Pathname & filename_r )
260 if ( PathInfo pi { filename_r }; ! pi.isFile() ) {
261 MIL << "Not a file " << pi << endl;
265 parser::IniDict dict { InputStream(filename_r) };
266 for ( const auto & el : dict.entries("main") )
268 if ( el.first == "vendors" )
271 strv::split( el.second, ",", strv::Trim::trim,
272 [&tmp]( std::string_view word ) {
273 if ( ! word.empty() )
274 tmp.push_back( std::string(word) );
276 _addVendorList( std::move(tmp) );
283 void VendorAttr::_addVendorList( VendorList && vendorList_r )
284 { _pimpl->addVendorList( std::move(vendorList_r) ); }
286 unsigned VendorAttr::foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
287 { return _pimpl->foreachVendorList( std::move(fnc_r) ); }
290 bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
291 { return const_cast<VendorAttr*>(this)->addVendorDirectory( dirname ); }
293 bool VendorAttr::addVendorFile( const Pathname & filename ) const
294 { return const_cast<VendorAttr*>(this)->addVendorFile( filename ); }
296 void VendorAttr::_addVendorList( std::vector<std::string> & vendorList_r ) const
297 { return const_cast<VendorAttr*>(this)->_addVendorList( VendorList( vendorList_r.begin(), vendorList_r.end() ) ); }
299 void VendorAttr::_addVendorList( std::vector<IdString> && list_r )
302 for ( const auto & el : list_r )
303 tmp.push_back( std::string(el) );
304 _addVendorList( std::move(tmp) );
307 //////////////////////////////////////////////////////////////////
308 // vendor equivalence:
309 //////////////////////////////////////////////////////////////////
311 bool VendorAttr::equivalent( IdString lVendor, IdString rVendor ) const
312 { return _pimpl->equivalent( lVendor, rVendor );}
314 bool VendorAttr::equivalent( const Vendor & lVendor, const Vendor & rVendor ) const
315 { return _pimpl->equivalent( IdString( lVendor ), IdString( rVendor ) ); }
317 bool VendorAttr::equivalent( sat::Solvable lVendor, sat::Solvable rVendor ) const
318 { return _pimpl->equivalent( lVendor.vendor(), rVendor.vendor() ); }
320 bool VendorAttr::equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const
321 { return _pimpl->equivalent( lVendor.satSolvable().vendor(), rVendor.satSolvable().vendor() ); }
323 //////////////////////////////////////////////////////////////////
325 std::ostream & operator<<( std::ostream & str, const VendorAttr & obj )
326 { return str << *obj._pimpl; }
328 /////////////////////////////////////////////////////////////////
330 ///////////////////////////////////////////////////////////////////