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