[packagekit] zypper patches + packages ...

Michael Andres ma at suse.de
Wed May 12 08:33:33 PDT 2010

On Tuesday 11 May 2010 18:33:10 Michael Meeks wrote:
> 	Riight; well - all that aside, the code I use is (no doubt)
> unbelievably nasty and is here; it's prolly simpler to review as code:
> http://cgit.freedesktop.org/packagekit/tree/backends/zypp/zypp-utils.cpp#n7

=== @zypp_find_arch_update_item()
(used by zypp_get_package_updates)

Is it intended to ignore repository priorities as well as solver
policies (like allow vendor change) when looking for an update?
Anyway, there's no need to search through the whole pool in
order to find an appropriate item. There's a proxy for this:


Selectable: sort of container offering all PoolItems with the same
name and kind as item_r. Includes (all) installed versions; all
uninstalled versions in a list ordered by repoprioriy, arch,
edition ('best' candidate first). Also status manipulating methods. 
      \ \_ installed: PoolItem(glibc-1.0)   < rpmdb
       \ _ available: PoolItem(glibc-1.1)   < repo-update (prio99)
                      PoolItem(glibc-1.0)   < repo-oss    (prio99)
                      PoolItem(glibc-1.0)   < DVD         (prio99)
                      PoolItem(glibc-2pm.0) < packman     (prio100)

 zypp_find_arch_update_item( ..., zypp::PoolItem item_r )
   if ( ! item_r )
     return zypp::PoolItem();

   // Get the Selectable for item.
   zypp::ui:Selectable::Ptr sel( zypp::ui:Selectable::get( item ) );
                     // (as item_r is valid, (sel != 0) is asserted
Now return one of the predefined items, or lookup the one you like best:

a) return sel->updateCandidateObj(); // The best candidate for update,
// if there is one. 

b) return sel->highestAvailableVersionObj; // Simply the highest
// available version, ignoring priorities and policies.

c) for_( it, sel->availableBegin(), sel->availableEnd() )
     zypp::PoolItem p( *it );
     if ( fits_your_needs( p ) )
       return p;
   return zypp::PoolItem();

But maybe you don't need zypp_find_arch_update_item at all...

=== @zypp_get_package_updates()

- Why excluding the(?) patch repo? Admitted that you ususally have one
patch repo on openSUSE, but that's just because others are probably too lazy 
to offer patches. It's no problem to have more than one repo offering 
patches, and ther's also no rule that would prevent such a repo to ship pure 
package updates at the same time.

 // Why not some smart ptr, reducing the risk of mem leaks?
 std::set<zypp::PoolItem> *pks = new std::set<zypp::PoolItem> ();

 // - zypp::ResPool pool = zypp::ResPool::instance ();
 // Better use the proxy, so you process each (package) name only
 // once. I.e. you iterate Selectables not PoolItems:

 zypp::ResPoolProy selPool( ResPool::instance().proxy() );
 for_( it, selPool.byKindBegin<Package>(), selPool.byKindEnd<Package>() )
    zypp::ui::Selectable::Ptr sel( *it ); // != 0 asserted in ResPoolProy

    // now e.g: 
    zypp::PoolItem candidate( sel->updateCandidateObj() );

    // (!candiate) would mean package is not installed or
    // there is no 'better' package which does not violate
    // any solver policy. There may be higher 'versions'
    // available in low prio repos or from different vendor...
    if ( candidate && ! candidate.status().isLocked() )
      pks->insert (candidate);
 return pks;

=== @zypp_zypp_get_updates()
  std::set<zypp::PoolItem> *candidates = zypp_get_patches ();
  if (!_updating_self) 
    std::set<zypp::PoolItem> *packages = zypp_get_package_updates();

Now you want to exclude all package_updates which are also covered by patches?
(maybe include zypp/IdString.h)

    zypp::IdStringSet covered; // collect names of packages updated by patches
    for_( it, candidates->begin(), candidates->end() )
      zypp::Patch::constPtr patch( it->asKind<zypp::Patch>() );
      if ( ! patch ) 
      zypp::Patch::Contents contents( patch->contents() );
      for_( c, contents.begin(), contents.end() )
        covered.insert( c->ident() );

    // Take the packages not updated by a patch
    for_( it, packages.begin(), packages.end() )
      if ( covered.find( (*it)->ident() ) == covered.end() )
        candidates->insert( *it );

    delete (packages);
  return candidates;

Just a note about line 746:

  for (pki = patch->contents().begin(); pki != patch->contents().end(); pki++) 

You should avoid calling .begin() and .end() on a container returned by value 
by some function call in the loop header. The first and the second 
patch->contents() return 2 different SolvableSets. What you do is:

  Container a = patch->contents();
  Container b = patch->contents();
  for( pki = a.begin(); pki != b.end(), ++pki )

You're lucky if the container type has a common representation for end() 
(a.end() == b.end()). Even if patch->contents() returned a reference, you'd 
need to be sure the implementation does not perform any operation which might 
invalidate previously retrieved iterators.

> 	I was slightly interested in the naming of patches (as PackageKit sees
> them), we appear to return a package name:
> http://cgit.freedesktop.org/packagekit/tree/backends/zypp/pk-backend-zypp.c
> 	based on a zypp::Patch's ->satSolvable() name / ver / etc. details;
> presumably it works well since it's what we did before :-) is there a
> pseudo-package created for a patch ? 

If you call the Solvable a pseudo-package - yes.

libzypp in 10 seconds:

A Solvable is an item with name, version, arch, dependencies (simplified).
Thus Packages as well as Patterns, Patches, Products, even Sourcepackages are 

A PoolItem is a Solvable + its associated status (or fate; keep, install, 
remove, lock).

The satsolver knows about all the Solvables, gets a bunch of job requests 
(lock this, update that,..) and tries to produce some reasonable result. This 
result is then translated into new Solvable fates (PoolItem changes status, 
or call it a transaction).

The ResPool is the place where all PoolItems live.

A Selectable finally is the collection of all PoolItems with the same name. 
It maintains a single status by combining the individual PoolItem fates. 
And it helps translating user requests into solver jobs. If you say 'update 
glibc' the Selectable thinks about how to explain it to the resolver without 
asking you to be more specific, because there are 6 glibcs for two different 
architectures available in 3 repositories....

The ResPoolProxy is the Selectable view to the pool. 
Usually faster and more convenient than iterating over the pool and manually 
collecting the matching Poolitems.

The rest is a bit repo handling, some comments and debug output. ;)

> Advice much appreciated, I have no 
> idea what I'm doing there (as you can probably see by now).

Hmm. Do you feel better or worse now?


    Michael Andres

Key fingerprint = 2DFA 5D73 18B1 E7EF A862  27AC 3FB8 9E3A 27C6 B0E4
Michael Andres             YaST Development            ma at novell.com
SUSE LINUX Products GmbH, GF:  Markus Rex,  HRB 16746 (AG Nuernberg)
Maxfeldstrasse 5, D-90409 Nuernberg, Germany, ++49 (0)911 - 740 53-0

More information about the PackageKit mailing list