Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / PoolQuery.h
index e63ff36..aeb3b4b 100644 (file)
 #ifndef ZYPP_POOLQUERY_H
 #define ZYPP_POOLQUERY_H
 
-#include "base/Regex.h"
-
-#include "zypp/ResKind.h"
-#include "zypp/sat/SolvAttr.h"
-#include "zypp/sat/SolvIterMixin.h"
-#include "zypp/sat/LookupAttr.h"
+#include <iosfwd>
+#include <set>
+#include <map>
 
+#include "zypp/base/Regex.h"
 #include "zypp/base/PtrTypes.h"
 #include "zypp/base/Function.h"
 
-extern "C"
-{
-struct _Dataiterator;
-}
+#include "zypp/sat/SolvIterMixin.h"
+#include "zypp/sat/LookupAttr.h"
+#include "zypp/base/StrMatcher.h"
+#include "zypp/sat/Pool.h"
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
@@ -44,16 +42,57 @@ namespace zypp
    * Meta-data query API. Returns solvables of specified kinds from specified
    * repositories with attributes matching the specified search strings.
    *
-   * TODO: details, examples.
+   * The search strings can be specified via \ref addString() and
+   * \ref addAttribute() methods. String matching type can be set using the
+   * setMatch*() methods. Multiple search strings for a particular attribute
+   * will be combined into a regex (see \ref addString() and
+   * \ref addAttribute() for more details).
+   *
+   * The begin() and end() methods return a PoolQueryIterator returning
+   * \ref sat::Solvable objects which can easily be turned into \ref Resolvable
+   * objects. Additionally, thanx to the \ref sat::SolvIterMixin, a Selectable
+   * and PoolItem iterators are automatically available.
+   *
+   * \note You will sometimes face the problem, that when using the \ref PoolItem
+   * iterator you hit multiple version of the same package, while when using the
+   * \ref ui::Selectable iterator the information which of the available candidates
+   * actually matched got lost. In this case class \ref PoolItemBest may help you.
+   * Use it to pick the best version only.
+   *
+   * <code>
+   * PoolQuery q;
+   * q.addAttribute(sat::SolvAttr::name, "zypp*");
+   * q.addKind(ResKind::package);
+   * q.setMatchGlob();
+   *
+   * for (PoolQuery::Selectable_iterator it = q.selectableBegin();
+   *     it != q.selectableEnd(); ++it)
+   * {
+   *   ui::Selectable::constPtr s = *it;
+   *   // ...
+   * }
+   * </code>
+   *
+   * Performance considerations
+   *
+   * Results of simple queries like those using one string and/or one attribute
+   * and/or one repository are filtered by sat-solver's Dataiterator directly,
+   * and thus it is fast.
+   *
+   * Queries with multiple strings are implemented using regexes. Queries based
+   * on kinds, multiple repos, and multiple attributes are filtered inside
+   * the PoolQuery, so these tend to be slower.
+   *
+   * \see detail::PoolQueryIterator on how to inspect matches in detail.
+   * \see tests/zypp/PoolQuery_test.cc for more examples
+   * \see sat::SolvIterMixin
    */
   class PoolQuery : public sat::SolvIterMixin<PoolQuery, detail::PoolQueryIterator>
   {
   public:
-    typedef std::set<std::string>                           StrContainer;
     typedef std::set<ResKind>                               Kinds;
+    typedef std::set<std::string>                           StrContainer;
     typedef std::map<sat::SolvAttr, StrContainer>           AttrRawStrMap;
-    typedef std::map<sat::SolvAttr, std::string>            AttrCompiledStrMap;
-    typedef std::map<sat::SolvAttr, str::regex>             AttrRegexMap;
 
     typedef detail::PoolQueryIterator                       const_iterator;
     typedef unsigned int                                    size_type;
@@ -66,22 +105,33 @@ namespace zypp
 
     /** Query result accessers. */
     //@{
-    class PoolQueryIterator;
-
-    /** */
+    /**
+     * Compile the query and return an iterator to the result.
+     *
+     * \return An iterator (\ref detail::PoolQueryIterator) returning
+     *         sat::Solvable objects pointing at the beginning of the query result.
+     * \throws sat::MatchInvalidRegexException if the query was about to use a regex which
+     *         failed to compile.
+     *
+     * \note Note that PoolQuery is derived from \ref sat::SolvIterMixin which
+     *       makes PoolItem and Selectable iterators automatically available.
+     * \see \ref sat::SolvIterMixin
+     */
     const_iterator begin() const;
-    /** */
+
+    /** An iterator pointing to the end of the query result. */
     const_iterator end() const;
-    /** */
-    bool empty();
-    /** */
-    size_type size();
+
+    /** Whether the result is empty. */
+    bool empty() const;
+
+    /** Number of solvables in the query result. */
+    size_type size() const;
     //@}
 
     /**
-     * executes the query with the current settings
-     * results are yielded on the callback passed on
-     * construction
+     * Executes the query with the current settings.
+     * Results are yielded via the \a fnc callback.
      */
     void execute(ProcessResolvable fnc);
 
@@ -91,8 +141,7 @@ namespace zypp
      * By default, all kinds will be returned. If addKind() is used,
      * only the specified kinds will be returned (multiple kinds will be ORed).
      *
-     * Pass ResTraits<T>::kind to this method, where T is one of the
-     * \ref Resolvable child classes (e.g. ResTraits<Pattern>::kind).
+     * Pass ResKind constants to this method, (e.g. ResKind::package).
      */
     void addKind(const ResKind & kind);
 
@@ -115,19 +164,46 @@ namespace zypp
       INSTALLED_ONLY = 1,
       UNINSTALLED_ONLY = 2
     };
+
+    /** Return only @System repo packages */
     void setInstalledOnly();
+    /** Return only packages from repos other than @System. */
     void setUninstalledOnly();
+    /** Set status filter directly \see StatusFilter */
     void setStatusFilterFlags( StatusFilter flags );
 
     //@}
 
     /**
-     * 
+     * Add a global query string. The string added via this method is applied
+     * to all query attributes as if addAttribute(..., \value) was called
+     * for all of them.
+     *
+     * This method can be used multiple times in which case the query strings
+     * will be combined (together with strings added via addAttribute()) into
+     * a regex. Searched attribute value will match this regex if <b>any</b>
+     * of these strings will match the value. This can be changed by
+     * (not yet implemented) \ref setRequireAll() method.
      */
     void addString(const std::string & value);
 
     /**
-     * Filter by the \a value of any available solvable attribute.
+     * Filter by the \a value of the specified \a attr attribute. This can
+     * be any of the available solvable attributes.
+     *
+     * This method can be used multiple times with the same \a attr in which
+     * case the query strings will be combined (together with strings added
+     * via addString()) into a regex. Searched attribute value will match
+     * this regex if <b>any</b> of these strings will match the value.
+     * This can be changed by (not yet implemented) \ref setRequireAll()
+     * method.
+     *
+     * \note Though it is possible to use dependency attributes like
+     * \ref Solv::Attr::provides here, note that the query string is
+     * matched against a dependencies \c "name" part only. Any
+     * <tt>"op edition"</tt> part of a \ref Capability is \b not
+     * considered at all. \see \ref addDependency on how to query for
+     * capabilities including edition ranges.
      *
      * \note Solvables of a kind not supporting the specified attribute will
      * <b>not</b> be returned.
@@ -135,38 +211,132 @@ namespace zypp
      *
      * \param attr Attribute identfier. Use sat::Solvattr::* constants
      * \param value What to search for.
+     *
+     * \see sat::SolvAttr
      */
-    void addAttribute(const sat::SolvAttr & attr, const std::string & value = "");
+    void addAttribute( const sat::SolvAttr & attr, const std::string & value = "" );
 
-    /**
-     * Filter by Selectable status.
+    /** \name Filter by dependencies matching a broken down capability <tt>name [op edition]</tt> and/or architecture.
+     *
+     * 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 arch</tt> addDependency behaves the
+     * same as \ref addAttribute. If an edition range is given, matches
+     * are restricted accordingly. There are various overloads, so pick
+     * the one you like best.
+     *
+     * An optional \c arch argument will additionally require the matching
+     * solvable to be of this arch.
+     *
+     * \code
+     * {
+     *   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 should cover also plain 'is installed' and 'not installed' statuses.
+     * 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
      *
-     * \param status Selectable status (zypp::ui::Status enum)
+     * \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
      */
-    //void addStatus(const Status status);
+    //@{
+    /** Query <tt>"name|global op edition"</tt>. */
+    void addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition );
+    /**  \overload also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch );
+
+    /** \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 also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const std::string & name, const Edition & edition, const Arch & arch )
+    { addDependency( attr, name, Rel::EQ, edition, arch ); }
+
+    /** \overload Query <tt>"name|global"</tt>. */
+    void addDependency( const sat::SolvAttr & attr, const std::string & name )
+    { addDependency( attr, name, Rel::ANY, Edition() ); }
+    /**  \overload also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const std::string & name, const Arch & arch )
+    { addDependency( attr, name, Rel::ANY, Edition(), arch ); }
+
+    /** \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 also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const Rel & op, const Edition & edition, const Arch & arch )
+    { addDependency( attr, std::string(), op, edition, arch ); }
+
+    /** \overload Query <tt>"global == edition"</tt>. */
+    void addDependency( const sat::SolvAttr & attr, const Edition & edition )
+    { addDependency( attr, std::string(), Rel::EQ, edition ); }
+    /**  \overload also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const Edition & edition, const Arch & arch )
+    { addDependency( attr, std::string(), Rel::EQ, edition, arch ); }
+
+    /** \overload Query <tt>"global"</tt>. */
+    void addDependency( const sat::SolvAttr & attr )
+    { addDependency( attr, std::string(), Rel::ANY, Edition() ); }
+    /**  \overload also restricting architecture */
+    void addDependency( const sat::SolvAttr & attr, const Arch & arch )
+    { addDependency( attr, std::string(), Rel::ANY, Edition(), arch ); }
+
+    /** \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 );
+    //@}
 
     /**
-     * Add dependency filter.
-     *
-     * \param dtype   depenedcy type
-     * \param name    depenency name
-     * \param edition edition for a versioned dependency
-     * \param rel     operand for a versioned dependency
+     * Set version condition. This will filter out solvables not matching
+     * <tt>solvableEdition \a op \a edition</tt>.
      *
-     * \todo maybe a isRegexp bool as in addName() for the name parameter would
-     *       be handy here as well.
-     * \todo add more addDependecy() variants
-     *//*
-    void addDependency(const Dep & dtype,
-                       const std::string & name,
-                       const Edition & edition = Edition(),
-                       const Rel & rel = Rel::EQ);
-*/
-
+     * \param edition Edition to look for.
+     * \param op      Found-wanted relation operator.
+     */
+    void setEdition(const Edition & edition, const Rel & op = Rel::EQ);
 
-    /** \name Text Matching Options */
+    /** \name Text Matching Options
+     * \note The implementation treats an empty search string as
+     * <it>"match always"</it>. So if you want to actually match
+     * an empty value, try <tt>( "^$", setMatchRegex )</tt>.
+     */
     //@{
     /**
      * Turn case sentitivity on or off (unsets or sets \ref SEARCH_NOCASE flag).
@@ -175,7 +345,17 @@ namespace zypp
      *
      * \param value Whether to turn the case sensitivity on (default) or off.
      */
-    void setCaseSensitive(const bool value = true);
+    void setCaseSensitive( bool value = true );
+
+    /**
+     * If set (default), look at the full path when searching in filelists.
+     * Otherwise just match the the basenames.
+     * \see \ref Match::FILES
+     */
+    void setFilesMatchFullPath( bool value = true );
+    /** \overload */
+    void setFilesMatchBasename( bool value = true )
+    { setFilesMatchFullPath( !value ); }
 
     /** Set to match exact string instead of substring.*/
     void setMatchExact();
@@ -190,12 +370,14 @@ namespace zypp
     //void setLocale(const Locale & locale);
     //@}
 
-
     /**
-     * Require that all of the values set by addString, addAttribute, addDep
-     * match the values of respective attributes. 
+     * Require that all of the values set by addString or addAttribute
+     * match the values of respective attributes.
+     *
+     * \todo doesn't work yet, don't use this function
      */
-    void setRequireAll(const bool require_all = true);
+    void setRequireAll( bool require_all = true );
+
 
     /** \name getters */
     //@{
@@ -213,20 +395,36 @@ namespace zypp
 
     const StrContainer & repos() const;
 
+    const Edition edition() const;
+    const Rel editionRel() const;
+
+    /**
+     * returns true if search is case sensitive
+     */
     bool caseSensitive() const;
 
+    /** Whether searching in filelists looks at the full path or just at the basenames. */
+    bool filesMatchFullPath() const;
+    /** \overload */
+    bool filesMatchBasename() const
+    { return !filesMatchFullPath(); }
+
     bool matchExact() const;
     bool matchSubstring() const;
     bool matchGlob() const;
     bool matchRegex() const;
-    /**
-     * Returns currently used string matching type.
-     * \see satsolver/repo.h
-     */
-    int  matchType() const;
-
     bool matchWord() const;
 
+    /** Returns string matching mode as enum.
+     * \see \ref Match::Mode
+     */
+    Match::Mode matchMode() const
+    { return flags().mode(); }
+
+    /**
+     * Whether all values added via addString() or addAttribute() are required
+     * to match the values of the respective attributes.
+     */
     bool requireAll() const;
 
     StatusFilter statusFilterFlags() const;
@@ -264,19 +462,22 @@ namespace zypp
     // low level API
 
     /**
-     * Free function to set the satsolver repo search
+     * Free function to get libsolv repo search
      * flags.
      *
-     * \see SEARCH_STRINGMASK
-     * \see SEARCH_STRING
-     * \see SEARCH_SUBSTRING
-     * \see SEARCH_GLOB
-     * \see SEARCH_REGEX
-     * \see SEARCH_NOCASE
-     * \see SEARCH_NO_STORAGE_SOLVABLE
+     * \see \ref Match
      */
-    void setFlags(int flags);
+    Match flags() const;
 
+    /**
+     * Free function to set libsolv repo search
+     * flags.
+     *
+     * \see \ref Match
+     */
+    void setFlags( const Match & flags );
+
+  public:
     class Impl;
   private:
     /** Pointer to implementation */
@@ -287,19 +488,25 @@ namespace zypp
   /** \relates PoolQuery Stream output. */
   std::ostream & operator<<( std::ostream & str, const PoolQuery & obj );
 
-
+  /** \relates PoolQuery Detailed stream output. */
+  std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj );
 
   ///////////////////////////////////////////////////////////////////
   namespace detail
   { /////////////////////////////////////////////////////////////////
 
+  class PoolQueryMatcher;
 
   ///////////////////////////////////////////////////////////////////
   //
   //  CLASS NAME : PoolQuery::PoolQueryIterator
   //
-  /**
-   * 
+  /** \ref PoolQuery iterator as returned by \ref PoolQuery::begin.
+   *
+   * The \ref PoolQueryIterator visits sat::Solavables that do contain matches.
+   *
+   * But it also provides an iterator by itself, to allow a detailed inspection of
+   * the individual attribute matches within the current Solvable.
    */
   class PoolQueryIterator : public boost::iterator_adaptor<
     PoolQueryIterator                  // Derived
@@ -309,77 +516,106 @@ namespace zypp
     , const sat::Solvable              // Reference
   >
   {
-  public:
-    PoolQueryIterator();
-
-    PoolQueryIterator(const PoolQueryIterator &);
-
-    explicit
-    PoolQueryIterator( const sat::LookupAttr::iterator & val_r )
-    { this->base_reference() = val_r; }
-
-    ~PoolQueryIterator();
-
-    PoolQueryIterator & operator=( const PoolQueryIterator & rhs );
-
-  private:
-    friend class boost::iterator_core_access;
-    friend class PoolQuery::Impl;
-
-    PoolQueryIterator(
-        scoped_ptr< ::_Dataiterator> & dip_r,
-        const PoolQuery::Impl * pqimpl);
-
-    const sat::Solvable dereference() const
-    {
-      return _sid ? sat::Solvable(_sid) : sat::Solvable::noSolvable;
-    }
-
-    void increment();
-
-    bool matchSolvable();
-
-  private:
-    /** current matching solvable id */
-    int _sid;
-    /** whether there is a next solvable to check */
-    bool _has_next;
-    /** whether to do text matching on our own (true) or the Dataiterator already did it */
-    bool _do_matching;
-
-    /** \name Query Data
-     * Depending on whether regexes are used in the search either \ref _str or
-     * \ref _regex (or either _attrs_str or _attrs_regex respectively) are used.
-     */
-    //@{
-
-    /** string matching option flags */
-    int _flags;
-    /** global query string compiled */
-    std::string _str;
-    /** global query compiled regex */
-    str::regex _regex;
-    /** Attribute to string map holding per-attribute query strings (compiled) */
-    PoolQuery::AttrCompiledStrMap _attrs_str;
-    /** Attribute to regex map holding per-attribute compiled regex */
-    PoolQuery::AttrRegexMap _attrs_regex;
-    /** Set of repository names include in the search. */
-    PoolQuery::StrContainer _repos;
-    /** Set of solvable kinds to include in the search. */
-    PoolQuery::Kinds _kinds;
-    /** Installed status filter flags. \see PoolQuery::StatusFilter */
-    int _status_flags;
-    //@}
-
-    /** used to copy current iterator in order to forward check for next attributes */
-    sat::LookupAttr::iterator _tmpit;
+      typedef std::vector<sat::LookupAttr::iterator> Matches;
+    public:
+      typedef Matches::size_type size_type;
+      typedef Matches::const_iterator matches_iterator;
+    public:
+      /** Default ctor is also \c end.*/
+      PoolQueryIterator()
+      {}
+
+      /** \Ref PoolQuery ctor. */
+      PoolQueryIterator( const shared_ptr<PoolQueryMatcher> & matcher_r )
+      : _matcher( matcher_r )
+      { increment(); }
+
+      /** \name Detailed inspection of attribute matches within the current Solvable.
+       *
+       * The \ref matches_iterator visits all attribute matches within the current Solvable,
+       * providing a \ref sat::LookupAttr::iterator pointing to attribute. While a
+       * \ref matches_iterator itself becomes invalid if the PoolQueryIterator is advanced,
+       * the \ref sat::LookupAttr::iterator it pointed to stays valid, even after the query
+       * ended.
+       *
+       * \code
+       * // Setup query for "libzypp"  in name or requires:
+       * PoolQuery q;
+       * q.addString( "libzypp" );
+       * q.setMatchSubstring();
+       * q.setCaseSensitive( false );
+       * q.addAttribute( sat::SolvAttr::name );
+       * q.addDependency( sat::SolvAttr::requires );
+       *
+       * // Iterate the result:
+       * for_( solvIter, q.begin(), q.end() )
+       * {
+       *   sat::Solvable solvable( *solvIter );
+       *   cout << "Found matches in " << solvable << endl;
+       *   if ( verbose )
+       *     for_( attrIter, solvIter.matchesBegin(), solvIter.matchesEnd() )
+       *     {
+       *       sat::LookupAttr::iterator attr( *attrIter );
+       *       cout << "    " << attr.inSolvAttr() << "\t\"" << attr.asString() << "\"" << endl;
+       *     }
+       * }
+       *
+       *
+       * Found matches in PackageKit-0.3.11-1.12.i586(@System)
+       *    solvable:requires        "libzypp.so.523"
+       * Found matches in libqdialogsolver1-1.2.6-1.1.2.i586(@System)
+       *    solvable:requires        "libzypp.so.523"
+       *    solvable:requires        "libzypp >= 5.25.3-0.1.2"
+       * Found matches in libzypp-5.30.3-0.1.1.i586(@System)
+       *    solvable:name            "libzypp"
+       * Found matches in libzypp-testsuite-tools-4.2.6-8.1.i586(@System)
+       *    solvable:name            "libzypp-testsuite-tools"
+       *    solvable:requires        "libzypp.so.523"
+       * ...
+       * \endcode
+       */
+      //@{
+      /** \c False unless this is the \c end iterator. */
+      bool matchesEmpty() const                        { return ! _matcher; }
+      /** Number of attribute matches. */
+      size_type matchesSize() const            { return matches().size(); }
+      /** Begin of matches. */
+      matches_iterator matchesBegin() const    { return matches().begin(); }
+      /** End of matches. */
+      matches_iterator matchesEnd() const      { return matches().end(); }
+      //@}
+
+    private:
+      friend class boost::iterator_core_access;
+
+      sat::Solvable dereference() const
+      { return base_reference().inSolvable(); }
+
+      void increment();
+
+    private:
+      const Matches & matches() const;
+
+    private:
+      shared_ptr<PoolQueryMatcher> _matcher;
+      mutable shared_ptr<Matches>  _matches;
   };
   ///////////////////////////////////////////////////////////////////
 
+  /** \relates PoolQueryIterator Stream output. */
+  inline std::ostream & operator<<( std::ostream & str, const PoolQueryIterator & obj )
+  { return str << obj.base(); }
+
+  /** \relates PoolQueryIterator Detailed stream output. */
+  std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj );
+
   ///////////////////////////////////////////////////////////////////
   } //namespace detail
   ///////////////////////////////////////////////////////////////////
 
+  inline detail::PoolQueryIterator PoolQuery::end() const
+  { return detail::PoolQueryIterator(); }
+
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////