1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
12 #include <boost/function.hpp>
13 #include <boost/function_output_iterator.hpp>
16 #include "zypp/base/Regex.h"
17 #include "zypp/base/String.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/IOStream.h"
20 #include "zypp/PoolItem.h"
21 #include "zypp/PoolQueryUtil.tcc"
22 #include "zypp/ZYppCallbacks.h"
23 #include "zypp/sat/SolvAttr.h"
24 #include "zypp/sat/Solvable.h"
25 #include "zypp/PathInfo.h"
27 #undef ZYPP_BASE_LOGGER_LOGGROUP
28 #define ZYPP_BASE_LOGGER_LOGGROUP "locks"
30 #include "zypp/Locks.h"
37 Locks& Locks::instance()
39 static Locks _instance;
51 bool mergeList(callback::SendReport<SavingLocksReport>& report);
53 Impl():locksDirty(false){}
56 Locks::Locks() : _pimpl(new Impl){}
58 Locks::const_iterator Locks::begin() const
59 { return _pimpl->locks.begin(); }
61 Locks::const_iterator Locks::end() const
62 { return _pimpl->locks.end(); }
64 Locks::LockList::size_type Locks::size() const
65 { return _pimpl->locks.size(); }
67 bool Locks::empty() const
68 { return _pimpl->locks.empty(); }
72 void operator()(const PoolQuery& query) const
74 for ( const PoolItem & item : query.poolItem() )
76 item.status().setLock(true,ResStatus::USER);
77 DBG << "lock "<< item.name();
83 * iterator that takes lock, lock all solvables from query
84 * and send query to output iterator
86 template <class OutputIterator>
87 struct LockingOutputIterator
89 LockingOutputIterator(OutputIterator& out_)
93 void operator()(const PoolQuery& query) const
103 void Locks::readAndApply( const Pathname& file )
105 MIL << "read and apply locks from "<<file << endl;
106 PathInfo pinfo(file);
107 if ( pinfo.isExist() )
109 std::insert_iterator<LockList> ii( _pimpl->locks, _pimpl->locks.end() );
110 LockingOutputIterator<std::insert_iterator<LockList> > lout(ii);
111 readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
114 MIL << "file not exist(or cannot be stat), no lock added." << endl;
118 void Locks::read( const Pathname& file )
120 MIL << "read locks from "<<file << endl;
121 PathInfo pinfo(file);
122 if ( pinfo.isExist() )
123 readPoolQueriesFromFile( file, std::insert_iterator<LockList>(_pimpl->locks, _pimpl->locks.end()) );
125 MIL << "file not exist(or cannot be stat), no lock added." << endl;
129 void Locks::apply() const
131 DBG << "apply locks" << endl;
132 for_each(begin(), end(), ApplyLock());
136 void Locks::addLock( const PoolQuery& query )
138 MIL << "add new lock" << endl;
139 for_( it,query.begin(),query.end() )
142 item.status().setLock(true,ResStatus::USER);
144 LockList::iterator i = find(_pimpl->toRemove.begin(),
145 _pimpl->toRemove.end(), query);
146 if ( i != _pimpl->toRemove.end() )
148 DBG << "query removed from toRemove" << endl;
149 _pimpl->toRemove.erase(i);
153 DBG << "query added as new" << endl;
154 _pimpl->toAdd.push_back( query );
158 void Locks::addLock( const IdString& ident_r )
160 sat::Solvable::SplitIdent id(ident_r);
161 addLock(id.kind(),id.name());
164 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
166 addLock(kind_r,IdString(name_r));
169 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
172 q.addAttribute( sat::SolvAttr::name,name_r.asString() );
175 q.setCaseSensitive(true);
176 DBG << "add lock by identifier" << endl;
180 void Locks::removeLock( const PoolQuery& query )
182 MIL << "remove lock" << endl;
183 for_( it,query.begin(),query.end() )
186 item.status().setLock(false,ResStatus::USER);
189 LockList::iterator i = find(_pimpl->toAdd.begin(),
190 _pimpl->toAdd.end(), query);
191 if ( i != _pimpl->toAdd.end() )
193 DBG << "query removed from added" << endl;
194 _pimpl->toAdd.erase(i);
198 DBG << "needed remove some old lock" << endl;
199 _pimpl->toRemove.push_back( query );
203 void Locks::removeLock( const IdString& ident_r )
205 sat::Solvable::SplitIdent id(ident_r);
206 removeLock(id.kind(),id.name());
209 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
211 removeLock(kind_r,IdString(name_r));
214 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
217 q.addAttribute( sat::SolvAttr::name,name_r.asString() );
220 q.setCaseSensitive(true);
222 DBG << "remove lock by selectactable" << endl;
226 bool Locks::existEmpty() const
228 for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
237 //handle locks during removing
238 class LocksCleanPredicate{
243 callback::SendReport<CleanEmptyLocksReport> &report;
246 LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
248 bool aborted(){ return skip_rest; }
250 bool operator()(PoolQuery& q)
258 if (!report->progress((100*searched)/all))
264 switch (report->execute(q))
266 case CleanEmptyLocksReport::ABORT:
267 report->finish(CleanEmptyLocksReport::ABORTED);
270 case CleanEmptyLocksReport::DELETE:
272 case CleanEmptyLocksReport::IGNORE:
275 WAR << "Unknown returned value. Callback have more value then"
276 << " this switch. Need correct handle all enum values." << std::endl;
284 void Locks::removeEmpty()
286 MIL << "cleaning of locks" << endl;
287 callback::SendReport<CleanEmptyLocksReport> report;
289 size_t sum = _pimpl->locks.size();
290 LocksCleanPredicate p(sum, report);
292 _pimpl->locks.remove_if(p);
296 MIL << "cleaning aborted" << endl;
297 report->finish(CleanEmptyLocksReport::ABORTED);
301 report->finish(CleanEmptyLocksReport::NO_ERROR);
305 if ( sum != _pimpl->locks.size() ) //some locks has been removed
306 _pimpl->locksDirty = true;
309 class LocksRemovePredicate
312 std::set<sat::Solvable>& solvs;
313 const PoolQuery& query;
314 callback::SendReport<SavingLocksReport>& report;
317 //1 for subset of set, 2 only intersect, 0 for not intersect
318 int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
320 bool intersect = false;
321 for_( it,q.begin(),q.end() )
323 if ( s.find(*it)!=s.end() )
333 return intersect ? 1 : 0;
337 LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
338 callback::SendReport<SavingLocksReport>& r)
339 : solvs(s), query(q),report(r),aborted_(false) {}
341 bool operator()(const PoolQuery& q)
347 DBG << "identical queries" << endl;
351 SavingLocksReport::ConflictState cs;
352 switch( contains(q,solvs) )
355 return false; //another lock
357 cs = SavingLocksReport::SAME_RESULTS;
360 cs = SavingLocksReport::INTERSECT;
365 MIL << "find conflict: " << cs << endl;
366 switch (report->conflict(q,cs))
368 case SavingLocksReport::ABORT:
370 DBG << "abort merging" << endl;
372 case SavingLocksReport::DELETE:
373 DBG << "force delete" << endl;
375 case SavingLocksReport::IGNORE:
376 DBG << "skip lock" << endl;
379 WAR << "should not reached, some state is missing" << endl;
383 bool aborted(){ return aborted_; }
386 bool Locks::Impl::mergeList(callback::SendReport<SavingLocksReport>& report)
388 MIL << "merging list old: " << locks.size()
389 << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
390 for_(it,toRemove.begin(),toRemove.end())
392 std::set<sat::Solvable> s(it->begin(),it->end());
393 locks.remove_if(LocksRemovePredicate(s,*it, report));
396 if (!report->progress())
399 for_( it, toAdd.begin(), toAdd.end() )
401 if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
402 locks.push_back( *it );
413 if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
415 return; //nothing to merge
418 callback::SendReport<SavingLocksReport> report;
420 if (!_pimpl->mergeList(report))
422 report->finish(SavingLocksReport::ABORTED);
425 DBG << "locks merged" << endl;
426 report->finish(SavingLocksReport::NO_ERROR);
427 _pimpl->locksDirty = true;
430 void Locks::save( const Pathname& file )
432 if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
433 && !_pimpl->locksDirty )
435 DBG << "nothing changed in locks - no write to file" << endl;
439 callback::SendReport<SavingLocksReport> report;
442 if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
444 if (!_pimpl->mergeList(report))
446 report->finish(SavingLocksReport::ABORTED);
451 DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
452 writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
453 report->finish(SavingLocksReport::NO_ERROR);
456 void Locks::removeDuplicates()
458 size_type sum = size();
459 for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
461 if ( find(_pimpl->locks.begin(),it,*it) != it )
462 _pimpl->locks.erase(it--); //-- to avoid using break iterator
466 _pimpl->locksDirty = true;