#include "zypp/sat/Pool.h"
#include "zypp/sat/Solvable.h"
-#include "zypp/sat/AttrMatcher.h"
+#include "zypp/base/StrMatcher.h"
#include "zypp/PoolQuery.h"
namespace
{ /////////////////////////////////////////////////////////////////
- /** Match data per attribtue.
- *
- * This includes the attribute itself, an optional \ref sat::AttrMatcher
- * to restrict the query to certain string values, and an optional
- * boolean \ref Predicate that may apply further restrictions that can
- * not be expressed by the \ref attrMatcher.
- *
- * Example for such a \ref predicate would be an additional edition range
- * check whan looking for dependencies. The \ref attrMatcher would
- * find potential matches by looking at the dependencies name, the
- * predicate will then check the edition ranges.
- *
- * As the \ref predicate takes an iterator pointing to the current
- * match, it's also suitable for sub-structure (flexarray) inspection
- * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
- */
- struct AttrMatchData
- {
- typedef function<bool(sat::LookupAttr::iterator)> Predicate;
-
- static bool always( sat::LookupAttr::iterator ) { return true; }
- static bool never( sat::LookupAttr::iterator ) { return false; }
-
- AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
- : attr( attr_r )
- , attrMatcher( attrMatcher_r )
- {}
-
- AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r, const Predicate & predicate_r )
- : attr( attr_r )
- , attrMatcher( attrMatcher_r )
- , predicate( predicate_r )
- {}
-
- sat::SolvAttr attr;
- sat::AttrMatcher attrMatcher;
- Predicate predicate;
- };
-
- std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
- {
- return str << obj.attr << ": " << obj.attrMatcher << ( obj.predicate ? " (+predicate)" : "" );
- }
-
- typedef std::list<AttrMatchData> AttrMatchList;
-
/////////////////////////////////////////////////////////////////
// some Helpers and Predicates
/////////////////////////////////////////////////////////////////
return false;
}
- /** Whether the current capabilities edition range ovelaps.
+ /** Whether the current capabilities edition range ovelaps and/or its solvables arch matches.
* Query asserts \a iter_r points to a capability and we
* have to check the range only.
*/
{
EditionRangePredicate( const Rel & op, const Edition & edition )
: _range( op, edition )
+ , _arch( Arch_empty )
+ {}
+ EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
+ : _range( op, edition )
+ , _arch( arch )
{}
bool operator()( sat::LookupAttr::iterator iter_r )
{
+ if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
+ return false;
+
CapDetail cap( iter_r.id() );
if ( ! cap.isSimple() )
return false;
return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
}
+ std::string serialize() const
+ {
+ std::string ret( "EditionRange" );
+ str::appendEscaped( ret, _range.op.asString() );
+ str::appendEscaped( ret, _range.value.asString() );
+ str::appendEscaped( ret, _arch.asString() );
+ return ret;
+ }
+
Edition::MatchRange _range;
- };
+ Arch _arch;
+ };
- /** Whether the current Solvables edition is within a given range. */
+ /** Whether the current Solvables edition is within a given range and/or its arch matches. */
struct SolvableRangePredicate
{
SolvableRangePredicate( const Rel & op, const Edition & edition )
: _range( op, edition )
+ , _arch( Arch_empty )
+ {}
+
+ SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
+ : _range( op, edition )
+ , _arch( arch )
{}
bool operator()( sat::LookupAttr::iterator iter_r )
{
- return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
+ if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
+ return false;
+ return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
+ }
+
+ std::string serialize() const
+ {
+ std::string ret( "SolvableRange" );
+ str::appendEscaped( ret, _range.op.asString() );
+ str::appendEscaped( ret, _range.value.asString() );
+ str::appendEscaped( ret, _arch.asString() );
+ return ret;
}
Edition::MatchRange _range;
+ Arch _arch;
};
/** Whether the current capability matches a given one.
return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
}
+ std::string serialize() const
+ {
+ std::string ret( "CapabilityMatch" );
+ str::appendEscaped( ret, _cap.asString() );
+ return ret;
+ }
+
Capability _cap;
};
+ /////////////////////////////////////////////////////////////////
+ //
+ /////////////////////////////////////////////////////////////////
+ /** Match data per attribtue.
+ *
+ * This includes the attribute itself, an optional \ref StrMatcher
+ * to restrict the query to certain string values, and an optional
+ * boolean \ref Predicate that may apply further restrictions that can
+ * not be expressed by the \ref strMatcher.
+ *
+ * Example for such a \ref predicate would be an additional edition range
+ * check whan looking for dependencies. The \ref strMatcher would
+ * find potential matches by looking at the dependencies name, the
+ * predicate will then check the edition ranges.
+ *
+ * As the \ref predicate takes an iterator pointing to the current
+ * match, it's also suitable for sub-structure (flexarray) inspection
+ * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
+ *
+ * \note: \see \ref addPredicate for further constraints.
+ */
+ struct AttrMatchData
+ {
+ typedef function<bool(sat::LookupAttr::iterator)> Predicate;
+
+ static bool always( sat::LookupAttr::iterator ) { return true; }
+ static bool never( sat::LookupAttr::iterator ) { return false; }
+
+ AttrMatchData()
+ {}
+
+ AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
+ : attr( attr_r )
+ , strMatcher( strMatcher_r )
+ {}
+
+ AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
+ const Predicate & predicate_r, const std::string & predicateStr_r )
+ : attr( attr_r )
+ , strMatcher( strMatcher_r )
+ , predicate( predicate_r )
+ , predicateStr( predicateStr_r )
+ {}
+
+ /** A usable Predicate must provide a string serialization.
+ * As there is no \c operator== for \ref Predicate, we compare it's
+ * string representation instead. If you add new predicated, check the
+ * deserialization code in \ref deserialize.
+ */
+ template<class _Predicate>
+ void addPredicate( const _Predicate & predicate_r )
+ {
+ predicate = predicate_r;
+ predicateStr = predicate_r.serialize();
+ }
+
+ /** Dumb serialization.
+ * \code
+ * AttrMatchData ATTRIBUTE SEARCHSTRING [C|X] SERIALIZED_PREDICATE
+ * \endcode
+ */
+ std::string serialize() const
+ {
+ std::string ret( "AttrMatchData" );
+ str::appendEscaped( ret, attr.asString() );
+ str::appendEscaped( ret, strMatcher.searchstring() );
+ // TODO: Actually the flag should be serialized too, but for PoolQuery
+ // it's by now sufficient to differ between mode OTHER and others,
+ // i.e. whether to compile or not compile.
+ str::appendEscaped( ret, strMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
+ str::appendEscaped( ret, predicateStr );
+ return ret;
+ }
+
+ /** Dumb restore from serialized string.
+ * \throw Exception on parse error.
+ */
+ static AttrMatchData deserialize( const std::string & str_r )
+ {
+ std::vector<std::string> words;
+ str::splitEscaped( str_r, std::back_inserter(words) );
+ if ( words.empty() || words[0] != "AttrMatchData" )
+ ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
+ if ( words.size() != 5 )
+ ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+
+ AttrMatchData ret;
+ ret.attr = sat::SolvAttr( words[1] );
+ ret.strMatcher = StrMatcher( words[2] );
+ if ( words[3] == "C" )
+ ret.strMatcher.setFlags( Match::OTHER );
+ ret.predicateStr = words[4];
+
+ // now the predicate
+ words.clear();
+ str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
+ if ( ! words.empty() )
+ {
+ if ( words[0] == "EditionRange" )
+ {
+ switch( words.size() )
+ {
+ case 3:
+ ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
+ break;
+ case 4:
+ ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
+ break;
+ default:
+ ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+ break;
+ }
+ }
+ else if ( words[0] == "SolvableRange" )
+ {
+ switch( words.size() )
+ {
+ case 3:
+ ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
+ break;
+ case 4:
+ ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
+ break;
+ default:
+ ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+ break;
+ }
+ }
+ else if ( words[0] == "CapabilityMatch" )
+ {
+ if ( words.size() != 2 )
+ ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
+ ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
+ }
+ else
+ ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
+ }
+ return ret;
+ }
+
+ sat::SolvAttr attr;
+ StrMatcher strMatcher;
+ Predicate predicate;
+ std::string predicateStr;
+ };
+
+ /** \relates AttrMatchData */
+ inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
+ {
+ str << obj.attr << ": " << obj.strMatcher;
+ if ( obj.predicate )
+ str << " +(" << obj.predicateStr << ")";
+ return str;
+ }
+
+ /** \relates AttrMatchData */
+ inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
+ {
+ return ( lhs.attr == rhs.attr
+ && lhs.strMatcher == rhs.strMatcher
+ && lhs.predicateStr == rhs.predicateStr );
+ }
+
+ /** \relates AttrMatchData */
+ inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
+ { return !( lhs == rhs ); }
+
+ /** \relates AttrMatchData Arbitrary order for std::container. */
+ inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
+ {
+ if ( lhs.attr != rhs.attr )
+ return ( lhs.attr < rhs.attr );
+ if ( lhs.strMatcher != rhs.strMatcher )
+ return ( lhs.strMatcher < rhs.strMatcher );
+ if ( lhs.predicateStr != rhs.predicateStr )
+ return ( lhs.predicateStr < rhs.predicateStr );
+ return false;
+ }
+
+ typedef std::list<AttrMatchData> AttrMatchList;
+
+
} /////////////////////////////////////////////////////////////////
// namespace
///////////////////////////////////////////////////////////////////
/** Raw attributes */
AttrRawStrMap _attrs;
/** Uncompiled attributes with predicate. */
- AttrMatchList _uncompiledPredicated;
+ std::set<AttrMatchData> _uncompiledPredicated;
/** Sat solver search flags */
Match _flags;
//@}
public:
+
+ bool operator==( const PoolQuery::Impl & rhs ) const
+ {
+ if ( _flags == rhs._flags
+ // bnc#792901: while libzypp uses exact match mode for a single
+ // package name lock, zypper always uses glob. :(
+ // We unify those two forms to enable zypper to remove zypp locks
+ // without need to actually evaluate the query (which would require
+ // repos to be loaded).
+ || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() )
+ || ( _flags.isModeGlob() && rhs._flags.isModeString() ) )
+ && _strings.empty()
+ && _attrs.size() == 1
+ && _attrs.begin()->first == sat::SolvAttr::name ) )
+ {
+ return ( _strings == rhs._strings
+ && _attrs == rhs._attrs
+ && _uncompiledPredicated == rhs._uncompiledPredicated
+ && _match_word == rhs._match_word
+ && _require_all == rhs._require_all
+ && _status_flags == rhs._status_flags
+ && _edition == rhs._edition
+ && _op == rhs._op
+ && _repos == rhs._repos
+ && _kinds == rhs._kinds );
+ }
+ return false;
+ }
+
+ bool operator!=( const PoolQuery::Impl & rhs ) const
+ { return ! operator==( rhs ); }
+
+ public:
/** Compile the regex.
* Basically building the \ref _attrMatchList from strings.
- * \throws MatchException Any of the exceptions thrown by \ref AttrMatcher::compile.
+ * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
*/
void compile() const;
- /** AttrMatcher per attribtue. */
+ /** StrMatcher per attribtue. */
mutable AttrMatchList _attrMatchList;
private:
{ return new Impl( *this ); }
};
+ ///////////////////////////////////////////////////////////////////
struct MyInserter
{
_attrMatchList.clear();
Match cflags( _flags );
- if ( cflags.mode() == Match::OTHER) // this will never succeed...
+ if ( cflags.mode() == Match::OTHER ) // this will never succeed...
ZYPP_THROW( MatchUnknownModeException( cflags ) );
/** Compiled search strings. */
if (joined.size() > 1) // switch to regex for multiple strings
cflags.setModeRegex();
_attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
- sat::AttrMatcher( rcstrings, cflags ) ) );
+ StrMatcher( rcstrings, cflags ) ) );
}
// // MULTIPLE ATTRIBUTES
}
if (joined.size() > 1) // switch to regex for multiple strings
cflags.setModeRegex();
- // May use the same AttrMatcher for all
- sat::AttrMatcher matcher( rcstrings, cflags );
+ // May use the same StrMatcher for all
+ StrMatcher matcher( rcstrings, cflags );
for_( ai, _attrs.begin(), _attrs.end() )
{
_attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
if (joined.size() > 1) // switch to regex for multiple strings
cflags.setModeRegex();
_attrMatchList.push_back( AttrMatchData( ai->first,
- sat::AttrMatcher( s, cflags ) ) );
+ StrMatcher( s, cflags ) ) );
}
}
}
invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
{
- if ( it->attrMatcher.flags().mode() == Match::OTHER )
+ if ( it->strMatcher.flags().mode() == Match::OTHER )
{
// need to compile:
StrContainer joined( global );
- const std::string & mstr( it->attrMatcher.searchstring() );
+ const std::string & mstr( it->strMatcher.searchstring() );
if ( ! mstr.empty() )
joined.insert( mstr );
cflags.setModeRegex();
_attrMatchList.push_back( AttrMatchData( it->attr,
- sat::AttrMatcher( rcstrings, cflags ),
- it->predicate ) );
+ StrMatcher( rcstrings, cflags ),
+ it->predicate, it->predicateStr ) );
}
else
{
if ( _strings.size() > 1 ) // switch to regex for multiple strings
cflags.setModeRegex();
_attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
- sat::AttrMatcher( rcstrings, cflags ) ) );
+ StrMatcher( rcstrings, cflags ) ) );
}
// Finally check here, whether all involved regex compile.
for_( it, _attrMatchList.begin(), _attrMatchList.end() )
{
- it->attrMatcher.compile(); // throws on error
+ it->strMatcher.compile(); // throws on error
}
//DBG << asString() << endl;
}
{ _pimpl->_attrs[attr].insert(value); }
void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
+ { return addDependency( attr, name, op, edition, Arch_empty ); }
+
+ void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
{
switch ( op.inSwitch() )
{
case Rel::ANY_e: // no additional constraint on edition.
- addAttribute( attr, name );
- return;
+ if ( arch.empty() ) // no additional constraint on arch.
+ {
+ addAttribute( attr, name );
+ return;
+ }
+ break;
case Rel::NONE_e: // will never match.
return;
break;
}
- // Match::OTHER indicates need to compile.
- sat::AttrMatcher matcher( name, Match::OTHER );
+ // Match::OTHER indicates need to compile
+ // (merge global search strings into name).
+ AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
- AttrMatchData::Predicate pred;
if ( isDependencyAttribute( attr ) )
- pred = EditionRangePredicate( op, edition );
+ attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
else
- pred = SolvableRangePredicate( op, edition );
+ attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
- _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) );
+ _pimpl->_uncompiledPredicated.insert( attrMatchData );
}
void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
return;
// Matches STRING per default. (won't get compiled!)
- sat::AttrMatcher matcher( cap.name().asString() );
+ AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
- AttrMatchData::Predicate pred;
if ( isDependencyAttribute( attr ) )
- pred = CapabilityMatchPredicate( cap_r );
+ attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
else
- pred = SolvableRangePredicate( cap.op(), cap.ed() );
+ attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
- _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) );
+ _pimpl->_uncompiledPredicated.insert( attrMatchData );
}
void PoolQuery::setEdition(const Edition & edition, const Rel & op)
static const PoolQueryAttr caseSensitiveAttr;
static const PoolQueryAttr installStatusAttr;
static const PoolQueryAttr editionAttr;
+ static const PoolQueryAttr complexAttr;
};
const PoolQueryAttr PoolQueryAttr::noAttr;
const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
const PoolQueryAttr PoolQueryAttr::editionAttr("version");
+ const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
class StringTypeAttr : public IdStringType<PoolQueryAttr>
{
//\TODO maybe ctor with stream can be usefull
+ //\TODO let it throw, let it throw, let it throw.
bool PoolQuery::recover( istream &str, char delim )
{
bool finded_something = false; //indicates some atributes is finded
PoolQueryAttr attribute( attrName );
- MIL << "attribute name: " << attrName << endl;
-
if ( attribute==PoolQueryAttr::repoAttr )
{
addRepo( attrValue );
setEdition(Edition(attrValue), rel);
}
+ else if ( attribute == PoolQueryAttr::complexAttr )
+ {
+ try
+ {
+ _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
+ }
+ catch ( const Exception & err )
+ {
+ WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
+
+ }
+ }
else if ( attribute==PoolQueryAttr::noAttr )
{
WAR << "empty attribute name" << endl;
string s = attrName;
str::replaceAll( s,"_",":" );
SolvAttr a(s);
- addAttribute(a,attrValue);
+ if ( a == SolvAttr::name || isDependencyAttribute( a ) )
+ {
+ Capability c( attrValue );
+ CapDetail d( c );
+ if ( d.isVersioned() )
+ addDependency( a, d.name().asString(), d.op(), d.ed() );
+ else
+ addDependency( a, attrValue );
+ }
+ else
+ addAttribute( a, attrValue );
}
} while ( true );
}
}
+ for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
+ {
+ str << "complex: "<< it->serialize() << delim;
+ }
+
//separating delim - protection
str << delim;
}
ostream & operator<<( ostream & str, const PoolQuery & obj )
{ return str << obj.asString(); }
- bool PoolQuery::operator==(const PoolQuery& a) const
- {
- if( flags() != a.flags() )
- return false;
- if( a.matchWord() != matchWord())
- return false;
- if( a.requireAll() != requireAll() )
- return false;
- if ( a.kinds() != kinds() )
- return false;
- if ( a.repos() != repos() )
- return false;
- if(a.edition() != edition())
- return false;
- if(a.editionRel() != editionRel())
- return false;
+ std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
+ { return dumpRange( str << obj, obj.begin(), obj.end() ); }
- return true;
- }
+ bool PoolQuery::operator==( const PoolQuery & rhs ) const
+ { return *_pimpl == *rhs._pimpl; }
///////////////////////////////////////////////////////////////////
namespace detail
{
const AttrMatchData & matchData( *mi );
sat::LookupAttr q( matchData.attr, inSolvable );
- if ( matchData.attrMatcher ) // an empty searchstring matches always
- q.setAttrMatcher( matchData.attrMatcher );
+ if ( matchData.strMatcher ) // an empty searchstring matches always
+ q.setStrMatcher( matchData.strMatcher );
if ( ! q.empty() ) // there are matches.
{
// Repo restriction:
sat::Pool satpool( sat::Pool::instance() );
+
for_( it, query_r->_repos.begin(), query_r->_repos.end() )
{
Repository r( satpool.reposFind( *it ) );
if ( r )
_repos.insert( r );
+ else
+ _neverMatchRepo = true;
}
+ // _neverMatchRepo: we just need to catch the case that no repo
+ // matched, so we'd interpret the empty list as 'take from all'
+ if ( _neverMatchRepo && ! _repos.empty() )
+ _neverMatchRepo = false;
+
// Kind restriction:
_kinds = query_r->_kinds;
// Edition restriction:
_edition = query_r->_edition;
// Status restriction:
_status_flags = query_r->_status_flags;
- // AttrMatcher
+ // StrMatcher
_attrMatchList = query_r->_attrMatchList;
}
{
sat::LookupAttr q;
+ if ( _neverMatchRepo )
+ return q.end();
+
// Repo restriction:
if ( _repos.size() == 1 )
q.setRepo( *_repos.begin() );
{
const AttrMatchData & matchData( _attrMatchList.front() );
q.setAttr( matchData.attr );
- if ( matchData.attrMatcher ) // empty searchstring matches always
- q.setAttrMatcher( matchData.attrMatcher );
+ if ( matchData.strMatcher ) // empty searchstring matches always
+ q.setStrMatcher( matchData.strMatcher );
}
else // more than 1 attr (but not all)
{
{
const AttrMatchData & matchData( *mi );
sat::LookupAttr q( matchData.attr, inSolvable );
- if ( matchData.attrMatcher ) // an empty searchstring matches always
- q.setAttrMatcher( matchData.attrMatcher );
+ if ( matchData.strMatcher ) // an empty searchstring matches always
+ q.setStrMatcher( matchData.strMatcher );
if ( ! q.empty() ) // there are matches.
{
private:
/** Repositories include in the search. */
std::set<Repository> _repos;
+ DefaultIntegral<bool,false> _neverMatchRepo;
/** Resolvable kinds to include. */
std::set<ResKind> _kinds;
/** Edition filter. */
Edition _edition;
/** Installed status filter flags. \see PoolQuery::StatusFilter */
int _status_flags;
- /** AttrMatcher per attribtue. */
+ /** StrMatcher per attribtue. */
AttrMatchList _attrMatchList;
};
///////////////////////////////////////////////////////////////////