ref: refs/heads/master
commit dd2cdca2c661bf98e4a5b5535409764324239d3f
Author: Michael Andres <ma(a)suse.de>
Date: Fri May 29 20:20:50 2009 +0200
Improve PoolQuery to allow queries on dependencies. (bnc #475682)
---
tests/zypp/PoolQuery_test.cc | 87 +++++++++++++++++++-
zypp/PoolQuery.cc | 192 +++++++++++++++++++++++++++++++++++++++--
zypp/PoolQuery.h | 118 ++++++++++++++++++--------
3 files changed, 350 insertions(+), 47 deletions(-)
diff --git a/tests/zypp/PoolQuery_test.cc b/tests/zypp/PoolQuery_test.cc
index 933a389..96372db 100644
--- a/tests/zypp/PoolQuery_test.cc
+++ b/tests/zypp/PoolQuery_test.cc
@@ -35,6 +35,24 @@ struct PrintAndCount
unsigned _count;
};
+void dumpQ( std::ostream & str, const PoolQuery & q, bool verbose = true )
+{
+ q.begin();
+ str << q << endl;
+ unsigned nc = 0;
+ if ( 1 )
+ {
+ for_( it, q.begin(), q.end() )
+ {
+ ++nc;
+ if ( verbose )
+ str << it << endl;
+ }
+ str << "--> MATCHES: " << nc << endl;
+ }
+}
+
+
#if 0
BOOST_AUTO_TEST_CASE(pool_query_experiment)
{
@@ -58,7 +76,6 @@ BOOST_AUTO_TEST_CASE(pool_query_experiment)
}
#endif
-
/////////////////////////////////////////////////////////////////////////////
// 0xx basic queries
/////////////////////////////////////////////////////////////////////////////
@@ -650,3 +667,71 @@ BOOST_AUTO_TEST_CASE(pool_query_equal)
BOOST_CHECK(q==q4);
BOOST_CHECK(q4!=q3);
}
+
+/////////////////////////////////////////////////////////////////////////////
+// Dependency Query
+/////////////////////////////////////////////////////////////////////////////
+
+BOOST_AUTO_TEST_CASE(addDependency)
+{
+ {
+ cout << "****addDependency1****" << endl;
+ PoolQuery q;
+ q.setCaseSensitive( false );
+ q.setMatchSubstring();
+ q.addString( "libzypp" );
+ q.addDependency( sat::SolvAttr::provides, "FOO" ); // ! finds 'perl(CPAN::InfoObj)' 'foO'
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ BOOST_CHECK_EQUAL( q.size(), 12 );
+ }
+ {
+ cout << "****addDependency2****" << endl;
+ PoolQuery q;
+ q.setCaseSensitive( false );
+ q.setMatchSubstring();
+ q.addString( "libzypp" );
+ q.addDependency( sat::SolvAttr::provides, "FOO", Rel::GT, Edition("5.0") );
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ //dumpQ( std::cout, q );
+ BOOST_CHECK_EQUAL( q.size(), 6 );
+ }
+
+ {
+ cout << "****addDependency3****" << endl;
+ PoolQuery q;
+ // includes wine
+ q.addDependency( sat::SolvAttr::provides, "kernel" );
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ //dumpQ( std::cout, q );
+ BOOST_CHECK_EQUAL( q.size(), 12 );
+ }
+ {
+ cout << "****addDependency4****" << endl;
+ PoolQuery q;
+ // no wine
+ q.addDependency( sat::SolvAttr::name, "kernel" );
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ //dumpQ( std::cout, q );
+ BOOST_CHECK_EQUAL( q.size(), 11 );
+ }
+ {
+ cout << "****addDependency5****" << endl;
+ PoolQuery q;
+ // Capability always matches exact
+ q.addDependency( sat::SolvAttr::provides, Capability("kernel") );
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ //dumpQ( std::cout, q );
+ BOOST_CHECK_EQUAL( q.size(), 2 );
+ }
+ {
+ cout << "****addDependency6****" << endl;
+ PoolQuery q;
+ // non dependecy + Capability matches solvable name!
+ q.addDependency( sat::SolvAttr::summary, Capability("kernel") );
+ std::for_each(q.begin(), q.end(), PrintAndCount());
+ //dumpQ( std::cout, q );
+ BOOST_CHECK_EQUAL( q.size(), 0 ); // non dependecy
+ }
+}
+
+
diff --git a/zypp/PoolQuery.cc b/zypp/PoolQuery.cc
index b0715a6..375a349 100644
--- a/zypp/PoolQuery.cc
+++ b/zypp/PoolQuery.cc
@@ -13,7 +13,7 @@
#include <sstream>
#include "zypp/base/Gettext.h"
-#include "zypp/base/Logger.h"
+#include "zypp/base/LogTools.h"
#include "zypp/base/Algorithm.h"
#include "zypp/base/String.h"
#include "zypp/repo/RepoException.h"
@@ -67,6 +67,12 @@ namespace zypp
, 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;
@@ -79,6 +85,84 @@ namespace zypp
typedef std::list<AttrMatchData> AttrMatchList;
+ /////////////////////////////////////////////////////////////////
+ // some Helpers and Predicates
+ /////////////////////////////////////////////////////////////////
+
+ bool isDependencyAttribute( sat::SolvAttr attr_r )
+ {
+ static sat::SolvAttr deps[] = {
+ SolvAttr::provides,
+ SolvAttr::requires,
+ SolvAttr::recommends,
+ SolvAttr::obsoletes,
+ SolvAttr::conflicts,
+ SolvAttr::suggests,
+ SolvAttr::supplements,
+ SolvAttr::enhances,
+ };
+ for_( it, arrayBegin(deps), arrayEnd(deps) )
+ if ( *it == attr_r )
+ return true;
+ return false;
+ }
+
+ /** Whether the current capabilities edition range ovelaps.
+ * Query asserts \a iter_r points to a capability and we
+ * have to check the range only.
+ */
+ struct EditionRangePredicate
+ {
+ EditionRangePredicate( const Rel & op, const Edition & edition )
+ : _range( op, edition )
+ {}
+
+ bool operator()( sat::LookupAttr::iterator iter_r )
+ {
+ CapDetail cap( iter_r.id() );
+ if ( ! cap.isSimple() )
+ return false;
+ if ( cap.isNamed() ) // no range to match
+ return true;
+ return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
+ }
+
+ Edition::MatchRange _range;
+ };
+
+ /** Whether the current Solvables edition is within a given range. */
+ struct SolvableRangePredicate
+ {
+ SolvableRangePredicate( const Rel & op, const Edition & edition )
+ : _range( op, edition )
+ {}
+
+ bool operator()( sat::LookupAttr::iterator iter_r )
+ {
+ return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
+ }
+
+ Edition::MatchRange _range;
+ };
+
+ /** Whether the current capability matches a given one.
+ * Query asserts \a iter_r points to a capability and we
+ * have to check the match only.
+ */
+ struct CapabilityMatchPredicate
+ {
+ CapabilityMatchPredicate( Capability cap_r )
+ : _cap( cap_r )
+ {}
+
+ bool operator()( sat::LookupAttr::iterator iter_r ) const
+ {
+ return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
+ }
+
+ Capability _cap;
+ };
+
} /////////////////////////////////////////////////////////////////
// namespace
///////////////////////////////////////////////////////////////////
@@ -111,6 +195,8 @@ namespace zypp
StrContainer _strings;
/** Raw attributes */
AttrRawStrMap _attrs;
+ /** Uncompiled attributes with predicate. */
+ AttrMatchList _uncompiledPredicated;
/** Sat solver search flags */
Match _flags;
@@ -199,11 +285,7 @@ namespace zypp
// create regex; store in rcstrings; if more strings flag regex;
if (_attrs.empty())
{
- rcstrings = createRegex(_strings, cflags);
- if (_strings.size() > 1) // switch to regex for multiple strings
- cflags.setModeRegex();
- _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
- sat::AttrMatcher( rcstrings, cflags ) ) );
+ ; // A default 'query-all' will be added after all sources are processed.
}
// // ONE ATTRIBUTE
@@ -305,7 +387,50 @@ attremptycheckend:
}
}
- // Check here, whether all involved regex compile.
+ // Now handle any predicated queries
+ if ( ! _uncompiledPredicated.empty() )
+ {
+ StrContainer global;
+ invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
+ for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
+ {
+ if ( it->attrMatcher.flags().mode() == Match::OTHER )
+ {
+ // need to compile:
+ StrContainer joined( global );
+ const std::string & mstr( it->attrMatcher.searchstring() );
+ if ( ! mstr.empty() )
+ joined.insert( mstr );
+
+ cflags = _flags;
+ rcstrings = createRegex( joined, cflags );
+ if ( joined.size() > 1 ) // switch to regex for multiple strings
+ cflags.setModeRegex();
+
+ _attrMatchList.push_back( AttrMatchData( it->attr,
+ sat::AttrMatcher( rcstrings, cflags ),
+ it->predicate ) );
+ }
+ else
+ {
+ // copy matcher
+ _attrMatchList.push_back( *it );
+ }
+ }
+ }
+
+ // If no attributes defined at all, then add 'query all'
+ if ( _attrMatchList.empty() )
+ {
+ cflags = _flags;
+ rcstrings = createRegex( _strings, cflags );
+ if ( _strings.size() > 1 ) // switch to regex for multiple strings
+ cflags.setModeRegex();
+ _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
+ sat::AttrMatcher( rcstrings, cflags ) ) );
+ }
+
+ // Finally check here, whether all involved regex compile.
for_( it, _attrMatchList.begin(), _attrMatchList.end() )
{
it->attrMatcher.compile(); // throws on error
@@ -460,6 +585,12 @@ attremptycheckend:
o << endl;
}
+ o << "predicated: " << endl;
+ for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
+ {
+ o << "* " << *it << endl;
+ }
+
// compiled
o << "last attribute matcher compiled: " << endl;
if ( _attrMatchList.empty() )
@@ -501,18 +632,59 @@ attremptycheckend:
_pimpl->_repos.insert(repoalias);
}
-
void PoolQuery::addKind(const ResKind & kind)
{ _pimpl->_kinds.insert(kind); }
-
void PoolQuery::addString(const string & value)
{ _pimpl->_strings.insert(value); }
-
void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
{ _pimpl->_attrs[attr].insert(value); }
+ void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
+ {
+ switch ( op.inSwitch() )
+ {
+ case Rel::ANY_e: // no additional constraint on edition.
+ addAttribute( attr, name );
+ return;
+
+ case Rel::NONE_e: // will never match.
+ return;
+
+ default: // go and add the predicated query (uncompiled)
+ break;
+ }
+
+ // Match::OTHER indicates need to compile.
+ sat::AttrMatcher matcher( name, Match::OTHER );
+
+ AttrMatchData::Predicate pred;
+ if ( isDependencyAttribute( attr ) )
+ pred = EditionRangePredicate( op, edition );
+ else
+ pred = SolvableRangePredicate( op, edition );
+
+ _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) );
+ }
+
+ void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
+ {
+ CapDetail cap( cap_r );
+ if ( ! cap.isSimple() ) // will never match.
+ return;
+
+ // Matches STRING per default. (won't get compiled!)
+ sat::AttrMatcher matcher( cap.name().asString() );
+
+ AttrMatchData::Predicate pred;
+ if ( isDependencyAttribute( attr ) )
+ pred = CapabilityMatchPredicate( cap_r );
+ else
+ pred = SolvableRangePredicate( cap.op(), cap.ed() );
+
+ _pimpl->_uncompiledPredicated.push_back( AttrMatchData( attr, matcher, pred ) );
+ }
void PoolQuery::setEdition(const Edition & edition, const Rel & op)
{
diff --git a/zypp/PoolQuery.h b/zypp/PoolQuery.h
index b41d775..cd80ffc 100644
--- a/zypp/PoolQuery.h
+++ b/zypp/PoolQuery.h
@@ -209,48 +209,94 @@ namespace zypp
*
* \see sat::SolvAttr
*/
- void addAttribute(const sat::SolvAttr & attr, const std::string & value = "");
-#if 0
- /**
- * Query for dependencies matching a broken down capability.
+ void addAttribute( const sat::SolvAttr & attr, const std::string & value = "" );
+
+ /** \name Filter by dependencies matching a broken down capability <tt>name [op edition]</tt>.
+ *
+ * The capabilities \c name part may be defined as query string
+ * like with \ref addAttribute. Globing and regex are supported.
+ * Global query strings defined by \ref addString are considered.
+ *
+ * So without any <tt>op edition</tt> addDependency behaves the
+ * same as \ref addAttribute. If an edition range is given, matches
+ * are restricted accordingly. Thete are various overloads, so pick
+ * the one you like best.
*
- * The capabilities \c name part may be defined as ordinary query
- * string (\see \ref addAttribute), so globing and regex are supported.
* \code
- * addDependency( sat::SolvAttr::provides, "kde*", Edition("2.0"), Rel::GE );
+ * {
+ * setMatchGlob();
+ * setCaseSensitive( false );
+ * addDependency( sat::SolvAttr::provides, "kde*", Rel::EQ, Edition("2.0") );
+ * addDependency( sat::SolvAttr::provides, "kde*", Edition("2.0") ); // same as above
+ * }
+ * {
+ * setMatchGlob();
+ * setCaseSensitive( false );
+ * addString( "kde*" );
+ * addDependency( sat::SolvAttr::provides, Rel::EQ, Edition("2.0") );// same as above
+ * addDependency( sat::SolvAttr::provides, Edition("2.0") ); // same as above
+ * }
+ * \endcode
+ *
+ * \note Thre's also a version of \ref addDependency provided, that takes a
+ * complete \ref Capability as argument. This always requires an exact match
+ * of the name part (as the resolver would do it).
+ *
+ * This is the list of valid dependency attributes:
+ * \code
+ * SolvAttr::provides
+ * SolvAttr::obsoletes
+ * SolvAttr::conflicts
+ * SolvAttr::requires
+ * SolvAttr::recommends
+ * SolvAttr::suggests
+ * SolvAttr::supplements
+ * SolvAttr::enhances
+ * \endcode
+ *
+ * \note <b>What happens if a non dependency attribute is passed?<\b>
+ * If an edition range is given, it is matched against the matching
+ * solvables edition instead. Without edition range it behaves the
+ * same as \ref addAttribute.
+ *
+ * \code
+ * // Find all packages providing "kernel > 2.0"
+ * addDependency( sat::SolvAttr::provides, "kernel", Rel::GT, Edition("2.0") );
+ *
+ * // // Find all packages named "kernel" and with edition "> 2.0"
+ * addDependency( sat::SolvAttr::name, "kernel", Rel::GT, Edition("2.0") );
* \endcode
- * \throws Exception in case \a attr is not a dependency attribute.
*/
- void addDependency( const sat::SolvAttr & attr, const std::string & name,
- const Edition & edition, const Rel & op = Rel::EQ );
- /** \overload Query provides */
- void addProvides( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::provides, name, edition, op ); }
- /** \overload Query requires */
- void addRequires( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::requires, name, edition, op ); }
- /** \overload Query obsoletes */
- void addObsoletes( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::obsoletes, name, edition, op ); }
- /** \overload Query conflicts */
- void addConflicts( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::conflicts, name, edition, op ); }
- /** \overload Query recommends */
- void addRecommends( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::recommends, name, edition, op ); }
- /** \overload Query suggests */
- void addSuggests( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::suggests, name, edition, op ); }
- /** \overload Query supplements */
- void addSupplements( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::supplements, name, edition, op ); }
- /** \overload Query enhances */
- void addEnhances( const std::string & name, const Edition & edition, const Rel & op = Rel::EQ )
- { addDependency( sat::SolvAttr::enhances, name, edition, op ); }
-
- /** \overload Query taking a \ref Capability (always exact name match) */
+ //@{
+ /** Query <tt>"name|global op edition"</tt>. */
+ void addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition );
+
+ /** \overload Query <tt>"name|global == edition"</tt>. */
+ void addDependency( const sat::SolvAttr & attr, const std::string & name, const Edition & edition )
+ { addDependency( attr, name, Rel::EQ, edition ); }
+
+ /** \overload Query <tt>"name|global"</tt>. */
+ void addDependency( const sat::SolvAttr & attr, const std::string & name )
+ { addDependency( attr, name, Rel::ANY, Edition() ); }
+
+ /** \overload Query <tt>"global op edition"</tt>.*/
+ void addDependency( const sat::SolvAttr & attr, const Rel & op, const Edition & edition )
+ { addDependency( attr, std::string(), op, edition ); }
+
+ /** \overload Query <tt>"global == edition"</tt>. */
+ void addDependency( const sat::SolvAttr & attr, const Edition & edition )
+ { addDependency( attr, std::string(), Rel::EQ, edition ); }
+
+ /** \overload Query <tt>"global"</tt>. */
+ void addDependency( const sat::SolvAttr & attr )
+ { addDependency( attr, std::string(), Rel::ANY, Edition() ); }
+
+ /** \overload Query taking a \ref Capability (always exact name match).
+ * \note If a non dependency attribute is passed, the \ref Capability
+ * will always be matched against the Solvables \c name and \c edition.
+ */
void addDependency( const sat::SolvAttr & attr, Capability cap_r );
-#endif
+ //@}
/**
* Set version condition. This will filter out solvables not matching
--
To unsubscribe, e-mail: zypp-commit+unsubscribe(a)opensuse.org
For additional commands, e-mail: zypp-commit+help(a)opensuse.org