Imported Upstream version 15.0.0
[platform/upstream/libzypp.git] / zypp / target / TargetImpl.commitFindFileConflicts.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/TargetImpl.commitFindFileConflicts.cc
10  */
11 extern "C"
12 {
13 #include <solv/pool.h>
14 #include <solv/repo.h>
15 #include <solv/solvable.h>
16 #include <solv/poolarch.h>
17 #include <solv/repo_solv.h>
18 #include <solv/repo_rpmdb.h>
19 #include <solv/pool_fileconflicts.h>
20 }
21 #include <iostream>
22 #include <unordered_set>
23 #include <string>
24
25 #include "zypp/base/LogTools.h"
26 #include "zypp/base/Gettext.h"
27 #include "zypp/base/Exception.h"
28 #include "zypp/base/UserRequestException.h"
29
30 #include "zypp/sat/Queue.h"
31 #include "zypp/sat/FileConflicts.h"
32 #include "zypp/sat/Pool.h"
33
34 #include "zypp/target/TargetImpl.h"
35 #include "zypp/target/CommitPackageCache.h"
36
37 #include "zypp/ZYppCallbacks.h"
38
39 using std::endl;
40
41 ///////////////////////////////////////////////////////////////////
42 namespace zypp
43 {
44   ///////////////////////////////////////////////////////////////////
45   namespace target
46   {
47     ///////////////////////////////////////////////////////////////////
48     namespace
49     {
50       /** libsolv::pool_findfileconflicts callback providing package header. */
51       struct FileConflictsCB
52       {
53         FileConflictsCB( ::_Pool * pool_r, ProgressData & progress_r )
54         : _progress( progress_r )
55         , _state( ::rpm_state_create( pool_r, ::pool_get_rootdir(pool_r) ), ::rpm_state_free )
56         {}
57
58         void * operator()( ::_Pool * pool_r, sat::detail::IdType id_r )
59         {
60           void * ret = lookup( id_r );
61
62           // report progress on 1st visit only, ticks later
63           // (there may be up to 3 visits)
64           if ( _visited.find( id_r ) == _visited.end() )
65           {
66             //DBG << "FCCB: " << sat::Solvable( id_r ) << " " << ret << endl;
67             _visited.insert( id_r );
68             if ( ! ret && sat::Solvable( id_r ).isKind<Package>() )     // only packages have filelists
69               _noFilelist.push( id_r );
70             _progress.incr();
71           }
72           else
73           {
74             _progress.tick();
75           }
76           return ret;
77         }
78
79         const sat::Queue & noFilelist() const
80         { return _noFilelist; }
81
82         static void * invoke( ::_Pool * pool_r, sat::detail::IdType id_r, void * cbdata_r )
83         { return (*reinterpret_cast<FileConflictsCB*>(cbdata_r))( pool_r, id_r ); }
84
85       private:
86         void * lookup( sat::detail::IdType id_r )
87         {
88           sat::Solvable solv( id_r );
89           if ( solv.isSystem() )
90           {
91             Solvable * s = solv.get();
92             if ( ! s->repo->rpmdbid )
93               return nullptr;
94             sat::detail::IdType rpmdbid = s->repo->rpmdbid[id_r - s->repo->start];
95             if ( ! rpmdbid )
96               return nullptr;
97             return ::rpm_byrpmdbid( _state, rpmdbid );
98           }
99           else
100           {
101             Package::Ptr pkg( make<Package>( solv ) );
102             if ( ! pkg )
103               return nullptr;
104             Pathname localfile( pkg->cachedLocation() );
105             if ( localfile.empty() )
106               return nullptr;
107             AutoDispose<FILE*> fp( ::fopen( localfile.c_str(), "re" ), ::fclose );
108             return ::rpm_byfp( _state, fp, localfile.c_str() );
109           }
110         }
111
112       private:
113         ProgressData & _progress;
114         AutoDispose<void*> _state;
115         std::unordered_set<sat::detail::IdType> _visited;
116         sat::Queue _noFilelist;
117       };
118
119     } // namespace
120     ///////////////////////////////////////////////////////////////////
121
122     void TargetImpl::commitFindFileConflicts( const ZYppCommitPolicy & policy_r, ZYppCommitResult & result_r )
123     {
124       sat::Queue todo;
125       sat::FileConflicts conflicts;
126       int newpkgs = result_r.transaction().installedResult( todo );
127       MIL << "Checking for file conflicts in " << newpkgs << " new packages..." << endl;
128       if ( ! newpkgs )
129         return;
130
131       try {
132         callback::SendReport<FindFileConflictstReport> report;
133         ProgressData progress( todo.size() );
134         if ( ! report->start( progress ) )
135           ZYPP_THROW( AbortRequestException() );
136
137         FileConflictsCB cb( sat::Pool::instance().get(), progress );
138         // lambda receives progress trigger and translates into report
139         auto sendProgress = [&]( const ProgressData & progress_r )->bool {
140           if ( ! report->progress( progress_r, cb.noFilelist() ) )
141             ZYPP_THROW( AbortRequestException() );
142           return true;
143         };
144         progress.sendTo( sendProgress );
145
146         unsigned count =
147           ::pool_findfileconflicts( sat::Pool::instance().get(),
148                                     todo,
149                                     newpkgs,
150                                     conflicts,
151                                     FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR,
152                                     &FileConflictsCB::invoke,
153                                     &cb );
154         progress.toMax();
155         progress.noSend();
156
157         (count?WAR:MIL) << "Found " << count << " file conflicts." << endl;
158         if ( ! report->result( progress, cb.noFilelist(), conflicts ) )
159           ZYPP_THROW( AbortRequestException() );
160       }
161       catch ( const AbortRequestException & e )
162       {
163         TargetAbortedException excpt( N_("Installation has been aborted as directed.") );
164         excpt.remember( e );
165         ZYPP_THROW( excpt );
166       }
167     }
168
169   } // namespace target
170   ///////////////////////////////////////////////////////////////////
171 } // namespace zypp
172 ///////////////////////////////////////////////////////////////////