Mailinglist Archive: zypp-devel (230 mails)

< Previous Next >
[zypp-devel] Re: RFC: ZYpp application layer comments
  • From: Jan Kupec <jkupec@xxxxxxx>
  • Date: Thu, 07 Feb 2008 20:21:19 +0100
  • Message-id: <47AB5A2F.2090808@xxxxxxx>
Duncan Mac-Vicar P. wrote:
I would like others (especially Michael) to review it.

I am quoting the blocks of texts from the Wiki, which I would like to focus
the discussion on.

Communication between the YCP application and the C++ package selector
widgets is very limited (almost nonexistent). In particular, the YCP
application cannot create a pool and pass a handle to that pool to the C++
package selector or vice versa.

Thus, for all important objects like pool or similar, there must be a
singleton object for each that can easily be accessed from both the YCP code
(via package bindings) and from the package selectors. Those singleton
objects should live in the app layer.

My guess is, that there will be no need for the applications to
manipulate the Pool directly as long as we have all the other API they
need (the Query, content iterators of Patterns, etc.)


Selectables have a higher level status that is the result of the useful
permutations of the status flags of their resolvables and the fact whether
or
not one resolvable from this selectable (one instance of that package) is
already installed:

Matching Selectable and Resolvable Status and Candidate Handling
The package selectors use the selectable status. They never store any
selectable's status; they always retrieve the status when it is needed. When
the user changes a selectable's status, they set new status and retrieve it
for display so the display and the selectable status are always in sync.

Since selectable don't exist in the libzypp layer, matching a selectable
status to the individual resolvable status flags is done by the app layer
and
vice versa. The app layer also keeps track of the candidate. This is
important when the selectable status is used since some operations (install,
update) implicitly operate on the candidate.

I think this is one of the central parts of the problem we need to solve.

What about merging NameKindProxy with Selectables? I mean to drop the
NameKindProxy and allow a Selectable to have multiple target (installed)
resolvables.

See also this mail from Michael, the second half:
http://lists4.suse.de/yast-devel/2007-06/msg00150.html

I quite agree with Michael there and i came to the same conclusion
recently. I don't mean using Selectables as Pool objects (i don't have
much solver knowledge), but the others, namely: "It would be a good
place to provide convenient status manipulating methods.", installation
candidate handling. Also it would be a good place for a 'contents'
iterator (whatever it would mean from the implementation POV). I guess
this is also consistent with what Klaus says in the other mail [1] in
this thread.

Can this be done? While i know that we want to be able to have multiple
versions of a resolvable to be installed, i don't know why this case
needs to be represented by multiple Selectables instead of one (which
has multiple target resolvables). Would it be harder or even impossible
for the UIs to handle?

As long as the user did not explicitly choose a specific candidate, the app
layer automatically chooses one from the available resolvables. That
automatic choice takes matching architectures and most recent version number
into account.

This is not trivial. Right now the UIs do this choices in some random code
somewhere in the UI, or using the selectable candidate function, which is
now
incomplete. This kind of decision is the same as the solver local policy. So
we have to connect them trough the API somehow. Imagine this something like:

bestCandidate( list_of_candidates, task )

Of course this has to be in Selectable, but it has to be connected to the
local policy, and it depends on the task you want to execute.

Otherwise the UIs will continue breaking things like vendor (the UIs iterate
over a package list and select the higher version instead of the best
candidate according to the system policies ).

I bet we all agree on this, this stuff must be handled in libzypp.

Before we continue to discuss this, let's settle on the term
'selectable' so that we know what we talk about. See my mail
"Selectables and 'candidate'".

Patterns (collections of packages to fulfil a certain task)

This is where the UI <-> library problems starts. What the wiki describes
there is the description of a Selection.

That's just a problem of agreeing on usage of the words. I see no _real_
problem here. The bottom line is, the UIs need to show what's inside a
pattern - libzypp must provide an API to enumerate something to display.
Once we agree on this, the rest is not such a big problem. We don't need
to argue about words (although i agree we should speak as precisely as
the subject requires when discussing technical matters).

Technically, none of those higher level objects has a package content: They
all just have dependencies that typically (but not necessarily) are
satisfied
by packages.

Exactly.

From a user's point of view, however, those higher level objects are nothing
else than containers for packages. Though this is a somewhat simplistic
view,
users typically want to see what is behind a pattern, a patch, or a language
resolvable. This is why each of them should have a mechanism to enumerate
the
packages that belong to them.

This is true, but only if you can live with the true: the mechanism to
enumerate the list of packages is just an algorithm, not a list. It can be
false information.

That is why I tried to start using the term "related packages" instead
of "content".

Again, this is 'just' about words. What we need is the API :O) Let's
have Selectable::contents{Begin,End,Size}(), whatever we put inside.


Now for searching. It was suggested that there should be a class
handling the queries - thus zypp::ui::Query. Based on requirements and
Bubli's (and my own) proposal, i've written the Query.h (see attached):

The user can select any one of those search modes:

* Contains
* Begins with
* Exact match

enum MatchLevel
{
MATCH_ANY_SUBSTRING,
MATCH_WHOLE_WORDS,
MATCH_EXACT_PHRASE,
MATCH_BEGINNING,
MATCH_END
};

void Query::setMatchLevel(const MatchLevel level) { _match_level = level; }

Maybe the MatchLevel should be in the addName() and addAttribute()
methods, not for the whole Query?


* Use wildcards (*, ?)

If the queries will be implemented with regexes, any wildards in the
search strings will be converted to correspondent regex sequences.

* Use regular expression

note the isRegex parameter:

void Query::addName(const std::string & name, bool is_regexp = false);
void addAttribute(const Attribute & attrid, const std::string & value,
bool isRegex = false);


Case sensitivity in all searches can be switched on or off.

void Query::setCaseSensitive(const bool value = true);

====

Another thingy to solve is the combination of several queries, e.g. give
two or three strings, match packages containg ALL of them, or ANY of them.

Some basic degree of this could be provided by:

void setRequireAll(bool require_all = true);

which would serve as AND operator if true, and OR if false to combine
all the conditions added to the Query with addName() and addAttribute()
(or even addDependency()). Not much flexiblity, but the question is also
whether we need more.

====

If you agree, i'll commit the file to svn trunk and we can polish it
there. If it is fundamentally wrong, i'll rewrite it and check with you
agin :O)


A query engine to replace this functionality in the UI should enumerate
(return an iterator to) the selectables that match the given criteria.

Update Problems Filter View
This filter view enumerates those packages that for one reason or the other
could not automatically be updated during a system update. Adding packages
to this list is done by the system update application layer.

And what is the criteria for searching those?

Again, whatever is the answer to this question, the API must be there
somewhere in libzypp, so that the UIs can just use it and not implment
it on their own.


Libzypp/Application Layer/API Proposal

enum Type {
PACKAGE,
PATTERN,
PATCH,
LANGUAGE
}

Why resolvable kind can't be used here? Why the need to duplicate it?

No need to duplicate, it was meant only as a demonstration. Of course we
will use Resolvable::Kind, but maybe it would be nice to have an
enumeration of currently used kinds.


* Create pool iterator (based on the above query as a parameter)

> Pool pool = new Pool (q);

So this is like a pool proxy based on a query? Why not the iterator taking
the
query as a parameter (Michael could comment more?)

I have one concern with the design of the pool based on queries. It means we
have to load the pool data, this will not be bad with the sat solver, but
this is not the same zypper does, as zypper only gets the resolvable data to
be displayed on the screen, without any pool.

Dropped in the actual API proposal, see Query.h in the attachment.


Other API that could be part of the zypp layer is a command oriented api.

If you look what API smart offers to the UIs is a much simpler API, and it is
the same the command line tool offers, and this is quite similar to all
zypper code.

It defines a Command class (install, search, etc)
it defines a abstract interface for callbacks (confirm dialogs, progress,
questions, etc)
The UI simply creates a command and executes it.

This is a much simpler approach, but I think it is needed in addition to the
layer our selector need.

Both packagekit and any app wanting to install a package could benefit from
this.

The is interesting, but i would rather discuss it in a separate thread.
Also it probably something for post 11.0 releases.


[1] http://lists4.suse.de/zypp-devel/2008-02/msg00018.html
/*---------------------------------------------------------------------\
| ____ _ __ __ ___ |
| |__ / \ / / . \ . \ |
| / / \ V /| _/ _/ |
| / /__ | | | | | | |
| /_____||_| |_| |_| |
| |
\---------------------------------------------------------------------*/
/** \file zypp/ui/Query.h
*
*/
#ifndef QUERY_H_
#define QUERY_H_

#include "zypp/ui/Selectable.h"
#include "zypp/sat/SolvAttr.h"


///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
namespace ui
{ /////////////////////////////////////////////////////////////////

/**
* Meta-data query API for user interfaces.
*
* TODO: details, examples.
*/
class Query
{
public:
enum MatchLevel
{
MATCH_ANY_SUBSTRING, //! implemented by e.g. <tt>string::find(value)</tt>
or <tt>regexp '.*value.*'</tt>
MATCH_WHOLE_WORDS, //! impelmented by e.g. <tt>regexp
'.*\bvalue\b.*'</tt>, value either regex-escaped or not
MATCH_EXACT_PHRASE, //! implemented by <tt>string::operator==()</tt> or
<tt>regexp 'value'</tt>
MATCH_BEGINNING, //! find() == 0 or ^value.*
MATCH_END //! .*value$
};

typedef SelectableSet::iterator ResultIterator;
typedef constSelectableSet::iterator constResultIterator;

Query();
~Query();

public:
/**
* Filter by selectable kind.
*
* 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).
*/
void addKind(const Resolvable::Kind kind);

/**
* Filter by selectable name.
*
* \param name what to search for
* \param isRegex is the value a regex?
*/
void addName(const std::string & name, bool isRegex = false);


/**
* Filter by the \a value of any available attribute of selectables.
*
* \note Selectables of a kind not supporting the specified attribute will
* <b>not</b> be returned.
*
* \param attrid attribute identfier (sat::SolvAttr or cache::Attribute
* or something implementation independent)
* \param value what to search for
* \param isRegex is the value a regex?
*/
void addAttribute(const solv::SolvAttr & attrid,
const std::string & value,
bool isRegex = false);

/**
* Filter by Selectable status.
*
* This should cover also plain 'is installed' and 'not installed' statuses.
*
* \param status Selectable status (zypp::ui::Status enum)
*/
void addStatus(const Status status);


/**
* 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
*
* \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);

/** \name Text Attributes Matching Options */
//@{
void setCaseSensitive(const bool value = true);
void setMatchLevel(const MatchLevel level) { _match_level = level; }
void setLocale(const Locale & locale);
//@}

void setRequireAll(const bool require_all = true);

/** selectable iterator over the result */
ResultIterator resultBegin() const;
ResultIterator resultEnd() const;

/** Returns the size of the query result. */
size_t resultSize() const;

/** Low-cost empty query result checker */
bool resultEmpty() const;

// a forEach method consuming a functor can be added here, too

public:
class Impl;
private:
/** Pointer to implementation */
RW_pointer<Impl> _pimpl;
};


/////////////////////////////////////////////////////////////////
} // namespace ui
///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
} // namespace zypp
///////////////////////////////////////////////////////////////////

#endif /*QUERY_H_*/
< Previous Next >