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 ); }
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).
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).
72 /** Reset vendor match cache if _vendorGroupMap was changed. */
73 void vendorMatchIdReset()
79 /** Helper mapping a vendor string to it's eqivalence class ID.
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)).
86 unsigned vendorMatchId( IdString vendor ) const;
89 friend Impl * rwcowClone<Impl>( const Impl * rhs );
90 /** clone for RWCOW_pointer */
92 { return new Impl( *this ); }
95 unsigned VendorAttr::Impl::vendorMatchId( IdString vendor ) const
97 VendorMatchEntry & ent { _vendorMatch[vendor] };
100 IdString lcvendor { str::toLower( vendor.asString() ) };
101 VendorMatchEntry & lcent( _vendorMatch[lcvendor] );
104 // Cache miss - check whether it belongs to a vendor group.
105 // Otherwise assign a new class ID to it.
108 // bnc#812608: no prefix compare in opensuse namespace
109 if ( str::hasPrefix( lcvendor.c_str(), "opensuse" ) )
111 if ( auto it = _vendorGroupMap.find( lcvendor.c_str() ); it != _vendorGroupMap.end() )
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 )
120 if ( str::hasPrefix( lcvendor.c_str(), it->first ) ) {
128 myid = --_nextId; // get a new class ID
130 ent = lcent = myid; // remember the new DI
133 ent = lcent; // take the ID from the lowercased vendor string
138 void VendorAttr::Impl::addVendorList( VendorList && vendorList_r )
140 // Will add a new equivalence group unless we merge with existing groups.
141 unsigned targetId = _vendorGroupId + 1;
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 )
147 vendor = str::toLower( std::move(vendor) );
149 if ( _vendorGroupMap.count( vendor ) )
151 unsigned joinId = _vendorGroupMap[vendor];
152 if ( targetId == _vendorGroupId + 1 ) {
153 targetId = joinId; // will extend the existing group
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;
162 vendor.clear(); // no need to add it later
166 // Now add the new entries
167 for ( std::string & vendor : vendorList_r ) {
168 if ( ! vendor.empty() )
169 _vendorGroupMap[vendor] = targetId;
172 if ( targetId == _vendorGroupId + 1 )
175 // invalidate any match cache
176 vendorMatchIdReset();
179 /** \relates VendorAttr::Impl Stream output */
180 inline std::ostream & operator<<( std::ostream & str, const VendorAttr::Impl & obj )
182 str << "Equivalent vendors:";
183 for( const auto & p : obj._vendorGroupMap ) {
184 str << endl << " [" << p.second << "] " << p.first;
189 ///////////////////////////////////////////////////////////////////
191 // CLASS NAME : VendorAttr
193 ///////////////////////////////////////////////////////////////////
195 const VendorAttr & VendorAttr::instance()
197 Target_Ptr trg { getZYpp()->getTarget() };
198 return trg ? trg->vendorAttr() : noTargetInstance();
201 VendorAttr & VendorAttr::noTargetInstance()
203 static VendorAttr _val { ZConfig::instance().vendorPath() };
207 VendorAttr::VendorAttr()
210 MIL << "Initial: " << *this << endl;
213 VendorAttr::VendorAttr( const Pathname & initial_r )
216 addVendorDirectory( initial_r );
217 MIL << "Initial " << initial_r << ": " << *this << endl;
220 VendorAttr::~VendorAttr()
223 bool VendorAttr::addVendorDirectory( const Pathname & dirname_r )
225 if ( PathInfo pi { dirname_r }; ! pi.isDir() ) {
226 MIL << "Not a directory " << pi << endl;
230 filesystem::dirForEach( dirname_r, filesystem::matchNoDots(),
231 [this]( const Pathname & dir_r, const std::string & str_r )->bool
233 this->addVendorFile( dir_r/str_r );
240 bool VendorAttr::addVendorFile( const Pathname & filename_r )
242 if ( PathInfo pi { filename_r }; ! pi.isFile() ) {
243 MIL << "Not a file " << pi << endl;
247 parser::IniDict dict { InputStream(filename_r) };
248 for ( const auto & el : dict.entries("main") )
250 if ( el.first == "vendors" )
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) );
258 _addVendorList( std::move(tmp) );
265 void VendorAttr::_addVendorList( VendorList && vendorList_r )
266 { _pimpl->addVendorList( std::move(vendorList_r) ); }
269 bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
270 { return const_cast<VendorAttr*>(this)->addVendorDirectory( dirname ); }
272 bool VendorAttr::addVendorFile( const Pathname & filename ) const
273 { return const_cast<VendorAttr*>(this)->addVendorFile( filename ); }
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() ) ); }
278 void VendorAttr::_addVendorList( std::vector<IdString> && list_r )
281 for ( const auto & el : list_r )
282 tmp.push_back( std::string(el) );
283 _addVendorList( std::move(tmp) );
286 //////////////////////////////////////////////////////////////////
287 // vendor equivalence:
288 //////////////////////////////////////////////////////////////////
290 bool VendorAttr::equivalent( IdString lVendor, IdString rVendor ) const
291 { return _pimpl->equivalent( lVendor, rVendor );}
293 bool VendorAttr::equivalent( const Vendor & lVendor, const Vendor & rVendor ) const
294 { return _pimpl->equivalent( IdString( lVendor ), IdString( rVendor ) ); }
296 bool VendorAttr::equivalent( sat::Solvable lVendor, sat::Solvable rVendor ) const
297 { return _pimpl->equivalent( lVendor.vendor(), rVendor.vendor() ); }
299 bool VendorAttr::equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const
300 { return _pimpl->equivalent( lVendor.satSolvable().vendor(), rVendor.satSolvable().vendor() ); }
302 //////////////////////////////////////////////////////////////////
304 std::ostream & operator<<( std::ostream & str, const VendorAttr & obj )
305 { return str << *obj._pimpl; }
307 /////////////////////////////////////////////////////////////////
309 ///////////////////////////////////////////////////////////////////