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"
34 using namespace zypp::str;
39 Locks& Locks::instance()
41 static Locks _instance;
53 bool mergeList(callback::SendReport<SavingLocksReport>& report);
55 Impl():locksDirty(false){}
58 Locks::Locks() : _pimpl(new Impl){}
60 Locks::const_iterator Locks::begin() const
61 { return _pimpl->locks.begin(); }
63 Locks::const_iterator Locks::end() const
64 { return _pimpl->locks.end(); }
66 Locks::LockList::size_type Locks::size() const
67 { return _pimpl->locks.size(); }
69 bool Locks::empty() const
70 { return _pimpl->locks.empty(); }
74 void operator()(const PoolQuery& query) const
76 for_( it,query.begin(),query.end() )
79 item.status().setLock(true,ResStatus::USER);
80 DBG << "lock "<< item.resolvable()->name();
86 * iterator that takes lock, lock all solvables from query
87 * and send query to output iterator
89 template <class OutputIterator>
90 struct LockingOutputIterator
92 LockingOutputIterator(OutputIterator& out_)
96 void operator()(const PoolQuery& query) const
106 void Locks::readAndApply( const Pathname& file )
108 MIL << "read and apply locks from "<<file << endl;
109 PathInfo pinfo(file);
110 if ( pinfo.isExist() )
112 insert_iterator<LockList> ii( _pimpl->locks,
113 _pimpl->locks.end() );
114 LockingOutputIterator<insert_iterator<LockList> > lout(ii);
115 readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
118 MIL << "file not exist(or cannot be stat), no lock added." << endl;
122 void Locks::read( const Pathname& file )
124 MIL << "read locks from "<<file << endl;
125 PathInfo pinfo(file);
126 if ( pinfo.isExist() )
127 readPoolQueriesFromFile(
128 file, insert_iterator<LockList>(_pimpl->locks, _pimpl->locks.end()) );
130 MIL << "file not exist(or cannot be stat), no lock added." << endl;
134 void Locks::apply() const
136 DBG << "apply locks" << endl;
137 for_each(begin(), end(), ApplyLock());
141 void Locks::addLock( const PoolQuery& query )
143 MIL << "add new lock" << endl;
144 for_( it,query.begin(),query.end() )
147 item.status().setLock(true,ResStatus::USER);
149 LockList::iterator i = find(_pimpl->toRemove.begin(),
150 _pimpl->toRemove.end(), query);
151 if ( i != _pimpl->toRemove.end() )
153 DBG << "query removed from toRemove" << endl;
154 _pimpl->toRemove.erase(i);
158 DBG << "query added as new" << endl;
159 _pimpl->toAdd.push_back( query );
163 void Locks::addLock( const IdString& ident_r )
165 sat::Solvable::SplitIdent id(ident_r);
166 addLock(id.kind(),id.name());
169 void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
171 addLock(kind_r,IdString(name_r));
174 void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
177 q.addAttribute( sat::SolvAttr::name,name_r.asString() );
180 q.setCaseSensitive(true);
181 DBG << "add lock by identifier" << endl;
185 void Locks::removeLock( const PoolQuery& query )
187 MIL << "remove lock" << endl;
188 for_( it,query.begin(),query.end() )
191 item.status().setLock(false,ResStatus::USER);
194 LockList::iterator i = find(_pimpl->toAdd.begin(),
195 _pimpl->toAdd.end(), query);
196 if ( i != _pimpl->toAdd.end() )
198 DBG << "query removed from added" << endl;
199 _pimpl->toAdd.erase(i);
203 DBG << "needed remove some old lock" << endl;
204 _pimpl->toRemove.push_back( query );
208 void Locks::removeLock( const IdString& ident_r )
210 sat::Solvable::SplitIdent id(ident_r);
211 removeLock(id.kind(),id.name());
214 void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
216 removeLock(kind_r,IdString(name_r));
219 void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
222 q.addAttribute( sat::SolvAttr::name,name_r.asString() );
225 q.setCaseSensitive(true);
227 DBG << "remove lock by selectactable" << endl;
231 bool Locks::existEmpty() const
233 for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
242 //handle locks during removing
243 class LocksCleanPredicate{
248 callback::SendReport<CleanEmptyLocksReport> &report;
251 LocksCleanPredicate(size_t count, callback::SendReport<CleanEmptyLocksReport> &_report): skip_rest(false),searched(0),all(count), report(_report){}
253 bool aborted(){ return skip_rest; }
255 bool operator()(PoolQuery& q)
263 if (!report->progress((100*searched)/all))
269 switch (report->execute(q))
271 case CleanEmptyLocksReport::ABORT:
272 report->finish(CleanEmptyLocksReport::ABORTED);
275 case CleanEmptyLocksReport::DELETE:
277 case CleanEmptyLocksReport::IGNORE:
280 WAR << "Unknown returned value. Callback have more value then"
281 << " this switch. Need correct handle all enum values." << std::endl;
289 void Locks::removeEmpty()
291 MIL << "cleaning of locks" << endl;
292 callback::SendReport<CleanEmptyLocksReport> report;
294 size_t sum = _pimpl->locks.size();
295 LocksCleanPredicate p(sum, report);
297 _pimpl->locks.remove_if(p);
301 MIL << "cleaning aborted" << endl;
302 report->finish(CleanEmptyLocksReport::ABORTED);
306 report->finish(CleanEmptyLocksReport::NO_ERROR);
310 if ( sum != _pimpl->locks.size() ) //some locks has been removed
311 _pimpl->locksDirty = true;
314 class LocksRemovePredicate
317 std::set<sat::Solvable>& solvs;
318 const PoolQuery& query;
319 callback::SendReport<SavingLocksReport>& report;
322 //1 for subset of set, 2 only intersect, 0 for not intersect
323 int contains(const PoolQuery& q, std::set<sat::Solvable>& s)
325 bool intersect = false;
326 for_( it,q.begin(),q.end() )
328 if ( s.find(*it)!=s.end() )
338 return intersect ? 1 : 0;
342 LocksRemovePredicate(std::set<sat::Solvable>& s, const PoolQuery& q,
343 callback::SendReport<SavingLocksReport>& r)
344 : solvs(s), query(q),report(r),aborted_(false) {}
346 bool operator()(const PoolQuery& q)
352 DBG << "identical queries" << endl;
356 SavingLocksReport::ConflictState cs;
357 switch( contains(q,solvs) )
360 return false; //another lock
362 cs = SavingLocksReport::SAME_RESULTS;
365 cs = SavingLocksReport::INTERSECT;
370 MIL << "find conflict: " << cs << endl;
371 switch (report->conflict(q,cs))
373 case SavingLocksReport::ABORT:
375 DBG << "abort merging" << endl;
377 case SavingLocksReport::DELETE:
378 DBG << "force delete" << endl;
380 case SavingLocksReport::IGNORE:
381 DBG << "skip lock" << endl;
384 WAR << "should not reached, some state is missing" << endl;
388 bool aborted(){ return aborted_; }
391 bool Locks::Impl::mergeList(callback::SendReport<SavingLocksReport>& report)
393 MIL << "merging list old: " << locks.size()
394 << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
395 for_(it,toRemove.begin(),toRemove.end())
397 std::set<sat::Solvable> s(it->begin(),it->end());
398 locks.remove_if(LocksRemovePredicate(s,*it, report));
401 if (!report->progress())
404 for_( it, toAdd.begin(), toAdd.end() )
406 if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
407 locks.push_back( *it );
418 if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
420 return; //nothing to merge
423 callback::SendReport<SavingLocksReport> report;
425 if (!_pimpl->mergeList(report))
427 report->finish(SavingLocksReport::ABORTED);
430 DBG << "locks merged" << endl;
431 report->finish(SavingLocksReport::NO_ERROR);
432 _pimpl->locksDirty = true;
435 void Locks::save( const Pathname& file )
437 if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
438 && !_pimpl->locksDirty )
440 DBG << "nothing changed in locks - no write to file" << endl;
444 callback::SendReport<SavingLocksReport> report;
447 if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
449 if (!_pimpl->mergeList(report))
451 report->finish(SavingLocksReport::ABORTED);
456 DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
457 writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
458 report->finish(SavingLocksReport::NO_ERROR);
461 void Locks::removeDuplicates()
463 size_type sum = size();
464 for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
466 if ( find(_pimpl->locks.begin(),it,*it) != it )
467 _pimpl->locks.erase(it--); //-- to avoid using break iterator
471 _pimpl->locksDirty = true;