- prepare for messages and scripts
[platform/upstream/libzypp.git] / zypp / target / TargetImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/target/TargetImpl.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <string>
16 #include <list>
17 #include <set>
18
19 #include <sys/types.h>
20 #include <dirent.h>
21
22 #include "zypp/base/Logger.h"
23 #include "zypp/base/Exception.h"
24 #include "zypp/base/Iterator.h"
25 #include "zypp/base/Gettext.h"
26 #include "zypp/base/IOStream.h"
27 #include "zypp/base/UserRequestException.h"
28
29 #include "zypp/ZConfig.h"
30
31 #include "zypp/PoolItem.h"
32 #include "zypp/ResObjects.h"
33 #include "zypp/Url.h"
34 #include "zypp/TmpPath.h"
35 #include "zypp/RepoStatus.h"
36 #include "zypp/ExternalProgram.h"
37 #include "zypp/Repository.h"
38
39 #include "zypp/ResFilters.h"
40 #include "zypp/target/CommitLog.h"
41 #include "zypp/target/TargetImpl.h"
42 #include "zypp/target/TargetCallbackReceiver.h"
43 #include "zypp/target/rpm/librpmDb.h"
44 #include "zypp/target/CommitPackageCache.h"
45
46 #include "zypp/pool/GetResolvablesToInsDel.h"
47 #include "zypp/solver/detail/Helper.h"
48
49 #include "zypp/repo/DeltaCandidates.h"
50 #include "zypp/repo/PackageProvider.h"
51 #include "zypp/repo/ScriptProvider.h"
52 #include "zypp/repo/SrcPackageProvider.h"
53
54 #include "zypp/sat/Pool.h"
55
56 using namespace std;
57 using namespace zypp;
58 using namespace zypp::resfilter;
59 using zypp::solver::detail::Helper;
60
61 ///////////////////////////////////////////////////////////////////
62 namespace zypp
63 { /////////////////////////////////////////////////////////////////
64   ///////////////////////////////////////////////////////////////////
65   namespace target
66   { /////////////////////////////////////////////////////////////////
67
68     ///////////////////////////////////////////////////////////////////
69     namespace
70     { /////////////////////////////////////////////////////////////////
71
72       // Execute file (passed as pi_t) as script
73       // report against report_r
74       //
75       void ExecuteScript( const Pathname & pn_r,
76                           callback::SendReport<ScriptResolvableReport> * report)
77       {
78         PathInfo pi( pn_r );
79         if ( ! pi.isFile() )
80         {
81           std::ostringstream err;
82           err << "Script is not a file: " << pi.fileType() << " " << pn_r;
83           if (report)
84             (*report)->problem( err.str() );
85           ZYPP_THROW(Exception(err.str()));
86         }
87
88         filesystem::chmod( pn_r, S_IRUSR|S_IWUSR|S_IXUSR );     // "rwx------"
89         ExternalProgram prog( pn_r.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true );
90
91         for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
92         {
93           // hmm, this depends on a ScriptResolvableReport :-(
94           if ( report
95                && ! (*report)->progress( ScriptResolvableReport::OUTPUT, output ) )
96             {
97               WAR << "User request to abort script." << endl;
98               prog.kill(); // the rest is handled by exit code evaluation.
99             }
100         }
101
102         int exitCode = prog.close();
103         if ( exitCode != 0 )
104         {
105           std::ostringstream err;
106           err << "Script failed with exit code " << exitCode;
107           if (report)
108             (*report)->problem( err.str() );
109           ZYPP_THROW(Exception(err.str()));
110         }
111         return;
112       }
113
114       // Check for (and run) update script
115       // path: directory where to look
116       // name,version,release: Script name must match 'name-version.release-' prefix
117       //
118 #warning needs to be reimplemented exception safe
119 #warning needs to take root prefix into account and execute chroot
120      void RunUpdateScript(Pathname path, std::string name, std::string version, std::string release)
121       {
122         // open the scripts directory
123
124         DIR *dir = opendir(path.asString().c_str());
125         if (!dir)
126         {
127           WAR << "Cannot access directory " << path << endl;
128           return;
129         }
130
131         // compute the name-version.release- prefix
132         std::string prefix = name + "-" + version + "-" + release + "-";
133         size_t pfx_size = prefix.length();
134         if (pfx_size > 255)
135         {
136           ERR << "Prefix size (" << pfx_size << ") larger than supported (255)" << endl;
137           pfx_size = 255;
138         }
139
140         // scan directory for match
141         const char *found = NULL;
142         struct dirent *dentry;
143         while ((dentry = readdir(dir)))
144         {
145           if (strncmp( dentry->d_name, prefix.c_str(), pfx_size) == 0) {
146             found = dentry->d_name;
147             break;
148           }
149         }
150         if (found)
151         {
152           ExecuteScript( Pathname(path / found), NULL );
153         }
154         closedir(dir);
155         return;
156       }
157
158       // Fetch and execute remote script
159       // access_r: remote access handle
160       // script_r: script (resolvable) handle
161       // do_r: true for 'do', false for 'undo'
162       //
163       void ExecuteScriptHelper( repo::RepoMediaAccess & access_r,
164                                 Script::constPtr script_r,
165                                 bool do_r )
166       {
167         MIL << "Execute script " << script_r << endl;
168         if ( ! script_r )
169         {
170           INT << "NULL Script passed." << endl;
171           return;
172         }
173
174         repo::ScriptProvider prov( access_r );
175         ManagedFile localfile = prov.provideScript( script_r, do_r );
176
177         if ( localfile->empty() )
178         {
179           DBG << "No " << (do_r?"do":"undo") << " script for " << script_r << endl;
180           return; // success
181         }
182
183         // Go...
184         callback::SendReport<ScriptResolvableReport> report;
185         report->start( script_r, localfile,
186                        (do_r ? ScriptResolvableReport::DO
187                         : ScriptResolvableReport::UNDO ) );
188
189         ExecuteScript( localfile, &report );
190         report->finish();
191
192         return;
193       }
194
195       inline void ExecuteDoScript( repo::RepoMediaAccess & access_r, const Script::constPtr & script_r )
196       {
197         ExecuteScriptHelper( access_r, script_r, true );
198       }
199
200       inline void ExecuteUndoScript( repo::RepoMediaAccess & access_r, const Script::constPtr & script_r )
201       {
202         ExecuteScriptHelper( access_r, script_r, false );
203       }
204       /////////////////////////////////////////////////////////////////
205     } // namespace
206     ///////////////////////////////////////////////////////////////////
207
208     /** Helper for PackageProvider queries during commit. */
209     struct QueryInstalledEditionHelper
210     {
211       bool operator()( const std::string & name_r,
212                        const Edition &     ed_r,
213                        const Arch &        arch_r ) const
214       {
215         rpm::librpmDb::db_const_iterator it;
216         for ( it.findByName( name_r ); *it; ++it )
217           {
218             if ( arch_r == it->tag_arch()
219                  && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
220               {
221                 return true;
222               }
223           }
224         return false;
225       }
226     };
227
228     /**
229      * \short Let the Source provide the package.
230      * \p pool_r \ref ResPool used to get candidates
231      * \p pi item to be commited
232     */
233     struct RepoProvidePackage
234     {
235       ResPool _pool;
236       repo::RepoMediaAccess &_access;
237
238       RepoProvidePackage( repo::RepoMediaAccess &access, ResPool pool_r )
239         : _pool(pool_r), _access(access)
240       {
241
242       }
243
244       ManagedFile operator()( const PoolItem & pi )
245       {
246         // Redirect PackageProvider queries for installed editions
247         // (in case of patch/delta rpm processing) to rpmDb.
248         repo::PackageProviderPolicy packageProviderPolicy;
249         packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() );
250
251         Package::constPtr p = asKind<Package>(pi.resolvable());
252
253
254         // Build a repository list for repos
255         // contributing to the pool
256         std::list<Repository> repos( _pool.knownRepositoriesBegin(), _pool.knownRepositoriesEnd() );
257         repo::DeltaCandidates deltas(repos, p->name());
258         repo::PackageProvider pkgProvider( _access, p, deltas, packageProviderPolicy );
259         return pkgProvider.providePackage();
260       }
261     };
262     ///////////////////////////////////////////////////////////////////
263
264     IMPL_PTR_TYPE(TargetImpl);
265
266     TargetImpl_Ptr TargetImpl::_nullimpl;
267
268     /** Null implementation */
269     TargetImpl_Ptr TargetImpl::nullimpl()
270     {
271       if (_nullimpl == 0)
272         _nullimpl = new TargetImpl;
273       return _nullimpl;
274     }
275
276     ///////////////////////////////////////////////////////////////////
277     //
278     //  METHOD NAME : TargetImpl::TargetImpl
279     //  METHOD TYPE : Ctor
280     //
281     TargetImpl::TargetImpl( const Pathname & root_r, bool doRebuild_r )
282     : _root( root_r )
283     , _requestedLocalesFile( home() / "RequestedLocales" )
284     , _softLocksFile( home() / "SoftLocks" )
285     , _hardLocksFile( Pathname::assertprefix( _root, ZConfig::instance().locksFile() ) )
286     {
287       _rpm.initDatabase( root_r, Pathname(), doRebuild_r );
288       MIL << "Initialized target on " << _root << endl;
289     }
290
291     ///////////////////////////////////////////////////////////////////
292     //
293     //  METHOD NAME : TargetImpl::~TargetImpl
294     //  METHOD TYPE : Dtor
295     //
296     TargetImpl::~TargetImpl()
297     {
298       _rpm.closeDatabase();
299       MIL << "Targets closed" << endl;
300     }
301
302     void TargetImpl::clearCache()
303     {
304       Pathname base = Pathname::assertprefix( _root,
305                                               ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoName() );
306       filesystem::recursive_rmdir( base );
307     }
308
309     void TargetImpl::buildCache()
310     {
311       Pathname base = Pathname::assertprefix( _root,
312                                               ZConfig::instance().repoSolvfilesPath() / sat::Pool::instance().systemRepoName() );
313       Pathname rpmsolv       = base/"solv";
314       Pathname rpmsolvcookie = base/"cookie";
315
316       bool build_rpm_solv = true;
317       // lets see if the rpm solv cache exists
318
319       RepoStatus rpmstatus(_root + "/var/lib/rpm/Name");
320       bool solvexisted = PathInfo(rpmsolv).isExist();
321       if ( solvexisted )
322       {
323         // see the status of the cache
324         PathInfo cookie( rpmsolvcookie );
325         MIL << "Read cookie: " << cookie << endl;
326         if ( cookie.isExist() )
327         {
328           RepoStatus status = RepoStatus::fromCookieFile(rpmsolvcookie);
329           // now compare it with the rpm database
330           if ( status.checksum() == rpmstatus.checksum() )
331             build_rpm_solv = false;
332           MIL << "Read cookie: " << rpmsolvcookie << " says: "
333               << (build_rpm_solv ? "outdated" : "uptodate") << endl;
334         }
335       }
336
337       if ( build_rpm_solv )
338       {
339         // Take care we unlink the solvfile on exception
340         ManagedFile guard( base, filesystem::recursive_rmdir );
341
342         // if it does not exist yet, we better create it
343         filesystem::assert_dir( base );
344
345         filesystem::TmpFile tmpsolv( filesystem::TmpFile::makeSibling( rpmsolv ) );
346         if (!tmpsolv)
347         {
348           Exception ex("Failed to cache rpm database.");
349           ex.remember(str::form(
350               "Cannot create temporary file under %s.", base.c_str()));
351           ZYPP_THROW(ex);
352         }
353
354         ostringstream cmd;
355         cmd << "rpmdb2solv";
356         if ( ! _root.empty() )
357           cmd << " -r '" << _root << "'";
358
359         if ( solvexisted )
360           cmd << " '" << rpmsolv << "'";
361
362         cmd << "  > '" << tmpsolv.path() << "'";
363
364         MIL << "Executing: " << cmd << endl;
365         ExternalProgram prog( cmd.str(), ExternalProgram::Stderr_To_Stdout );
366
367         cmd << endl;
368         for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
369           WAR << "  " << output;
370           cmd << "     " << output;
371         }
372
373         int ret = prog.close();
374         if ( ret != 0 )
375         {
376           Exception ex(str::form("Failed to cache rpm database (%d).", ret));
377           ex.remember( cmd.str() );
378           ZYPP_THROW(ex);
379         }
380
381         ret = filesystem::rename( tmpsolv, rpmsolv );
382         if ( ret != 0 )
383           ZYPP_THROW(Exception("Failed to move cache to final destination"));
384         // if this fails, don't bother throwing exceptions
385         filesystem::chmod( rpmsolv, 0644 );
386
387         rpmstatus.saveToCookieFile(rpmsolvcookie);
388
389         // We keep it.
390         guard.resetDispose();
391       }
392     }
393
394     void TargetImpl::unload()
395     {
396       Repository system( sat::Pool::instance().findSystemRepo() );
397       if ( system )
398         system.eraseFromPool();
399     }
400
401
402     void TargetImpl::load()
403     {
404       buildCache();
405
406       // now add the repos to the pool
407       sat::Pool satpool( sat::Pool::instance() );
408       Pathname rpmsolv( Pathname::assertprefix( _root,
409                         ZConfig::instance().repoSolvfilesPath() / satpool.systemRepoName() / "solv" ) );
410       MIL << "adding " << rpmsolv << " to pool(" << satpool.systemRepoName() << ")" << endl;
411
412       // Providing an empty system repo, unload any old content
413       Repository system( sat::Pool::instance().findSystemRepo() );
414       if ( system && ! system.solvablesEmpty() )
415       {
416         system.eraseFromPool(); // invalidates system
417       }
418       if ( ! system )
419       {
420         system = satpool.systemRepo();
421       }
422
423       try
424       {
425         system.addSolv( rpmsolv );
426       }
427       catch ( const Exception & exp )
428       {
429         ZYPP_CAUGHT( exp );
430         MIL << "Try to handle exception by rebuilding the solv-file" << endl;
431         clearCache();
432         buildCache();
433
434         system.addSolv( rpmsolv );
435       }
436
437       // (Re)Load the requested locales et al.
438       // If the requested locales are empty, we leave the pool untouched
439       // to avoid undoing changes the application applied. We expect this
440       // to happen on a bare metal installation only. An already existing
441       // target should be loaded before its settings are changed.
442       {
443         const LocaleSet & requestedLocales( _requestedLocalesFile.locales() );
444         if ( ! requestedLocales.empty() )
445         {
446           satpool.setRequestedLocales( requestedLocales );
447         }
448       }
449       {
450         const SoftLocksFile::Data & softLocks( _softLocksFile.data() );
451         if ( ! softLocks.empty() )
452         {
453           ResPool::instance().setAutoSoftLocks( softLocks );
454         }
455       }
456       if ( ZConfig::instance().apply_locks_file() )
457       {
458         const HardLocksFile::Data & hardLocks( _hardLocksFile.data() );
459         if ( ! hardLocks.empty() )
460         {
461           ResPool::instance().setHardLockQueries( hardLocks );
462         }
463       }
464
465
466       MIL << "Target loaded: " << system.solvablesSize() << " resolvables" << endl;
467     }
468
469     ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
470     {
471       // ----------------------------------------------------------------- //
472       // Fake outstanding YCP fix: Honour restriction to media 1
473       // at installation, but install all remaining packages if post-boot.
474       ZYppCommitPolicy policy_r( policy_rX );
475       if ( policy_r.restrictToMedia() > 1 )
476         policy_r.allMedia();
477       // ----------------------------------------------------------------- //
478
479       MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
480
481       ///////////////////////////////////////////////////////////////////
482       // Store non-package data:
483       ///////////////////////////////////////////////////////////////////
484       filesystem::assert_dir( home() );
485       // requested locales
486       _requestedLocalesFile.setLocales( pool_r.getRequestedLocales() );
487       // weak locks
488       {
489         SoftLocksFile::Data newdata;
490         pool_r.getActiveSoftLocks( newdata );
491         _softLocksFile.setData( newdata );
492       }
493       // hard locks
494       if ( ZConfig::instance().apply_locks_file() )
495       {
496         HardLocksFile::Data newdata;
497         pool_r.getHardLockQueries( newdata );
498         _hardLocksFile.setData( newdata );
499       }
500
501       ///////////////////////////////////////////////////////////////////
502       // Process packages:
503       ///////////////////////////////////////////////////////////////////
504       if ( root() == "/" && CommitLog::fname().empty() )
505       {
506         // Yes, we simply hijack /var/log/YaST2/y2logRPM
507         // until we maintain some zypp history database.
508         CommitLog::setFname( "/var/log/YaST2/y2logRPM" );
509       }
510
511       ZYppCommitResult result;
512
513       TargetImpl::PoolItemList to_uninstall;
514       TargetImpl::PoolItemList to_install;
515       TargetImpl::PoolItemList to_srcinstall;
516       {
517
518         pool::GetResolvablesToInsDel
519         collect( pool_r, policy_r.restrictToMedia() ? pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR
520                  : pool::GetResolvablesToInsDel::ORDER_BY_SOURCE );
521         MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
522         to_uninstall.swap( collect._toDelete );
523         to_install.swap( collect._toInstall );
524         to_srcinstall.swap( collect._toSrcinstall );
525       }
526
527       if ( policy_r.restrictToMedia() )
528       {
529         MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
530       }
531
532       commit (to_uninstall, policy_r, pool_r );
533
534       if (policy_r.restrictToMedia() == 0)
535       {                 // commit all
536         result._remaining = commit( to_install, policy_r, pool_r );
537         result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
538       }
539       else
540       {
541         TargetImpl::PoolItemList current_install;
542         TargetImpl::PoolItemList current_srcinstall;
543
544         // Collect until the 1st package from an unwanted media occurs.
545         // Further collection could violate install order.
546         bool hitUnwantedMedia = false;
547         for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
548         {
549           ResObject::constPtr res( it->resolvable() );
550
551           if ( hitUnwantedMedia
552                || ( res->mediaNr() && res->mediaNr() != policy_r.restrictToMedia() ) )
553           {
554             hitUnwantedMedia = true;
555             result._remaining.push_back( *it );
556           }
557           else
558           {
559             current_install.push_back( *it );
560           }
561         }
562
563         TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
564         result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
565
566         for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
567         {
568           Resolvable::constPtr res( it->resolvable() );
569           Package::constPtr pkg( asKind<Package>(res) );
570           if (pkg && policy_r.restrictToMedia() != pkg->mediaNr()) // check medianr for packages only
571           {
572             XXX << "Package " << *pkg << ", wrong media " << pkg->mediaNr() << endl;
573             result._srcremaining.push_back( *it );
574           }
575           else
576           {
577             current_srcinstall.push_back( *it );
578           }
579         }
580         bad = commit( current_srcinstall, policy_r, pool_r );
581         result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
582       }
583
584       // Try to rebuild solv file while rpm database is still in cache.
585       buildCache();
586
587       result._result = (to_install.size() - result._remaining.size());
588       MIL << "TargetImpl::commit(<pool>, " << policy_r << ") returns: " << result << endl;
589       return result;
590     }
591
592
593     TargetImpl::PoolItemList
594     TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
595                         const ZYppCommitPolicy & policy_r,
596                         const ResPool & pool_r )
597     {
598       TargetImpl::PoolItemList remaining;
599       repo::RepoMediaAccess access;
600       MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
601
602       bool abort = false;
603
604       // remember the last used source (if any)
605       Repository lastUsedRepo;
606
607       RepoProvidePackage repoProvidePackage( access, pool_r);
608       // prepare the package cache.
609       CommitPackageCache packageCache( items_r.begin(), items_r.end(),
610                                        root() / "tmp", repoProvidePackage );
611
612       for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
613       {
614         if (isKind<Package>(it->resolvable()))
615         {
616           Package::constPtr p = asKind<Package>(it->resolvable());
617           if (it->status().isToBeInstalled())
618           {
619             ManagedFile localfile;
620             try
621             {
622               localfile = packageCache.get( it );
623             }
624             catch ( const SkipRequestException &e )
625             {
626               ZYPP_CAUGHT( e );
627               WAR << "Skipping package " << p << " in commit" << endl;
628               continue;
629             }
630
631             lastUsedRepo = p->repository();                     // remember the package source
632
633 #warning Exception handling
634             // create a installation progress report proxy
635             RpmInstallPackageReceiver progress( it->resolvable() );
636             progress.connect();
637             bool success = true;
638             unsigned flags = 0;
639             // Why force and nodeps?
640             //
641             // Because zypp builds the transaction and the resolver asserts that
642             // everything is fine.
643             // We use rpm just to unpack and register the package in the database.
644             // We do this step by step, so rpm is not aware of the bigger context.
645             // So we turn off rpms internal checks, because we do it inside zypp.
646             flags |= rpm::RpmDb::RPMINST_NODEPS;
647             flags |= rpm::RpmDb::RPMINST_FORCE;
648             //
649             if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
650             if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
651             if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
652
653             try
654             {
655               progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
656               rpm().installPackage( localfile, flags );
657
658               if ( progress.aborted() )
659               {
660                 WAR << "commit aborted by the user" << endl;
661                 progress.disconnect();
662                 success = false;
663                 abort = true;
664                 break;
665               }
666             }
667             catch (Exception & excpt_r)
668             {
669               ZYPP_CAUGHT(excpt_r);
670               if ( policy_r.dryRun() )
671               {
672                 WAR << "dry run failed" << endl;
673                 progress.disconnect();
674                 break;
675               }
676               // else
677               WAR << "Install failed" << endl;
678               remaining.push_back( *it );
679               progress.disconnect();
680               success = false;
681               break;
682             }
683
684             if ( success && !policy_r.dryRun() )
685             {
686               it->status().resetTransact( ResStatus::USER );
687               // check for and run an update script
688               RunUpdateScript(ZConfig::instance().update_scriptsPath(), p->name(), p->edition().version(), p->edition().release());
689             }
690             progress.disconnect();
691           }
692           else
693           {
694             bool success = true;
695
696             RpmRemovePackageReceiver progress( it->resolvable() );
697             progress.connect();
698             unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
699             if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
700             try
701             {
702               rpm().removePackage( p, flags );
703             }
704             catch (Exception & excpt_r)
705             {
706               WAR << "removal of " << p << " failed";
707               success = false;
708               ZYPP_CAUGHT( excpt_r );
709             }
710             if (success
711                 && !policy_r.dryRun())
712             {
713               it->status().resetTransact( ResStatus::USER );
714             }
715             progress.disconnect();
716           }
717         }
718         else if (!policy_r.dryRun()) // other resolvables (non-Package)
719         {
720           if (it->status().isToBeInstalled())
721           {
722             bool success = false;
723             try
724             {
725               if (isKind<Message>(it->resolvable()))
726               {
727                 Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
728                 std::string text = m->text().asString();
729
730                 callback::SendReport<target::MessageResolvableReport> report;
731
732                 report->show( m );
733
734                 MIL << "Displaying the text '" << text << "'" << endl;
735               }
736               else if (isKind<Script>(it->resolvable()))
737               {
738                 ExecuteDoScript( access, asKind<Script>(it->resolvable()));
739               }
740               else if (!isKind<Atom>(it->resolvable())) // atoms are re-created from the patch data, no need to save them
741               {
742                 // #160792 do not just add, also remove older versions
743                 if (true) // !installOnly - only on Package?!
744                 {
745                   // this would delete the same item over and over
746                   //for (PoolItem old = Helper::findInstalledItem (pool_r, *it); old; )
747                   #warning REMOVE ALL OLD VERSIONS AND NOT JUST ONE
748                   PoolItem old = Helper::findInstalledItem (pool_r, *it);
749                   if (old)
750                   {
751                     // FIXME _storage.deleteObject(old.resolvable());
752                   }
753                 }
754                 // FIXME _storage.storeObject(it->resolvable());
755               }
756               success = true;
757             }
758             catch (Exception & excpt_r)
759             {
760               ZYPP_CAUGHT(excpt_r);
761               WAR << "Install of Resolvable from storage failed" << endl;
762             }
763             if (success)
764               it->status().resetTransact( ResStatus::USER );
765           }
766           else
767           {                                     // isToBeUninstalled
768             bool success = false;
769             try
770             {
771               if (isKind<Atom>(it->resolvable()))
772               {
773                 DBG << "Uninstalling atom - no-op" << endl;
774               }
775               else if (isKind<Message>(it->resolvable()))
776               {
777                 DBG << "Uninstalling message - no-op" << endl;
778               }
779               else if (isKind<Script>(it->resolvable()))
780               {
781                 ExecuteUndoScript( access, asKind<Script>(it->resolvable()));
782               }
783               else
784               {
785                 //FIXME _storage.deleteObject(it->resolvable());
786               }
787               success = true;
788             }
789             catch (Exception & excpt_r)
790             {
791               ZYPP_CAUGHT(excpt_r);
792               WAR << "Uninstall of Resolvable from storage failed" << endl;
793             }
794             if (success)
795               it->status().resetTransact( ResStatus::USER );
796           }
797
798         }  // other resolvables
799
800       } // for
801
802       // we're done with the commit, release the source media
803       //   In the case of a single media, end of commit means we don't need _this_
804       //   media any more.
805       //   In the case of 'commit any media', end of commit means we're completely
806       //   done and don't need the source's media anyways.
807
808       if (lastUsedRepo)
809       {         // if a source was used
810         //lastUsedRepo.release();       //  release their medias
811       }
812
813       if ( abort )
814         ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
815
816       return remaining;
817     }
818
819     rpm::RpmDb & TargetImpl::rpm()
820     {
821       return _rpm;
822     }
823
824     bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
825     {
826       return _rpm.hasFile(path_str, name_str);
827     }
828
829     /** Set the log file for target */
830     bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
831     {
832       CommitLog::setFname(path_r);
833       return true;
834     }
835
836     Date TargetImpl::timestamp() const
837     {
838       return _rpm.timestamp();
839     }
840
841     std::string TargetImpl::release() const
842     {
843       std::ifstream suseRelease( (_root / "/etc/SuSE-release").c_str() );
844       for( iostr::EachLine in( suseRelease ); in; in.next() )
845       {
846         std::string line( str::trim( *in ) );
847         if ( ! line.empty() )
848           return line;
849       }
850
851       return _("Unknown Distribution");
852     }
853
854     void TargetImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
855     {
856       // provide on local disk
857       repo::RepoMediaAccess access_r;
858       repo::SrcPackageProvider prov( access_r );
859       ManagedFile localfile = prov.provideSrcPackage( srcPackage_r );
860       // install it
861       rpm().installPackage ( localfile );
862     }
863
864     /////////////////////////////////////////////////////////////////
865   } // namespace target
866   ///////////////////////////////////////////////////////////////////
867   /////////////////////////////////////////////////////////////////
868 } // namespace zypp
869 ///////////////////////////////////////////////////////////////////