Decrease severity of unknown 'namespace callback' log message (bnc #484751)
[platform/upstream/libzypp.git] / zypp / sat / detail / PoolImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/sat/detail/PoolImpl.cc
10  *
11 */
12 #include <iostream>
13 #include <boost/mpl/int.hpp>
14
15 #include "zypp/base/Easy.h"
16 #include "zypp/base/LogTools.h"
17 #include "zypp/base/Gettext.h"
18 #include "zypp/base/Exception.h"
19 #include "zypp/base/Measure.h"
20 #include "zypp/base/WatchFile.h"
21 #include "zypp/base/Sysconfig.h"
22
23 #include "zypp/ZConfig.h"
24
25 #include "zypp/sat/detail/PoolImpl.h"
26 #include "zypp/sat/Pool.h"
27 #include "zypp/Capability.h"
28 #include "zypp/Locale.h"
29 #include "zypp/PoolItem.h"
30
31 #include "zypp/target/modalias/Modalias.h"
32
33 using std::endl;
34
35 #undef  ZYPP_BASE_LOGGER_LOGGROUP
36 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::satpool"
37
38 // ///////////////////////////////////////////////////////////////////
39 namespace zypp
40 { /////////////////////////////////////////////////////////////////
41   ///////////////////////////////////////////////////////////////////
42   namespace sat
43   { /////////////////////////////////////////////////////////////////
44
45     ///////////////////////////////////////////////////////////////////
46     namespace detail
47     { /////////////////////////////////////////////////////////////////
48
49       // MPL checks for satlib constants we redefine to avoid
50       // includes and defines.
51       BOOST_MPL_ASSERT_RELATION( noId,                 ==, STRID_NULL );
52       BOOST_MPL_ASSERT_RELATION( emptyId,              ==, STRID_EMPTY );
53
54       BOOST_MPL_ASSERT_RELATION( noSolvableId,         ==, ID_NULL );
55       BOOST_MPL_ASSERT_RELATION( systemSolvableId,     ==, SYSTEMSOLVABLE );
56
57       BOOST_MPL_ASSERT_RELATION( solvablePrereqMarker, ==, SOLVABLE_PREREQMARKER );
58       BOOST_MPL_ASSERT_RELATION( solvableFileMarker,   ==, SOLVABLE_FILEMARKER );
59
60       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_AND,       ==, REL_AND );
61       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR,        ==, REL_OR );
62       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH,      ==, REL_WITH );
63       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
64       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH,      ==, REL_ARCH );
65
66      /////////////////////////////////////////////////////////////////
67
68       const std::string & PoolImpl::systemRepoAlias()
69       {
70         static const std::string _val( "@System" );
71         return _val;
72       }
73
74       /////////////////////////////////////////////////////////////////
75
76       static void logSat( struct _Pool *, void *data, int type, const char *logString )
77       {
78           if ( type & (SAT_FATAL|SAT_ERROR) ) {
79             _ERR("satsolver") << logString;
80           } else if ( type & SAT_DEBUG_STATS ) {
81             _DBG("satsolver") << logString;
82           } else {
83             _MIL("satsolver") << logString;
84           }
85       }
86
87       detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
88       {
89         // lhs:    the namespace identifier, e.g. NAMESPACE:MODALIAS
90         // rhs:    the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
91         // return: 0 if not supportded
92         //         1 if supported by the system
93         //        -1  AFAIK it's also possible to return a list of solvables that support it, but don't know how.
94
95         static const detail::IdType RET_unsupported    = 0;
96         static const detail::IdType RET_systemProperty = 1;
97         switch ( lhs )
98         {
99           case NAMESPACE_LANGUAGE:
100           {
101             static IdString en( "en" );
102             const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
103             if ( locale2Solver.empty() )
104             {
105               return rhs == en.id() ? RET_systemProperty : RET_unsupported;
106             }
107             return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
108           }
109           break;
110
111           case NAMESPACE_MODALIAS:
112           {
113             // modalias strings in capability may be hexencoded because rpm does not allow
114             // ',', ' ' or other special chars.
115             return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
116                 ? RET_systemProperty
117               : RET_unsupported;
118           }
119           break;
120
121           case NAMESPACE_FILESYSTEM:
122           {
123             static const Pathname sysconfigStoragePath( "/etc/sysconfig/storage" );
124             static WatchFile      sysconfigFile( sysconfigStoragePath, WatchFile::NO_INIT );
125             static std::set<std::string> requiredFilesystems;
126             if ( sysconfigFile.hasChanged() )
127             {
128               requiredFilesystems.clear();
129               str::split( base::sysconfig::read( sysconfigStoragePath )["USED_FS_LIST"],
130                           std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
131             }
132             return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
133           }
134           break;
135
136           case NAMESPACE_PRODUCTBUDDY:
137           {
138             PoolItem pi( (Solvable(rhs)) );
139             return( pi ? pi.buddy().id() : noId );
140           }
141
142           break;
143         }
144
145         WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
146         return RET_unsupported;
147       }
148
149       ///////////////////////////////////////////////////////////////////
150       //
151       //        METHOD NAME : PoolMember::myPool
152       //        METHOD TYPE : PoolImpl
153       //
154       PoolImpl & PoolMember::myPool()
155       {
156         static PoolImpl _global;
157         return _global;
158       }
159
160       ///////////////////////////////////////////////////////////////////
161       //
162       //        METHOD NAME : PoolImpl::PoolImpl
163       //        METHOD TYPE : Ctor
164       //
165       PoolImpl::PoolImpl()
166       : _pool( ::pool_create() )
167       {
168         MIL << "Creating sat-pool." << endl;
169         if ( ! _pool )
170         {
171           ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
172         }
173         // initialialize logging
174         bool verbose = ( getenv("ZYPP_FULLLOG") || getenv("ZYPP_LIBSAT_FULLLOG") );
175         if (verbose)
176             ::pool_setdebuglevel( _pool, 2 );
177         else
178             ::pool_setdebugmask(_pool, SAT_DEBUG_JOB);
179
180         ::pool_setdebugcallback( _pool, logSat, NULL );
181
182         // set namespace callback
183         _pool->nscallback = &nsCallback;
184         _pool->nscallbackdata = (void*)this;
185       }
186
187       ///////////////////////////////////////////////////////////////////
188       //
189       //        METHOD NAME : PoolImpl::~PoolImpl
190       //        METHOD TYPE : Dtor
191       //
192       PoolImpl::~PoolImpl()
193       {
194         ::pool_free( _pool );
195       }
196
197      ///////////////////////////////////////////////////////////////////
198
199       void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 )
200       {
201         if ( a1 )
202         {
203           if      ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
204           else if ( a2 ) MIL << a1 << " " << a2 << endl;
205           else           MIL << a1 << endl;
206         }
207         _serial.setDirty();           // pool content change
208         _availableLocalesPtr.reset(); // available locales may change
209
210         // invaldate dependency/namespace related indices:
211         depSetDirty();
212       }
213
214       void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
215       {
216         if ( a1 )
217         {
218           if      ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
219           else if ( a2 ) MIL << a1 << " " << a2 << endl;
220           else           MIL << a1 << endl;
221         }
222         ::pool_freewhatprovides( _pool );
223       }
224
225       void PoolImpl::prepare() const
226       {
227         if ( _watcher.remember( _serial ) )
228         {
229           // After repo/solvable add/remove:
230           // set pool architecture
231           ::pool_setarch( _pool,  ZConfig::instance().systemArchitecture().asString().c_str() );
232         }
233         if ( ! _pool->whatprovides )
234         {
235           MIL << "pool_createwhatprovides..." << endl;
236           ::pool_addfileprovides( _pool );
237           ::pool_createwhatprovides( _pool );
238         }
239         if ( ! _pool->languages )
240         {
241           std::vector<std::string> fallbacklist;
242           for ( Locale l( ZConfig::instance().textLocale() ); l != Locale::noCode; l = l.fallback() )
243           {
244             fallbacklist.push_back( l.code() );
245           }
246           dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
247
248           std::vector<const char *> fallbacklist_cstr;
249           for_( it, fallbacklist.begin(), fallbacklist.end() )
250           {
251             fallbacklist_cstr.push_back( it->c_str() );
252           }
253           ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
254         }
255       }
256
257       ///////////////////////////////////////////////////////////////////
258
259       ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
260       {
261         setDirty(__FUNCTION__, name_r.c_str() );
262         ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
263         if ( ret && name_r == systemRepoAlias() )
264           ::pool_set_installed( _pool, ret );
265         return ret;
266       }
267
268       void PoolImpl::_deleteRepo( ::_Repo * repo_r )
269       {
270         setDirty(__FUNCTION__, repo_r->name );
271         ::repo_free( repo_r, /*reuseids*/false );
272         eraseRepoInfo( repo_r );
273       }
274
275       int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
276       {
277         setDirty(__FUNCTION__, repo_r->name );
278         int ret = ::repo_add_solv( repo_r , file_r );
279         if ( ret == 0 )
280           _postRepoAdd( repo_r );
281         return ret;
282       }
283
284       int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
285       {
286         setDirty(__FUNCTION__, repo_r->name );
287         ::repo_add_helix( repo_r , file_r, 0 ); // unfortunately void
288         _postRepoAdd( repo_r );
289         return 0;
290       }
291
292       void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
293       {
294         if ( ! isSystemRepo( repo_r ) )
295         {
296             // Filter out unwanted archs
297           std::set<detail::IdType> sysids;
298           {
299             Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
300             for_( it, sysarchs.begin(), sysarchs.end() )
301               sysids.insert( it->id() );
302
303               // unfortunately satsolver treats src/nosrc as architecture:
304             sysids.insert( ARCH_SRC );
305             sysids.insert( ARCH_NOSRC );
306           }
307
308           detail::IdType blockBegin = 0;
309           unsigned       blockSize  = 0;
310           for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
311           {
312               ::_Solvable * s( _pool->solvables + i );
313               if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
314               {
315                 // Remember an unwanted arch entry:
316                 if ( ! blockBegin )
317                   blockBegin = i;
318                 ++blockSize;
319               }
320               else if ( blockSize )
321               {
322                 // Free remembered entries
323                   ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
324                   blockBegin = blockSize = 0;
325               }
326           }
327           if ( blockSize )
328           {
329               // Free remembered entries
330               ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
331               blockBegin = blockSize = 0;
332           }
333         }
334       }
335
336       detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
337       {
338         setDirty(__FUNCTION__, repo_r->name );
339         return ::repo_add_solvable_block( repo_r, count_r );
340       }
341
342       ///////////////////////////////////////////////////////////////////
343
344       // need on demand and id based Locale
345       void _locale_hack( const LocaleSet & locales_r,
346                          std::tr1::unordered_set<IdString> & locale2Solver )
347       {
348         std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
349         for_( it, locales_r.begin(),locales_r.end() )
350         {
351           for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
352             locale2Solver.insert( IdString( l.code() ) );
353         }
354         MIL << "New Solver Locales: " << locale2Solver << endl;
355       }
356
357       void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
358       {
359         depSetDirty( "setRequestedLocales" );
360         _requestedLocales = locales_r;
361         MIL << "New RequestedLocales: " << locales_r << endl;
362         _locale_hack( _requestedLocales, _locale2Solver );
363       }
364
365       bool PoolImpl::addRequestedLocale( const Locale & locale_r )
366       {
367         if ( _requestedLocales.insert( locale_r ).second )
368         {
369           depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
370           _locale_hack( _requestedLocales, _locale2Solver );
371           return true;
372         }
373         return false;
374       }
375
376       bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
377       {
378         if ( _requestedLocales.erase( locale_r ) )
379         {
380           depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
381           _locale_hack( _requestedLocales, _locale2Solver );
382           return true;
383         }
384         return false;
385       }
386
387       static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
388       {
389         // Collect locales from any 'namespace:language(lang)' dependency
390         CapDetail detail( cap_r );
391         if ( detail.kind() == CapDetail::EXPRESSION )
392         {
393           switch ( detail.capRel() )
394           {
395             case CapDetail::CAP_AND:
396             case CapDetail::CAP_OR:
397               // expand
398               _getLocaleDeps( detail.lhs(), store_r );
399               _getLocaleDeps( detail.rhs(), store_r );
400               break;
401
402             case CapDetail::CAP_NAMESPACE:
403               if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
404               {
405                 store_r.insert( detail.rhs().id() );
406               }
407               break;
408
409             case CapDetail::REL_NONE:
410             case CapDetail::CAP_WITH:
411             case CapDetail::CAP_ARCH:
412               break; // unwanted
413           }
414         }
415       }
416
417       const LocaleSet & PoolImpl::getAvailableLocales() const
418       {
419         if ( !_availableLocalesPtr )
420         {
421           // Collect any 'namespace:language(ja)' dependencies
422           std::tr1::unordered_set<sat::detail::IdType> tmp;
423           Pool pool( Pool::instance() );
424           for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
425           {
426             Capabilities cap( it->supplements() );
427             for_( cit, cap.begin(), cap.end() )
428             {
429               _getLocaleDeps( *cit, tmp );
430             }
431           }
432 #warning immediately build LocaleSet as soon as Loale is an Id based type
433           _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
434           for_( it, tmp.begin(), tmp.end() )
435           {
436             _availableLocalesPtr->insert( Locale( IdString(*it) ) );
437           }
438         }
439         return *_availableLocalesPtr;
440       }
441
442       /////////////////////////////////////////////////////////////////
443     } // namespace detail
444     ///////////////////////////////////////////////////////////////////
445     /////////////////////////////////////////////////////////////////
446   } // namespace sat
447   ///////////////////////////////////////////////////////////////////
448   /////////////////////////////////////////////////////////////////
449 } // namespace zypp
450 ///////////////////////////////////////////////////////////////////