dont break signatures
[platform/upstream/libzypp.git] / zypp / zypp_detail / ZYppImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/zypp_detail/ZYppImpl.cc
10  *
11 */
12
13 #include <sys/utsname.h>
14 #include <unistd.h>
15 #include <iostream>
16 #include <fstream>
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/String.h"
19
20 #include "zypp/zypp_detail/ZYppImpl.h"
21 #include "zypp/detail/ResImplTraits.h"
22 #include "zypp/solver/detail/Helper.h"
23 #include "zypp/target/TargetImpl.h"
24 #include "zypp/ZYpp.h"
25 #include "zypp/NVRAD.h"
26 #include "zypp/Language.h"
27 #include "zypp/DiskUsageCounter.h"
28 #include "zypp/NameKindProxy.h"
29
30 using std::endl;
31
32 ///////////////////////////////////////////////////////////////////
33 namespace zypp
34 { /////////////////////////////////////////////////////////////////
35   ///////////////////////////////////////////////////////////////////
36   namespace zypp_detail
37   { /////////////////////////////////////////////////////////////////
38
39     inline Locale defaultTextLocale()
40     {
41       Locale ret( "en" );
42       char * envlist[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
43       for ( char ** envvar = envlist; *envvar; ++envvar )
44         {
45           char * envlang = getenv( *envvar );
46           if ( envlang )
47             {
48               std::string envstr( envlang );
49               if ( envstr != "POSIX" && envstr != "C" )
50                 {
51                   Locale lang( envlang );
52                   if ( lang != Locale::noCode )
53                     {
54                       ret = lang;
55                       break;
56                     }
57                 }
58             }
59         }
60       return ret;
61     }
62
63     ///////////////////////////////////////////////////////////////////
64     //
65     //  METHOD NAME : ZYppImpl::ZYppImpl
66     //  METHOD TYPE : Constructor
67     //
68     ZYppImpl::ZYppImpl()
69     : _textLocale( defaultTextLocale() )
70     , _pool()
71     , _sourceFeed( _pool )
72     , _target(0)
73     , _resolver( new Resolver(_pool.accessor()) )
74     , _disk_usage()
75     {
76       MIL << "defaultTextLocale: '" << _textLocale << "'" << endl;
77       
78       MIL << "initializing keyring..." << std::endl;
79       //_keyring = new KeyRing(homePath() + Pathname("/keyring/all"), homePath() + Pathname("/keyring/trusted"));
80       _keyring = new KeyRing(tmpPath());
81
82       // detect the true architecture
83       struct utsname buf;
84       if (uname (&buf) < 0) {
85         ERR << "Can't determine system architecture" << endl;
86       }
87       else {
88         _architecture = Arch( buf.machine );
89
90         MIL << "uname architecture is '" << buf.machine << "'" << endl;
91
92         // some CPUs report i686 but dont implement cx8 and cmov
93         // check for both flags in /proc/cpuinfo and downgrade
94         // to i586 if either is missing (cf bug #18885)
95
96         if (_architecture == Arch_i686)
97         {
98             std::ifstream cpuinfo ("/proc/cpuinfo");
99             if (!cpuinfo)
100             {
101                 ERR << "Cant open /proc/cpuinfo" << endl;
102             }
103             else
104             {
105                 char infoline[1024];
106                 while (cpuinfo.good())
107                 {
108                     if (!cpuinfo.getline (infoline, 1024, '\n'))
109                     {
110                         if (cpuinfo.eof())
111                             break;
112                     }
113                     if (strncmp (infoline, "flags", 5) == 0)
114                     {
115                         std::string flagsline (infoline);
116                         if ((flagsline.find( "cx8" ) == std::string::npos)
117                             || (flagsline.find( "cmov" ) == std::string::npos))
118                         {
119                             _architecture = Arch_i586;
120                         }
121                         break;
122                     } // flags found
123                 } // read proc/cpuinfo
124             } // proc/cpuinfo opened
125         } // i686 extra flags check
126
127         MIL << "System architecture is '" << _architecture << "'" << endl;
128       }
129     
130
131       
132       if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") ) 
133       {
134         Arch already_set = _architecture;
135         
136         std::string fakearch(getenv("ZYPP_TESTSUITE_FAKE_ARCH"));
137         try
138         { 
139           _architecture = Arch( fakearch );
140           MIL << "ZYPP_TESTSUITE_FAKE_ARCH: Setting fake system architecture for test purpuses (warning! commit will be disabled!) to: '" << _architecture << "'" << endl;
141         }
142         catch(...)
143         {
144           ERR << "ZYPP_TESTSUITE_FAKE_ARCH: Wrong architecture specified on env variable, using: '" << _architecture << "'" << endl;
145         }
146       }
147     }
148
149     ///////////////////////////////////////////////////////////////////
150     //
151     //  METHOD NAME : ZYppImpl::~ZYppImpl
152     //  METHOD TYPE : Destructor
153     //
154     ZYppImpl::~ZYppImpl()
155     {}
156
157     //------------------------------------------------------------------------
158     // add/remove resolvables
159
160     void ZYppImpl::addResolvables (const ResStore& store, bool installed)
161     {
162         _pool.insert(store.begin(), store.end(), installed);
163     }
164
165     void ZYppImpl::removeResolvables (const ResStore& store)
166     {
167         for (ResStore::iterator it = store.begin(); it != store.end(); ++it)
168         {
169             _pool.erase(*it);
170         }
171     }
172
173     void ZYppImpl::removeInstalledResolvables ()
174     {
175         for (ResPool::const_iterator it = pool().begin(); it != pool().end();)
176         {
177             ResPool::const_iterator next = it; ++next;
178             if (it->status().isInstalled())
179                 _pool.erase( *it );
180             it = next;
181         }
182     }
183
184     DiskUsageCounter::MountPointSet ZYppImpl::diskUsage()
185     { return _disk_usage.disk_usage(pool()); }
186
187     void ZYppImpl::setPartitions(const DiskUsageCounter::MountPointSet &mp)
188     { _disk_usage.setMountPoints(mp); }
189
190     //------------------------------------------------------------------------
191     // target
192
193     Target_Ptr ZYppImpl::target() const
194     {
195       if (! _target)
196         ZYPP_THROW(Exception("Target not initialized."));
197       return _target;
198      }
199
200     void ZYppImpl::initTarget(const Pathname & root, bool commit_only)
201     {
202       MIL << "initTarget( " << root << ", " << commit_only << ")" << endl;
203       if (_target) {
204         if (_target->root() == root) {
205             MIL << "Repeated call to initTarget()" << endl;
206             return;
207         }
208         removeInstalledResolvables( );
209       }
210       _target = new Target( root );
211       if (!commit_only)
212       {
213         _target->enableStorage( root );
214         addResolvables( _target->resolvables(), true );
215       }
216     }
217
218     void ZYppImpl::finishTarget()
219     {
220       if (_target)
221         removeInstalledResolvables();
222       _target = 0;
223     }
224
225     //------------------------------------------------------------------------
226     // commit
227
228     /** \todo Remove workflow from target, lot's of it could be done here,
229      * and target used for transact. */
230     ZYppCommitResult ZYppImpl::commit( const ZYppCommitPolicy & policy_r )
231     {
232       if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") )
233       {
234         ZYPP_THROW( Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") );
235       }
236         
237       MIL << "Attempt to commit (" << policy_r << ")" << endl;
238       if (! _target)
239         ZYPP_THROW( Exception("Target not initialized.") );
240
241       ZYppCommitResult res = _target->_pimpl->commit( pool(), policy_r );
242
243       if (! policy_r.dryRun() ) {
244         // reload new status from target
245         removeInstalledResolvables();
246         addResolvables( _target->resolvables(), true );
247       }
248
249       MIL << "Commit (" << policy_r << ") returned: "
250           << res << endl;
251       return res;
252     }
253
254
255     //------------------------------------------------------------------------
256     // locales
257
258     /** */
259     void ZYppImpl::setRequestedLocales( const LocaleSet & locales_r )
260     {
261       ResPool mpool( pool() );
262       // assert all requested are available
263       for ( LocaleSet::const_iterator it = locales_r.begin();
264             it != locales_r.end(); ++it )
265         {
266           NameKindProxy select( nameKindProxy<Language>( mpool, it->code() ) );
267           if ( select.installedEmpty() && select.availableEmpty() )
268             _pool.insert( Language::availableInstance( *it ) );
269         }
270
271       // now adjust status
272       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
273             it != mpool.byKindEnd<Language>(); ++it )
274         {
275           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
276           if ( locales_r.find( Locale( (*it)->name() ) ) != locales_r.end() )
277             {
278               // Language is requested
279               if ( select.installedEmpty() )
280                 {
281                   if ( select.availableEmpty() )
282                     {
283                       // no item ==> provide available to install
284                       _pool.insert( Language::availableInstance( Locale((*it)->name()) ) );
285                       select = nameKindProxy<Language>( mpool, (*it)->name() );
286                     }
287                   // available only ==> to install
288                   select.availableBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
289                 }
290               else
291                 {
292                   // installed ==> keep it
293                   select.installedBegin()->status().setTransactValue( ResStatus::KEEP_STATE, ResStatus::USER );
294                   if ( ! select.availableEmpty() )
295                     {
296                       // both items ==> keep
297                       select.availableBegin()->status().resetTransact( ResStatus::USER );
298                     }
299                 }
300             }
301           else
302             {
303               // Language is NOT requested
304               if ( ! select.installedEmpty() )
305                 select.installedBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
306               if ( ! select.availableEmpty() )
307                 select.availableBegin()->status().resetTransact( ResStatus::USER );
308             }
309         }
310     }
311
312     /** */
313     ZYppImpl::LocaleSet ZYppImpl::getAvailableLocales() const
314     {
315       ZYpp::LocaleSet ret;
316       ResPool mpool( pool() );
317       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
318             it != mpool.byKindEnd<Language>(); ++it )
319         {
320           if ( (*it).status().isUninstalled() ) // available!
321             ret.insert( Locale( (*it)->name() ) );
322         }
323       return ret;
324     }
325
326     /** */
327     ZYppImpl::LocaleSet ZYppImpl::getRequestedLocales() const
328     {
329       ZYpp::LocaleSet ret;
330       ResPool mpool( pool() );
331       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
332             it != mpool.byKindEnd<Language>(); ++it )
333         {
334           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
335           if ( ! select.installedEmpty()
336                && select.installedBegin()->status().getTransactValue() != ResStatus::TRANSACT )
337             ret.insert( Locale( (*it)->name() ) );
338           else if ( ! select.availableEmpty()
339                     && select.availableBegin()->status().getTransactValue() == ResStatus::TRANSACT )
340             ret.insert( Locale( (*it)->name() ) );
341         }
342       return ret;
343     }
344
345     void ZYppImpl::availableLocale( const Locale & locale_r )
346     {
347       _pool.insert( Language::availableInstance( locale_r ) );
348     }
349
350     //------------------------------------------------------------------------
351     // architecture
352
353     void ZYppImpl::setArchitecture( const Arch & arch )
354     {
355         _architecture = arch;
356         if (_resolver) _resolver->setArchitecture( arch );
357     }
358
359     //------------------------------------------------------------------------
360     // target store path
361
362     Pathname ZYppImpl::homePath() const
363     { return _home_path.empty() ? Pathname("/var/lib/zypp") : _home_path; }
364
365     void ZYppImpl::setHomePath( const Pathname & path )
366     { _home_path = path; }
367
368     Pathname ZYppImpl::tmpPath() const
369     { 
370       static TmpDir zypp_tmp_dir("/var/tmp", "zypp.");
371       return zypp_tmp_dir.path();
372     }
373     
374     /******************************************************************
375      **
376      ** FUNCTION NAME : operator<<
377      ** FUNCTION TYPE : std::ostream &
378     */
379     std::ostream & operator<<( std::ostream & str, const ZYppImpl & obj )
380     {
381       return str << "ZYppImpl";
382     }
383
384     /////////////////////////////////////////////////////////////////
385   } // namespace zypp_detail
386   ///////////////////////////////////////////////////////////////////
387   /////////////////////////////////////////////////////////////////
388 } // namespace zypp
389 ///////////////////////////////////////////////////////////////////