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