#include <fstream>
#include <boost/function.hpp>
#include <boost/function_output_iterator.hpp>
+#include <algorithm>
#include "zypp/base/Regex.h"
#include "zypp/base/String.h"
#include "zypp/PoolQueryUtil.tcc"
#include "zypp/ZYppCallbacks.h"
#include "zypp/sat/SolvAttr.h"
+#include "zypp/sat/Solvable.h"
#include "zypp/PathInfo.h"
#undef ZYPP_BASE_LOGGER_LOGGROUP
namespace zypp
{
-namespace locks
-{
Locks& Locks::instance()
{
class Locks::Impl
{
public:
- std::list<PoolQuery> locks;
- std::list<PoolQuery> toAdd;
- std::list<PoolQuery> toRemove;
+ LockList locks;
+ LockList toAdd;
+ LockList toRemove;
+ bool locksDirty;
bool mergeList(callback::SendReport<SavingLocksReport>& report);
+ Impl():locksDirty(false){}
};
Locks::Locks() : _pimpl(new Impl){}
+Locks::const_iterator Locks::begin() const
+{ return _pimpl->locks.begin(); }
+
+Locks::const_iterator Locks::end() const
+{ return _pimpl->locks.end(); }
+
+Locks::LockList::size_type Locks::size() const
+{ return _pimpl->locks.size(); }
+
+bool Locks::empty() const
+{ return _pimpl->locks.empty(); }
+
+struct ApplyLock
+{
+ void operator()(const PoolQuery& query) const
+ {
+ for_( it,query.begin(),query.end() )
+ {
+ PoolItem item(*it);
+ item.status().setLock(true,ResStatus::USER);
+ DBG << "lock "<< item.resolvable()->name();
+ }
+ }
+};
+
/**
* iterator that takes lock, lock all solvables from query
* and send query to output iterator
void operator()(const PoolQuery& query) const
{
- for_( it,query.begin(),query.end() )
- {
- PoolItem item(*it);
- item.status().setLock(true,ResStatus::USER);
- }
-
+ ApplyLock a;a(query);
*out++ = query;
}
private:
OutputIterator& out;
- };
+};
+
+void Locks::readAndApply( const Pathname& file )
+{
+ MIL << "read and apply locks from "<<file << endl;
+ PathInfo pinfo(file);
+ if ( pinfo.isExist() )
+ {
+ insert_iterator<LockList> ii( _pimpl->locks,
+ _pimpl->locks.end() );
+ LockingOutputIterator<insert_iterator<LockList> > lout(ii);
+ readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
+ }
+ else
+ MIL << "file not exist(or cannot be stat), no lock added." << endl;
+
+}
-void Locks::loadLocks( const Pathname& file )
+void Locks::read( const Pathname& file )
{
- insert_iterator<std::list<PoolQuery> > ii( _pimpl->locks,
- _pimpl->locks.end() );
- LockingOutputIterator<insert_iterator<std::list<PoolQuery> > > lout(ii);
- readPoolQueriesFromFile( file, boost::make_function_output_iterator(lout) );
+ MIL << "read locks from "<<file << endl;
+ PathInfo pinfo(file);
+ if ( pinfo.isExist() )
+ readPoolQueriesFromFile(
+ file, insert_iterator<LockList>(_pimpl->locks, _pimpl->locks.end()) );
+ else
+ MIL << "file not exist(or cannot be stat), no lock added." << endl;
+}
+
+
+void Locks::apply() const
+{
+ DBG << "apply locks" << endl;
+ for_each(begin(), end(), ApplyLock());
}
+
void Locks::addLock( const PoolQuery& query )
{
+ MIL << "add new lock" << endl;
for_( it,query.begin(),query.end() )
{
PoolItem item(*it);
item.status().setLock(true,ResStatus::USER);
}
- std::list<PoolQuery>::iterator i = find(_pimpl->toRemove.begin(),
+ LockList::iterator i = find(_pimpl->toRemove.begin(),
_pimpl->toRemove.end(), query);
if ( i != _pimpl->toRemove.end() )
{
}
}
-void Locks::addLock(const ui::Selectable& selectable)
+void Locks::addLock( const IdString& ident_r )
+{
+ sat::Solvable::SplitIdent id(ident_r);
+ addLock(id.kind(),id.name());
+}
+
+void Locks::addLock( const ResKind& kind_r, const C_Str & name_r )
+{
+ addLock(kind_r,IdString(name_r));
+}
+
+void Locks::addLock( const ResKind& kind_r, const IdString& name_r )
{
PoolQuery q;
- q.addAttribute( sat::SolvAttr::name,selectable.name() );
- q.addKind( selectable.kind() );
+ q.addAttribute( sat::SolvAttr::name,name_r.asString() );
+ q.addKind( kind_r );
q.setMatchExact();
q.setCaseSensitive(true);
- q.requireAll();
+ DBG << "add lock by identifier" << endl;
addLock( q );
}
-void Locks::unlock( const PoolQuery& query )
+void Locks::removeLock( const PoolQuery& query )
{
+ MIL << "remove lock" << endl;
for_( it,query.begin(),query.end() )
{
PoolItem item(*it);
item.status().setLock(false,ResStatus::USER);
}
- std::list<PoolQuery>::iterator i = find(_pimpl->toAdd.begin(),
+ LockList::iterator i = find(_pimpl->toAdd.begin(),
_pimpl->toAdd.end(), query);
if ( i != _pimpl->toAdd.end() )
{
}
}
-void Locks::unlock( const ui::Selectable& s )
+void Locks::removeLock( const IdString& ident_r )
+{
+ sat::Solvable::SplitIdent id(ident_r);
+ removeLock(id.kind(),id.name());
+}
+
+void Locks::removeLock( const ResKind& kind_r, const C_Str & name_r )
+{
+ removeLock(kind_r,IdString(name_r));
+}
+
+void Locks::removeLock( const ResKind &kind_r, const IdString &name_r )
{
PoolQuery q;
- q.addAttribute( sat::SolvAttr::name,s.name() );
- q.addKind( s.kind() );
+ q.addAttribute( sat::SolvAttr::name,name_r.asString() );
+ q.addKind( kind_r );
q.setMatchExact();
q.setCaseSensitive(true);
q.requireAll();
- unlock(q);
+ DBG << "remove lock by selectactable" << endl;
+ removeLock(q);
}
-bool Locks::existEmptyLocks()
+bool Locks::existEmpty() const
{
for_( it, _pimpl->locks.begin(), _pimpl->locks.end() )
{
};
-void Locks::removeEmptyLocks()
+void Locks::removeEmpty()
{
+ MIL << "cleaning of locks" << endl;
callback::SendReport<CleanEmptyLocksReport> report;
report->start();
size_t sum = _pimpl->locks.size();
if( p.aborted() )
{
+ MIL << "cleaning aborted" << endl;
report->finish(CleanEmptyLocksReport::ABORTED);
}
else
report->finish(CleanEmptyLocksReport::NO_ERROR);
}
+
+ if ( sum != _pimpl->locks.size() ) //some locks has been removed
+ _pimpl->locksDirty = true;
}
class LocksRemovePredicate
switch( contains(q,solvs) )
{
case 0:
- return false;
+ return false; //another lock
case 1:
cs = SavingLocksReport::SAME_RESULTS;
break;
case 2:
cs = SavingLocksReport::INTERSECT;
+ break;
default:
return true;
}
+ MIL << "find conflict: " << cs << endl;
switch (report->conflict(q,cs))
{
case SavingLocksReport::ABORT:
bool Locks::Impl::mergeList(callback::SendReport<SavingLocksReport>& report)
{
+ MIL << "merging list old: " << locks.size()
+ << " to add: " << toAdd.size() << "to remove: " << toRemove.size() << endl;
for_(it,toRemove.begin(),toRemove.end())
{
- if (!report->progress())
- return false;
std::set<sat::Solvable> s(it->begin(),it->end());
locks.remove_if(LocksRemovePredicate(s,*it, report));
}
if (!report->progress())
return false;
- locks.insert(locks.end(),toAdd.begin(),toAdd.end());
+
+ for_( it, toAdd.begin(), toAdd.end() )
+ {
+ if( std::find( locks.begin(), locks.end(), *it ) == locks.end() )
+ locks.push_back( *it );
+ }
+
+ toAdd.clear();
+ toRemove.clear();
+
return true;
}
-void Locks::saveLocks( const Pathname& file )
+void Locks::merge()
{
+ if( (_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
+ {
+ return; //nothing to merge
+ }
+
callback::SendReport<SavingLocksReport> report;
report->start();
if (!_pimpl->mergeList(report))
report->finish(SavingLocksReport::ABORTED);
return;
}
+ DBG << "locks merged" << endl;
+ report->finish(SavingLocksReport::NO_ERROR);
+ _pimpl->locksDirty = true;
+}
+
+void Locks::save( const Pathname& file )
+{
+ if( ((_pimpl->toAdd.size() | _pimpl->toRemove.size())==0)
+ && !_pimpl->locksDirty )
+ {
+ DBG << "nothing changed in locks - no write to file" << endl;
+ return;
+ }
+
+ callback::SendReport<SavingLocksReport> report;
+ report->start();
+
+ if ((_pimpl->toAdd.size() | _pimpl->toRemove.size())!=0)
+ {
+ if (!_pimpl->mergeList(report))
+ {
+ report->finish(SavingLocksReport::ABORTED);
+ return;
+ }
+ }
+
DBG << "writed "<< _pimpl->locks.size() << "locks" << endl;
writePoolQueriesToFile( file, _pimpl->locks.begin(), _pimpl->locks.end() );
report->finish(SavingLocksReport::NO_ERROR);
}
-} // ns locks
+void Locks::removeDuplicates()
+{
+ size_type sum = size();
+ for_(it,_pimpl->locks.begin(),_pimpl->locks.end())
+ {
+ if ( find(_pimpl->locks.begin(),it,*it) != it )
+ _pimpl->locks.erase(it--); //-- to avoid using break iterator
+ }
+
+ if (sum!=size())
+ _pimpl->locksDirty = true;
+}
+
} // ns zypp