[Mageia-sysadm] [419] Import cleaned perl-URPM

root at mageia.org root at mageia.org
Fri Feb 4 14:43:09 CET 2011


Revision: 419
Author:   dmorgan
Date:     2011-02-04 14:41:50 +0100 (Fri, 04 Feb 2011)
Log Message:
-----------
Import cleaned perl-URPM

Added Paths:
-----------
    rpm/perl-URPM/
    rpm/perl-URPM/trunk/
    rpm/perl-URPM/trunk/.perl_checker
    rpm/perl-URPM/trunk/ChangeLog
    rpm/perl-URPM/trunk/MANIFEST
    rpm/perl-URPM/trunk/META.yml
    rpm/perl-URPM/trunk/Makefile.PL
    rpm/perl-URPM/trunk/NEWS
    rpm/perl-URPM/trunk/README
    rpm/perl-URPM/trunk/URPM/
    rpm/perl-URPM/trunk/URPM/.perl_checker
    rpm/perl-URPM/trunk/URPM/Build.pm
    rpm/perl-URPM/trunk/URPM/Query.pm
    rpm/perl-URPM/trunk/URPM/Resolve.pm
    rpm/perl-URPM/trunk/URPM/Signature.pm
    rpm/perl-URPM/trunk/URPM.pm
    rpm/perl-URPM/trunk/URPM.xs
    rpm/perl-URPM/trunk/t/
    rpm/perl-URPM/trunk/t/00prepare.t
    rpm/perl-URPM/trunk/t/buggy_synthesis.cz
    rpm/perl-URPM/trunk/t/empty_synthesis.cz
    rpm/perl-URPM/trunk/t/fatal.t
    rpm/perl-URPM/trunk/t/parse.t
    rpm/perl-URPM/trunk/t/pod.t
    rpm/perl-URPM/trunk/t/rpmdb.t
    rpm/perl-URPM/trunk/t/sort_graph.t
    rpm/perl-URPM/trunk/t/synthesis.t
    rpm/perl-URPM/trunk/t/test-rpm.spec
    rpm/perl-URPM/trunk/typemap

Added: rpm/perl-URPM/trunk/.perl_checker
===================================================================
--- rpm/perl-URPM/trunk/.perl_checker	                        (rev 0)
+++ rpm/perl-URPM/trunk/.perl_checker	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,2 @@
+Compress::Zlib
+File::Path

Added: rpm/perl-URPM/trunk/ChangeLog
===================================================================
--- rpm/perl-URPM/trunk/ChangeLog	                        (rev 0)
+++ rpm/perl-URPM/trunk/ChangeLog	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,4159 @@
+2010-07-23 02:43  
+
+	* - fix deferencement on hash (instead hashref), warning triggered
+	  by perl 5.12
+
+2010-04-23 16:06  
+
+	* only print debug message if debug callback is defined
+
+2010-04-23 15:40  
+
+	* 3.35
+
+2010-04-23 15:39  
+
+	* honour search medias when using --auto-select
+
+2010-03-23 15:48  
+
+	* 3.34.1
+
+2010-03-23 15:47  
+
+	* check selected packages for unsatisfied requires when a promoted
+	  package is backtracked and no replacement is found
+	  
+	  (#57224, Anssi Hannula)
+
+2010-03-23 15:47  
+
+	* 3.34
+
+2010-02-24 11:01  
+
+	* adjust rpm.org/rpm5.org detection code
+	  
+	  It used to assume that rpm.org had version numbers < 4.7, but
+	  it's
+	  no longer true with rpm 4.8 being released. Test against 5.0
+	  since
+	  rpm5.org releases started at 5.0
+
+2010-02-12 15:58  
+
+	* check for conflicting selected packages before selecting a
+	  package
+	  
+	  check for conflicting selected packages before selecting a
+	  package
+	  instead of after selecting it, to avoid having to unselect
+	  package
+	  in case of conflict (which incorrectly unselected packages with
+	  unsatisfied dependencies as well, making the following
+	  backtrack_selected
+	  call behave wrongly as it simply noticed that the package is no
+	  longer
+	  required)
+	  
+	  Here's the second patch again, now with the function comment
+	  updated
+	  and added _remove_all_rejected_from() call so that prerejections
+	  are
+	  still cleared (this was previously called from the
+	  removed disable_selected() call). Testsuites pass.
+	  
+	  Patch by Anssi Hannula, fixes #57224
+
+2009-10-05 09:48  
+
+	* 3.33
+
+2009-10-03 15:18  
+
+	* Improve previous fix
+
+2009-10-03 14:56  
+
+	* fix lookup of existing pubkeys (#53710)
+
+2009-08-10 14:37  
+
+	* update NEWS for 3.32
+
+2009-08-10 14:37  
+
+	* 3.32
+
+2009-08-10 14:37  
+
+	* comment out unused code
+
+2009-08-10 14:37  
+
+	* use set_rejected_and_compute_diff_provides for package removal
+	  
+	  Patch by Anssi Hannula, fixes bug #52667
+	  
+	  k1-1 provides k, but not k1-2
+	  l-1 and l-2 requires k
+	  m-1 requires k but not m-2
+	  n requires m
+	  
+	  User has l-1, m-1, n-1, k1-1.
+	  
+	  There is only one upgrade path:
+	  k1-1 -> k1-2
+	  m-1 -> m-2
+	  removal of l-1
+	  
+	  When transaction is created with all of them (e.g. what
+	  --auto-select does
+	  first), the path is resolved correctly.
+	  However, when the upgrade is triggered with the upgrade of k1,
+	  and l is in RPM
+	  db before n, resolving proceeds as follows:
+	  1. k1 selected and old version rejected
+	  2. l is promoted
+	  3. m is promoted
+	  4. l-2 is therefore selected
+	  5. no packages are found for k (as k1-1 was rejected in step 1)
+	  6. backtrack_selected calls resolve_rejected to reject the chain
+	  7. rejection process rejects l, m, n
+	  8. m-2 is selected because of step 3
+	  End result: n is wrongly removed.
+	  
+	  Therefore, when using --auto-select (with --split-length 1
+	  --split-level 1 in
+	  this small case, to force splitting) to trigger the upgrade, the
+	  early resolve
+	  is done correctly, but the first splitted transaction ("rpms
+	  sorted by
+	  dependencies" has k1 and m separately, so split is tried) tries
+	  to remove n and
+	  URPM fallbacks to single big transaction.
+	  
+	  In reverse, when using "urpmi k1" to trigger the upgrade, urpmi
+	  asks user
+	  confirmation for n removal, but the transaction is created with
+	  both k1 and m
+	  ("rpms sorted by dependencies" has k1+m, so they are put in same
+	  transaction),
+	  thus triggering the correct behaviour and n is not really removed
+	  after all,
+	  even if user agreed to it.
+	  
+	  Attached patch fixes this by switching backtrack_selected() to
+	  use
+	  set_rejected_and_compute_diff_provides() for package removal
+	  instead of
+	  resolve_rejected_(). The code already contained a comment
+	  indicating that
+	  diff_provides code should be applied.
+	  The patch introduces no regression in the urpmi and perl-URPM
+	  testsuites.
+
+2009-08-05 20:24  
+
+	* Obey options (keep, nodeps) when unselecting current package in
+	  the case
+	  that was added in 3.31 (Anssi Hannula). In a simple mistake,
+	  %options was
+	  not passed to backtrack_selected.
+
+2009-08-05 20:17  
+
+	* remove extra newline from NEWS
+
+2009-08-05 11:15  
+
+	* remove no longer used SPEC_VERIFY constant
+
+2009-08-04 16:47  
+
+	* disttag & distepoch isn't utf8…
+
+2009-08-04 16:28  
+
+	* cast (es-s) to U32 (as the hv_fetch prototype expects) rather
+	  than casting strlen(s) to signed
+
+2009-07-28 16:15  
+
+	* 3.31
+
+2009-07-28 16:15  
+
+	* we need to link with rpmbuild with rpm 4.6
+
+2009-07-28 13:16  
+
+	* update NEWS file
+
+2009-07-28 13:16  
+
+	* add a backtrack entry "conflicts" for avoided packages in
+	  backtrack_selected
+	  
+	  Patch from Anssi Hannula, fixes part of bug #52153
+
+2009-07-28 13:15  
+
+	* do not try to promote to an older package
+	  
+	  Patch by Anssi Hannula, fixes bug #52460
+	  
+	  When searching for possible promotions, _handle_diff_provides()
+	  allows
+	  downgrade as well as upgrade.
+	  
+	  However, downgrade is not currently supported, and will fail
+	  early in
+	  _no_more_recent_installed_and_providing(), called from
+	  resolve_requested__no_suggests_().
+	  
+	  As no backtracking is done for early failures in this function
+	  (should it be?
+	  dunno), the promotion gets forgotten and a failing transaction
+	  will occur.
+	  
+	  Simple fix is to only allow upgrade before doing the promotion.
+	  Patch attached.
+	  It introduces no regressions in urpmi or perl-URPM testsuite.
+
+2009-07-28 13:15  
+
+	* unselect current package if an avoided package is already
+	  selected
+	  
+	  Patch by Anssi Hannula, fixes bug #52145
+	  
+	  If package 'a' Conflicts on 'b', and user (or a dependency chain)
+	  tries to
+	  install both at the same time, perl-URPM will only detect the
+	  conflict if
+	  package 'a' gets selected first (this depends on hdlist order),
+	  as
+	  _set_rejected_from is only called in one direction from
+	  _handle_conflicts and
+	  it does not detect that a package it is about to reject_from is
+	  already
+	  selected.
+	  
+	  This bug currently causes a failure in urpmi
+	  handle-conflict-deps2 testcase.
+	  
+	  This commit checks if avoided package is already selected, and
+	  unselects
+	  current package in such a case
+
+2009-07-28 13:15  
+
+	* move part of _handle_conflicts to _handle_conflicts_with_selected
+	  
+	  Patch by Anssi Hannula, first step toward fixing bug #52145
+	  
+	  If package 'a' Conflicts on 'b', and user (or a dependency chain)
+	  tries to
+	  install both at the same time, perl-URPM will only detect the
+	  conflict if
+	  package 'a' gets selected first (this depends on hdlist order),
+	  as
+	  _set_rejected_from is only called in one direction from
+	  _handle_conflicts and
+	  it does not detect that a package it is about to reject_from is
+	  already
+	  selected.
+	  
+	  This patch moves part of _handle_conflicts to
+	  _handle_conflicts_with_selected
+	  to be called before dependencies get added, needed by next patch
+
+2009-07-28 13:14  
+
+	* _handle_conflicts: check all provides for conflicts, not just
+	  package name
+	  
+	  Patch by Anssi Hannula, fixes bug #52135
+	  
+	  If package a has "Conflicts: x" and b has "Provides: x",
+	  installing both at the
+	  same time creates a failing transaction (instead of producing the
+	  "cannot
+	  install a (or b), continue?") as perl-URPM does not detect the
+	  conflict, as it
+	  just checks the conflicts on the package name (it does the
+	  correct thing with
+	  installed packages, though).
+	  
+	  _handle_conflicts: call _set_rejected_from if any provides match
+	  the conflict,
+	  instead of just package name
+
+2009-07-28 13:13  
+
+	* keep psel/promote info and remove deadlocked pkg instead of
+	  aborting upgrade
+	  
+	  Patch from Anssi Hannula, fixes bug #52105
+	  
+	  lib64gcj9 has to be removed (conflicts), therefore so does
+	  libgcj9-src (x86_64)
+	  that depends on it. Installed java-1.5.0-gcj-src depends on
+	  libgcj9-src, so
+	  perl-URPM tries to promote the i586 libgcj9-src for it. However,
+	  strict_arch
+	  check prohibits changing the arch, so it falls back to
+	  backtracking.
+	  Backtracking finds libgcj9-src again and tries to select it;
+	  however, it drops
+	  $dep->{psel} and $dep->{promote}, so when it fails again,
+	  perl-URPM does not
+	  know java-1.5.0-gcj-src should also be removed due to the failed
+	  promotion.
+	  
+	  This patch changes the code in backtrack_selected in two ways:
+	  
+	  1) When a replacement package is found, keep {promote} and {psel}
+	  info, so that
+	  when backtrack_selected is run the second time it correctly
+	  handles the failed
+	  promotion.
+	  2) When such a replacement fails as well and the deadlock
+	  protection is
+	  triggered, do not switch to keep mode for the package that caused
+	  the promotion
+	  (it would unselect all the packages involved in the update that
+	  caused the
+	  promotion). Instead proceed to remove it as usual.
+	  
+	  The patch introduces no failures on the urpmi testsuite.
+
+2009-07-28 13:12  
+
+	* keep track of sources for obsoleted/removed levels
+	  
+	  Patch by Anssi Hannula, fixes bug #50666
+	  
+	  removed/obsoleted levels are set in set_rejected() when a package
+	  is rejected
+	  (i.e. removed) or a rejection reason is added. They keep track on
+	  whether the
+	  package is removed and/or obsoleted.
+	  
+	  When the package has both flags and one of the rejection reasons
+	  is removed by
+	  _remove_rejected_from(), appropriate flags do not get removed.
+	  
+	  The case I encountered: the package is set for removal when a
+	  package it
+	  depends on fails upgrade due to unsatisfied dependency and has to
+	  be removed
+	  (backtrack_selected => resolve_rejected, causing removed=1), and
+	  the package is
+	  then promoted (causing obsoleted=1). However, the promotion fails
+	  due to the
+	  same unsatisfied dependency and backtrack_selected =>
+	  disable_selected_and_unrequested_dependencies => disable_selected
+	  =>
+	  _remove_all_rejected_from => _remove_rejected_from gets called.
+	  This removes
+	  the latter rejection reason, but leaves flags, including the now
+	  wrong
+	  obsoleted=1. Thus the package is not explicitely removed as an
+	  obsoletion is
+	  assumed, therefore failing the transaction.
+
+2009-07-27 12:42  
+
+	* use pkg-config for rpm 4.x too
+
+2009-07-27 12:41  
+
+	* remove unused variable
+
+2009-07-26 16:07  
+
+	* rephrase wording, only support for querying %disttag & %distepoch
+	  so far, no support
+	  for using %distepoch i version comparisions yet...
+
+2009-07-26 16:06  
+
+	* add support for %disttag & %distepoch
+
+2009-07-26 08:36  
+
+	* just use (void) rather than assign rpmtsFree() since it seems to
+	  cause crashy behaviour certain places...
+
+2009-07-26 08:07  
+
+	* bumping version was forgotten for 3.30 release, might as well
+	  bump it up to
+	  3.31 now for next release…
+
+2009-07-26 08:05  
+
+	* update changelog regarding rpm5
+
+2009-07-26 07:08  
+
+	* oops, put back line that accidentally got removed in the previous
+	  commit…
+
+2009-07-26 06:50  
+
+	* enable and fix additional (-Wextra) warnings
+
+2009-07-26 06:38  
+
+	* fix gcc warnings about values not being used
+
+2009-07-26 06:23  
+
+	* * clean out compatibility code for older rpm versions that's not
+	  really
+	  supported anymore anyways and move out as much as possible
+	  rpm5.org
+	  compatibility code out of URPM into new rpm46compat.h @ rpm5.org
+
+2009-07-25 20:50  
+
+	* add support for specifying custom filter for compression with
+	  build_synthesis()
+
+2009-07-22 18:21  
+
+	* really clean up temporary files & directories properly
+
+2009-07-22 18:19  
+
+	* prevent distepoch & disttag to be added and appended to package
+	  filename
+
+2009-05-11 13:26  
+
+	* Removed forgotten debugging logs
+
+2009-05-11 13:22  
+
+	* Add bug #
+
+2009-05-11 13:17  
+
+	* Release 3.30
+
+2009-05-11 13:17  
+
+	* Use key IDs to check if a key is already known or not
+	  
+	  This has the side-effect that if we get a newer public key
+	  corresponding
+	  to an already known key id, it won't get updated, but for now RPM
+	  doesn't let us do that anyway. If a pubkey file contains multiple
+	  keys,
+	  we no longer handle this case, but I don't think this has been
+	  widely
+	  tested, if ever...
+
+2009-05-11 13:17  
+
+	* Fix comment
+
+2009-05-11 13:17  
+
+	* Introduce get_gpg_fingerprint XS function
+
+2009-03-27 14:58  
+
+	* 3.29
+
+2009-03-27 14:58  
+
+	* Fix regression introduced in fix for bug #47803
+	  
+	  This reverts the previous commit
+	  
+	  only compute diff_provides when the package is newly rejected, in
+	  set_rejected_and_compute_diff_provides
+	  
+	  Try this incremental patch. It fixes
+	  set_rejected_and_compute_diff_provides to
+	  not compute diff_provides if package was already rejected (and
+	  thus the
+	  dependencies properly handled already).
+
+2009-03-27 10:28  
+
+	* Revert part of the fix for bug #47803 since it breaks upgrades
+	  from 2008.1
+
+2009-03-25 13:41  
+
+	* 3.28:
+
+2009-03-25 13:22  
+
+	* Postpone user choices as much as possible
+	  
+	  Fixes bug #48100, patch from Anssi Hannula
+	  Package A requires D and E.
+	  Package B provides D and E.
+	  Package C provides E.
+	  
+	  If the require on E happens to be resolved first, then perl-URPM
+	  will
+	  prompt the user, even though installing B is enough.
+
+2009-03-24 16:50  
+
+	* Change format of "rpm sorted by dependencies" string
+
+2009-03-24 15:55  
+
+	* 3.27
+
+2009-03-23 10:03  
+
+	* Don't silently install Suggests:, fixes bug #47934
+	  
+	  When installing a package which suggests an uninstalled package,
+	  urpmi
+	  currently installs both packages without asking the user while it
+	  asks
+	  when installing a package which requires an uninstalled package.
+	  This is
+	  because we call resolve_requested__no_suggests to find which
+	  suggested
+	  package to install, but this mark the package as requested as
+	  well (and
+	  we don't ask for confirmation before installing a requested
+	  package).
+	  This patch calls resolve_requested__no_suggests_ (with a trailing
+	  '_')
+	  instead which is the same as resolve_requested__no_suggests but
+	  does not
+	  mark the packages as requested.
+
+2009-03-23 09:40  
+
+	* fix _handle_diff_provides in case of impossible-to-satisfy
+	  selected packages
+	  
+	  Fixes bug #48223, patch from Anssi Hannula
+	  
+	  Currently, if _handle_diff_provides finds unsatisfied requires on
+	  an already
+	  selected package, and cannot find any packages from the repo that
+	  satisfy
+	  these, it calls resolve_rejected_ (or
+	  set_rejected_and_compute_diff_provides
+	  after fix to bug #47803) (as it does when those unsatisfied
+	  requires are on an
+	  installed package, which was always the case before r242656).
+	  However, those should be called with installed packages only.
+	  
+	  Attached patch makes _handle_diff_provides call
+	  disable_selected_and_unrequested_dependencies and
+	  _set_rejected_from in case of
+	  selected packages.
+
+2009-03-20 18:32  
+
+	* check rep for another pkg providing X if the prev pkg gets
+	  removed due to a conflict
+	  
+	  Fixes bug #47803, patch from Anssi Hannula
+	  
+	  Closer look at urpmi revealed it only does this if a provide X is
+	  removed from
+	  an upgraded package, not when a package providing X has to be
+	  removed.
+	  
+	  i.e. this works:
+	  
+	  A provides foo
+	  B provides foo
+	  C requires foo
+	  
+	  Installed A,C.
+	  
+	  A is upgraded and Provides:foo is dropped, B gets installed in
+	  order to
+	  keep C.
+	  
+	  But this won't:
+	  
+	  A provides foo
+	  A requires dep
+	  B provides foo
+	  C requires foo
+	  D provides dep
+	  
+	  Installed A,C,D.
+	  
+	  D is upgraded and Provides:dep is dropped, A gets removed, C gets
+	  removed.
+
+2009-03-05 11:14  
+
+	* 3.26
+
+2009-03-05 11:13  
+
+	* (verify_signature) make checking urpmi signatures works in
+	  chrooted environments
+	  (especially important for installer where there's no rpmdb in /
+	  (really
+	  /var/lib/rpm) and thus no keys to check against)
+
+2009-01-16 14:48  
+
+	* Release 3.25
+
+2009-01-16 14:48  
+
+	* Really fix bug #46874
+
+2009-01-13 14:27  
+
+	* Version 3.24 - 13 January 2009, by Christophe Fergeau
+	  
+	  - fix sorting choices on provided version (feature introduced in
+	  3.08,
+	  but was not working if packages were coming from different
+	  repository)
+	  - when a "Requires:" can be fullfilled by several different
+	  packages and
+	  one of those packages is explicitly required by another package
+	  which
+	  is also being installed, silently choose this package instead of
+	  letting
+	  the choice up to perl-URPM user (fixes bug #46874)
+
+2009-01-12 08:04  
+
+	* add comments
+
+2009-01-12 08:03  
+
+	* - drop parse_rpms (unused, parse_rpms_build_headers or parse_rpm
+	  are used instead)
+	  - add a comment
+
+2009-01-12 07:59  
+
+	* add a comment
+
+2009-01-12 07:56  
+
+	* - drop function fuzzy_parse() (it is unused)
+	  - add some comment
+
+2009-01-09 14:40  
+
+	* add a comment
+
+2009-01-09 14:39  
+
+	* add some comment
+
+2009-01-09 14:24  
+
+	* - @unsatisfied is a better var name than @l
+	  - add some comment
+
+2009-01-08 13:46  
+
+	* make it clear the func is local
+
+2009-01-08 13:45  
+
+	* add a comment
+
+2009-01-08 09:24  
+
+	* Favour required packages when we have several choices to fulfill
+	  a "requires", fixes bug #46874
+
+2009-01-06 15:55  
+
+	* - add some comment
+	  - enhance a comment
+
+2009-01-06 14:05  
+
+	* document a "hack"
+
+2008-12-15 17:02  
+
+	* - fix sorting choices on provided version (feature introduced in
+	  3.08,
+	  but was not working if packages were coming from different
+	  repository)
+
+2008-12-15 11:08  
+
+	* 3.23
+
+2008-12-15 11:05  
+
+	* - fix bad free() (thanks to glibc for detecting it)
+
+2008-12-12 11:04  
+
+	* 3.22
+
+2008-12-12 09:19  
+
+	* - fix scriptlet failing:
+	  adapt to librpm4.6, rpmtsSetRootDir(ts, "") is forbidden
+
+2008-12-09 16:40  
+
+	* revert wrong commit
+
+2008-12-09 16:33  
+
+	* correctly clean temp directories
+
+2008-12-09 16:05  
+
+	* 3.21
+
+2008-12-09 16:04  
+
+	* - adapt to librpm4.6
+
+2008-12-09 16:03  
+
+	* - adapt to rpm 4.6 changes:
+	  - headerNextIterator -> headerNext
+	  - headerAddEntry -> headerPut
+	  - headerModifyEntry -> headerMod
+
+2008-12-09 16:02  
+
+	* - adapt to rpm 4.6 changes: headerGetEntry -> headerGet
+
+2008-12-09 16:00  
+
+	* - adapt to some easy rpm 4.6 changes:
+	  - headerSprintf -> headerFormat
+	  - headerAddEntry -> headerPutString
+	  - headerRemoveEntry -> headerDel
+	  - rpmProblemGetLong -> rpmProblemGetDiskNeed
+
+2008-12-09 15:55  
+
+	* free the iterator *after* use
+	  (otherwise it segfaults with 4.6.0-rc1, and i wonder how it
+	  worked before...)
+
+2008-12-09 15:52  
+
+	* do free the ts after user, this is especially needed since
+	  rpmVerifySignature
+	  (wrongly) called in rpmReadPackageFile can open the rpmdb which
+	  won't get
+	  closed if ts is not closed
+
+2008-12-09 15:50  
+
+	* - don't handle %_sourcedir specially, it's not needed
+	  - use an absolute filename for %_topdir, it seems to help
+	  (bug in rpm 4.6.0-rc1?)
+
+2008-12-09 15:49  
+
+	* - list_rpm_tag() is no more
+	  - remove a failing test (old)
+
+2008-12-09 15:47  
+
+	* - drop list_rpm_tag()
+
+2008-12-09 15:45  
+
+	* adapt types to rpm-4.6.x
+
+2008-12-08 17:35  
+
+	* fix rpmRelocation usage with rpm 5.2
+
+2008-10-14 17:35  
+
+	* 3.20
+
+2008-10-14 17:35  
+
+	* - $trans->run can now return both the translated errors, and some
+	  parsable
+	  errors (useful for example to detect diskspace issues)
+
+2008-10-14 08:51  
+
+	* use rpmuint64_t rather than long long, we know that it should
+	  stay compatible:)
+
+2008-10-10 09:14  
+
+	* fix build with rpm5.org HEAD
+
+2008-10-07 10:47  
+
+	* 3.19
+
+2008-10-07 10:46  
+
+	* - handle flag "replacefiles"
+
+2008-07-18 18:09  
+
+	* add filelinktos() & dirnames() to URPM::Package
+
+2008-07-17 20:03  
+
+	* ensure that initSourceHeader gets run for rpm5.org, otherwise
+	  querying of spec files won't work
+
+2008-07-14 16:49  
+
+	* fix build with rpm5.org HEAD
+
+2008-07-07 21:53  
+
+	* 3.18
+
+2008-07-07 14:08  
+
+	* - revert change introduced in 3.16 (it breaks too much, eg
+	  superuser--priority-upgrade.t test case), and introduce
+	  $state->{rejected_already_installed} instead
+
+2008-07-07 13:23  
+
+	* fix typo in description
+
+2008-07-04 13:06  
+
+	* 3.17
+
+2008-07-04 13:05  
+
+	* add removed_or_obsoleted_packages()
+
+2008-07-04 13:04  
+
+	* - handle $state->{orphans_to_remove} in selected_size() and
+	  build_transaction_set()
+
+2008-07-04 11:25  
+
+	* - add traverse_tag_find()
+
+2008-07-03 11:25  
+
+	* perl_checker compliance
+
+2008-07-03 11:23  
+
+	* remove unused vars
+
+2008-07-03 11:22  
+
+	* create packages_to_remove() and use it to factorize code
+
+2008-07-01 15:26  
+
+	* create rpmtag_from_string() out of Db_traverse_tag
+
+2008-06-26 12:47  
+
+	* 3.16
+
+2008-06-26 09:46  
+
+	* - when not selecting a package because already installed,
+	  but it in $state->{rejected} with flags {installed}
+
+2008-06-24 09:06  
+
+	* adapt tests to ->compare change
+
+2008-06-23 08:42  
+
+	* 3.15
+
+2008-06-17 09:39  
+
+	* add Anssi name in the log
+
+2008-06-17 09:38  
+
+	* - fix urpmi wrongly considering epochless conflicts to match any
+	  epoch in a
+	  case when urpmi should upgrade a conflicting package to an
+	  actually
+	  non-conflicting version (cf epochless-conflict-with-promotion
+	  urpmi test)
+	  
+	  from Anssi.
+	  
+	  i tested various upgrades from some chroot with 2008.0, 2007.1,
+	  2007.0, and it
+	  didn't change the result, so it should be quite safe :)
+
+2008-05-23 08:24  
+
+	* 3.14
+
+2008-05-23 08:23  
+
+	* - add is_package_installed() in URPM/Resolve.pm
+	  (to be used in urpmi 5.20)
+
+2008-05-20 09:54  
+
+	* 3.13
+
+2008-05-19 15:17  
+
+	* - do not ignore dropped provide from updated package
+	  (mdvbz#40842)
+
+2008-05-15 12:04  
+
+	* enhance error message
+
+2008-04-14 17:11  
+
+	* un-revert rpm5.org cosmetics now that cooker has reopened
+
+2008-04-10 08:16  
+
+	* update authors and copyright notic
+
+2008-03-25 13:15  
+
+	* revert unneeded commit for now
+
+2008-03-19 04:37  
+
+	* fix a typo in a comment </pedanticlamer>
+
+2008-03-19 04:34  
+
+	* make URPM more portable by using standard %{_target_vendor} &
+	  %{_target_cpu} macros in stead of Mandriva specific
+	  %{_real_vendor} & (now dead) %{_real_arch}
+
+2008-03-19 04:18  
+
+	* change x,y check to y,x. More intuitive, for me at least, other
+	  order frequently confuses me ;p
+
+2008-03-19 03:24  
+
+	* d'oh, argument to hexversion() must of course be passed as
+	  strings
+
+2008-03-19 03:12  
+
+	* improve rpm version detection
+	  really fix callback size for rpm5.org versions
+
+2008-03-07 16:50  
+
+	* 3.12
+
+2008-03-07 16:49  
+
+	* - do allow to promoting a pkg even if it has unsatisfied require
+	  (since the
+	  code will then fix the unsatisfied require). fixes "big
+	  transaction"
+	  (cf urpmi split-transactions--strict-require.t test_efgh())
+	  
+	  this code was introduced long ago (*), the code has
+	  changed quite a lot, and it's hard to tell for which reason it
+	  was introduced.
+	  Maybe the check "obsoletes_overlap" replaces it for good?
+	  
+	  (*) in "r11064 | fpons | 2002-06-13", search for "try if
+	  upgrading the package
+	  will be satisfying all the requires"
+
+2008-03-06 16:59  
+
+	* ouch, add back 'case RPMPROB_DISKNODES:' removed by mistake :/
+
+2008-03-06 15:25  
+
+	* revert back to long long since they're of same size anyways and
+	  we avoid warnings that way :)
+
+2008-03-06 14:24  
+
+	* simplify as pixel suggested
+	  use uint64_t in stead of unsigned long long (which is really the
+	  same, but nicer and more consistent with rpm5:)
+
+2008-03-03 12:06  
+
+	* minor cosmetics
+
+2008-03-03 00:50  
+
+	* move compatibility wrapper to rpm5.org upstream
+
+2008-03-02 23:29  
+
+	* more fixes, makes apt-get build succesfully :D
+
+2008-03-02 22:22  
+
+	* make all functions inline functions
+
+2008-03-02 22:02  
+
+	* some more functions for apt-get..
+
+2008-03-02 18:18  
+
+	* make C++ compliant
+	  add som function wrappers for apt-get
+
+2008-03-01 12:33  
+
+	* define WITH_DB in rpm5compat.h in stead of in Makefile
+	  drop useless conditionals for headers as they're already
+	  conditional in themself ;)
+
+2008-03-01 12:29  
+
+	* do better "detection" of callback size without having to define
+	  it in Makefile (inspired by apt)
+
+2008-02-29 21:26  
+
+	* try improve on freeing up memory
+
+2008-02-29 19:06  
+
+	* be sure to return NULL in case of RPMRC_NOTFOUND
+
+2008-02-29 19:00  
+
+	* provide function name in logging
+
+2008-02-29 18:45  
+
+	* be sure to always initialize in headerGetEntry
+
+2008-02-29 15:36  
+
+	* add rpm5.org support to NEWS :)
+
+2008-02-29 15:33  
+
+	* rpm 4.5 and newer uses unsigned long long ulong1 in stead of
+	  unsigned long ulong1 for rpmProblemGetLong, therefore use %lld in
+	  stead of %ld
+
+2008-02-29 15:03  
+
+	* add back copyright field manually since svn wouldn't set it..
+
+2008-02-29 14:57  
+
+	* try add svn properties to top of file
+
+2008-02-29 14:42  
+
+	* add svn keywords properties
+
+2008-02-29 14:40  
+
+	* make inclusion of headers conditional
+
+2008-02-29 14:29  
+
+	* be sure to set return value to NULL in headerGetEntry when Epoch
+	  isn't set
+
+2008-02-29 14:24  
+
+	* fix assignment from incompatible pointer type in
+	  Urpm_list_rpm_tag for rpm5
+
+2008-02-29 14:14  
+
+	* be sure to use same data type for check_flag
+
+2008-02-28 17:07  
+
+	* make sure to use same type (signess) in pack_rpm_header
+
+2008-02-28 16:45  
+
+	* do not define RPM_CALLBACK_LONGLONG for rpm 5.0
+
+2008-02-28 16:20  
+
+	* add copyright notice
+
+2008-02-28 15:30  
+
+	* fix return type and variable of headerRead()
+
+2008-02-28 13:29  
+
+	* 3.11
+
+2008-02-28 13:29  
+
+	* - restore FILENAME_TAG in generated hdlist (to be compatible with
+	  older
+	  distros where ->filename can rely on it) (thanks to Nanar)
+
+2008-02-28 11:04  
+
+	* fix double _free of msg in headerWrite() & headerRead()
+	  do rpmlog for headerWrite() & headerRead()
+	  drop unused variable in cointainer for headerNextIterator()
+
+2008-02-28 02:35  
+
+	* drop unused variable
+
+2008-02-28 02:28  
+
+	* get rid of some warnings
+
+2008-02-28 02:03  
+
+	* add wrapper function for rpmMachineScore
+
+2008-02-28 01:38  
+
+	* add wrapper function for headerRead
+
+2008-02-28 01:24  
+
+	* add wrapper function for headerModifyEntry
+
+2008-02-28 01:06  
+
+	* fix define of _RPMTAG_INTERNAL at right place and drop redundant
+	  include of rpmtag.h
+
+2008-02-28 00:56  
+
+	* add rpm5 wrapper functions, work in progress, URPM builds now at
+	  least :o)
+
+2008-02-27 21:45  
+
+	* fix building with rpm5 DEVEL version
+
+2008-02-25 23:39  
+
+	* do not mark as deprecated ->filename and
+	  URPM::Build::build_hdlist()
+
+2008-02-25 23:22  
+
+	* 3.10
+
+2008-02-25 21:57  
+
+	* adding filesize to synthesis on @info@ will break backward
+	  compatibility for
+	  no good reason, so switching to a new @filesize@ line
+
+2008-02-25 21:37  
+
+	* make ->filename work (again) on header
+
+2008-02-25 21:17  
+
+	* 3.09
+
+2008-02-25 21:13  
+
+	* do not do "uniq" on "fullname" since gpg-pubkey-xxxxxxxx-xxxxxxxx
+	  can be installed twice
+
+2008-02-25 21:05  
+
+	* since ->filename is deprecated, do not use it, esp where not
+	  needed
+
+2008-02-25 20:43  
+
+	* - add filesize to synthesis, add ->filesize to get it, and add
+	  selected_size_filesize() to compute the sum
+
+2008-02-25 20:41  
+
+	* fix previous commit (XS comments are perl-style, not C-style)
+
+2008-02-25 19:17  
+
+	* - do not add FILENAME_TAG and FILESIZE_TAG to hdlist anymore,
+	  deprecate ->filename and ->header_filename,
+	  deprecate URPM::Build build_hdlist and parse_rpms_build_headers
+
+2008-02-25 16:18  
+
+	* - allow fixing "using one big transaction" that occurs when using
+	  --keep
+	  (#30198)
+	  
+	  nb: since build_transaction_set calls resolve_requested, it must
+	  use the same
+	  options to select the same packages
+
+2008-02-25 16:16  
+
+	* - allow urpmi to know a package was not selected because a newer
+	  version is
+	  installed (#29838)
+
+2008-02-25 13:34  
+
+	* - fix sort choices changed in perl-URPM 3.08
+
+2008-02-25 13:33  
+
+	* - handle new package providing xxx which conflicts with an
+	  installed package (#17106)
+
+2008-02-25 09:20  
+
+	* 3.08
+
+2008-02-25 09:19  
+
+	* - sort choices on virtual package by provided version (#12645)
+
+2007-09-12 15:11  Pixel <pixel at mandriva.com>
+
+	* : better indicate the test case in urpmi
+
+2007-09-12 15:04  Pixel <pixel at mandriva.com>
+
+	* : update doc
+
+2007-09-12 15:04  Pixel <pixel at mandriva.com>
+
+	* : update doc
+
+2007-09-12 15:01  Pixel <pixel at mandriva.com>
+
+	* : update doc
+
+2007-09-12 15:00  Pixel <pixel at mandriva.com>
+
+	* : create _remove_all_rejected_from() out of disable_selected()
+
+2007-09-12 14:57  Pixel <pixel at mandriva.com>
+
+	* : create _remove_rejected_from()
+
+2007-09-12 14:47  Pixel <pixel at mandriva.com>
+
+	* : update doc
+
+2007-09-12 14:44  Pixel <pixel at mandriva.com>
+
+	* : factorize code into _set_rejected_from()
+
+2007-09-12 14:38  Pixel <pixel at mandriva.com>
+
+	* : replacing {backtrack}{closure} with {closure} since it looks
+	  like it was a typo
+
+2007-09-12 14:27  Pixel <pixel at mandriva.com>
+
+	* : adapt doc to is really done (may kill {backtrack}{closure}
+	  later)
+
+2007-09-12 13:16  Pixel <pixel at mandriva.com>
+
+	* : update doc
+
+2007-09-12 13:12  Pixel <pixel at mandriva.com>
+
+	* : - fix typo in previous commit: pass $urpm to set_selected() for
+	  debug message
+	  - {from} options to resolve_rejected_ and set_selected is now a
+	  pkg object
+	  instead of a fullname string
+
+2007-09-12 13:08  Pixel <pixel at mandriva.com>
+
+	* : add debug message
+
+2007-09-12 13:07  Pixel <pixel at mandriva.com>
+
+	* : simplify
+
+2007-09-12 13:06  Pixel <pixel at mandriva.com>
+
+	* : handle {size} in set_rejected()
+
+2007-09-12 12:59  Pixel <pixel at mandriva.com>
+
+	* : - add ability to merge {closure} fields in set_rejected (from
+	  $options{why})
+	  - {from} is a fullname here
+	  - {why} is a hash
+	  - use set_rejected() to factorize code
+
+2007-09-12 12:12  Pixel <pixel at mandriva.com>
+
+	* : cleanup
+
+2007-09-12 12:11  Pixel <pixel at mandriva.com>
+
+	* : fix typo in previous commit
+
+2007-09-12 12:03  Pixel <pixel at mandriva.com>
+
+	* : create set_rejected() out of resolve_rejected_()
+
+2007-09-12 11:03  Pixel <pixel at mandriva.com>
+
+	* : dep field "choices" is here for debug purpose, rename it
+	  _choices
+
+2007-09-12 11:00  Pixel <pixel at mandriva.com>
+
+	* : create _dep_to_name() and use it
+
+2007-09-12 10:50  Pixel <pixel at mandriva.com>
+
+	* : drop unused option "closure_as_removed"
+
+2007-09-12 10:14  Pixel <pixel at mandriva.com>
+
+	* : backtrack_selected() was always returning empty list, so
+	  backtrack_selected_psel_keep() should return empty list. but it's
+	  simply to
+	  modify callers to take into account the return value is ()
+
+2007-09-12 10:07  Pixel <pixel at mandriva.com>
+
+	* : move var declaration where it's used
+
+2007-09-12 10:06  Pixel <pixel at mandriva.com>
+
+	* : move function created in previous commit
+
+2007-09-12 10:04  Pixel <pixel at mandriva.com>
+
+	* : create _choose_required() out of
+	  resolve_requested__no_suggests_()
+
+2007-09-12 09:50  Pixel <pixel at mandriva.com>
+
+	* : this is good to have in NEWS
+
+2007-09-11 16:27  Pixel <pixel at mandriva.com>
+
+	* : document side-effects of each functions
+
+2007-09-11 15:41  Pixel <pixel at mandriva.com>
+
+	* : add some doc
+
+2007-09-11 15:35  Pixel <pixel at mandriva.com>
+
+	* : rename disable_selected_unrequested_dependencies() into
+	  disable_selected_and_unrequested_dependencies()
+
+2007-09-11 15:09  Pixel <pixel at mandriva.com>
+
+	* : don't keep a hash when we really want its values
+
+2007-09-11 15:03  Pixel <pixel at mandriva.com>
+
+	* : - create strict_arch_check() out of find_required_package()
+	  - and factorize some more code into $may_add_to_packages
+
+2007-09-11 14:46  Pixel <pixel at mandriva.com>
+
+	* : create backtrack_selected_psel_keep() out of
+	  backtrack_selected() and use it
+
+2007-09-11 14:12  Pixel <pixel at mandriva.com>
+
+	* : drop keep_unrequested_dependencies option (it is unused)
+
+2007-09-11 14:10  Pixel <pixel at mandriva.com>
+
+	* : drop keep_requested_flag by creating
+	  resolve_requested__no_suggests_()
+
+2007-09-11 14:04  Pixel <pixel at mandriva.com>
+
+	* : simplify
+
+2007-09-11 14:00  Pixel <pixel at mandriva.com>
+
+	* : define var where it's needed
+
+2007-09-11 13:59  Pixel <pixel at mandriva.com>
+
+	* : rename var, $dep will only be used as an element from
+	  @properties
+
+2007-09-11 13:58  Pixel <pixel at mandriva.com>
+
+	* : rename var, $dep will only be used as an element from
+	  @properties
+
+2007-09-11 13:52  Pixel <pixel at mandriva.com>
+
+	* : add doc
+
+2007-09-11 13:37  Pixel <pixel at mandriva.com>
+
+	* : add some doc
+
+2007-09-11 13:37  Pixel <pixel at mandriva.com>
+
+	* : simplify
+
+2007-09-11 13:32  Pixel <pixel at mandriva.com>
+
+	* : simplify
+
+2007-09-11 13:24  Pixel <pixel at mandriva.com>
+
+	* : simplify: make find_candidate_packages() the wrapper around
+	  find_candidate_packages_() instead of the other way round
+
+2007-09-11 13:21  Pixel <pixel at mandriva.com>
+
+	* : create find_candidate_packages_(), wrapper around
+	  find_candidate_packages()
+
+2007-09-11 13:16  Pixel <pixel at mandriva.com>
+
+	* : drop callback_backtrack, unused for a long time
+
+2007-09-11 11:54  Pixel <pixel at mandriva.com>
+
+	* : fix old typo in comment
+
+2007-09-11 11:51  Pixel <pixel at mandriva.com>
+
+	* : add a comment
+
+2007-09-11 10:54  Pixel <pixel at mandriva.com>
+
+	* : fix old typo (rejected field is unused anyway afaik)
+
+2007-09-11 10:00  Pixel <pixel at mandriva.com>
+
+	* : fix typo in previous typo fix
+
+2007-09-11 10:00  Pixel <pixel at mandriva.com>
+
+	* : fix typo in previous commit :-/
+
+2007-09-11 09:58  Pixel <pixel at mandriva.com>
+
+	* : - speedup is_arch_compat (x7) by keeping the platform in a
+	  cache
+
+2007-09-11 09:55  Pixel <pixel at mandriva.com>
+
+	* : add missing free()
+
+2007-09-11 08:44  Pixel <pixel at mandriva.com>
+
+	* : move doc where it belongs
+
+2007-09-11 07:28  Pixel <pixel at mandriva.com>
+
+	* : add comment
+
+2007-09-10 16:58  Pixel <pixel at mandriva.com>
+
+	* : simplify prototype of find_candidate_packages()
+
+2007-09-10 16:56  Pixel <pixel at mandriva.com>
+
+	* : rename find_chosen_packages() into find_required_package()
+	  (better name)
+
+2007-09-10 16:49  Pixel <pixel at mandriva.com>
+
+	* : - pass the prefered choices to {callback_choices}: this allows
+	  urpmi to select
+	  all the prefered packages according to installed locales
+
+2007-09-10 15:48  Pixel <pixel at mandriva.com>
+
+	* : - do not propose packages for non installed locales
+
+2007-09-10 15:48  Pixel <pixel at mandriva.com>
+
+	* : - do not propose packages for non installed locales
+	  - cleanup code
+
+2007-09-10 15:46  Pixel <pixel at mandriva.com>
+
+	* : fix typo in previous commit
+
+2007-09-10 15:16  Pixel <pixel at mandriva.com>
+
+	* : create _find_chosen_packages__sort() out of
+	  find_chosen_packages()
+
+2007-09-08 20:29  Pixel <pixel at mandriva.com>
+
+	* : more detailed doc
+
+2007-09-08 09:24  Pixel <pixel at mandriva.com>
+
+	* : typo in comment
+
+2007-09-08 09:16  Pixel <pixel at mandriva.com>
+
+	* : rename lists with "closure" in the name to things like
+	  "xxx_todo" or
+	  "all_xxx", i find it more readable, and it helps making the
+	  difference with
+	  {closure} field
+
+2007-09-08 09:10  Pixel <pixel at mandriva.com>
+
+	* : rename local var for clarity
+
+2007-09-08 09:07  Pixel <pixel at mandriva.com>
+
+	* : rename local var
+
+2007-09-08 09:05  Pixel <pixel at mandriva.com>
+
+	* : document $state fields
+
+2007-09-08 08:10  Pixel <pixel at mandriva.com>
+
+	* : rename a local variable for clarity
+
+2007-09-08 08:09  Pixel <pixel at mandriva.com>
+
+	* : create _handle_conflicts() out of
+	  resolve_requested__no_suggests()
+
+2007-09-08 07:39  Pixel <pixel at mandriva.com>
+
+	* : fix typo in older commit
+
+2007-09-08 07:38  Pixel <pixel at mandriva.com>
+
+	* : use function calls instead of method calls (it allows
+	  perl_checker checks when
+	  temporarilly renaming URPM/Resolve.pm package name to URPM)
+
+2007-09-07 21:56  Pixel <pixel at mandriva.com>
+
+	* : create _handle_diff_provides() out of
+	  resolve_requested__no_suggests()
+
+2007-09-07 20:49  Pixel <pixel at mandriva.com>
+
+	* : create _compute_diff_provides() and
+	  _compute_diff_provides_one() out of
+	  resolve_requested__no_suggests()
+
+2007-09-07 20:31  Pixel <pixel at mandriva.com>
+
+	* : factorize regexps into functions
+
+2007-09-07 19:45  Pixel <pixel at mandriva.com>
+
+	* : make it more clear
+
+2007-09-07 19:35  Pixel <pixel at mandriva.com>
+
+	* : cleanup
+
+2007-09-07 19:32  Pixel <pixel at mandriva.com>
+
+	* : create _ids_to_fullnames() and _ids_to_names()
+
+2007-09-07 19:19  Pixel <pixel at mandriva.com>
+
+	* : fix typo in recent commit
+
+2007-09-07 19:18  Pixel <pixel at mandriva.com>
+
+	* : make it clear that resolve_rejected_ is modifying @properties
+	  from
+	  resolve_requested()
+
+2007-09-07 18:39  Pixel <pixel at mandriva.com>
+
+	* : revert previous commit: compute_deps() is still used by mkcd
+
+2007-09-07 17:55  Pixel <pixel at mandriva.com>
+
+	* : remove unused compute_deps() \o/
+
+2007-09-07 17:49  Pixel <pixel at mandriva.com>
+
+	* : simplify: nopromoteepoch is always 1 (no caller ever define it)
+
+2007-09-07 17:43  Pixel <pixel at mandriva.com>
+
+	* : cleanup: nopromoteepoch is 1 by default in
+	  find_candidate_packages
+
+2007-09-07 15:44  Pixel <pixel at mandriva.com>
+
+	* : factorize code in functions whatrequires() and
+	  whatrequires_id()
+
+2007-09-07 15:30  Pixel <pixel at mandriva.com>
+
+	* : simplify: whatrequires is a hash with provides_nosense as key,
+	  don't need to
+	  use ->provides then remove the sense
+
+2007-09-07 15:19  Pixel <pixel at mandriva.com>
+
+	* : hoist a debug message so that it occurs for other uses of
+	  with_db_unsatisfied_requires()
+
+2007-09-07 15:06  Pixel <pixel at mandriva.com>
+
+	* : re-use same code for conflict from installed package as is used
+	  for conflict
+	  from selected package. this fixes test_gh() from urpmi
+	  split-transactions--promote test case
+
+2007-09-07 14:44  Pixel <pixel at mandriva.com>
+
+	* : move code from resolve_requested__no_suggests() into new
+	  function _handle_provides_overlap()
+
+2007-09-07 14:30  Pixel <pixel at mandriva.com>
+
+	* : prepare to factorize code handling property becoming
+	  unavailable.
+	  
+	  it really seems {why}{conflicts} is only used for debugging
+	  purpose, so this
+	  change won't break.
+
+2007-09-07 14:24  Pixel <pixel at mandriva.com>
+
+	* : one more debug message
+
+2007-09-07 11:26  Pixel <pixel at mandriva.com>
+
+	* : small cleanup
+
+2007-09-07 11:26  Pixel <pixel at mandriva.com>
+
+	* : add some debug messages
+
+2007-09-05 15:19  Pixel <pixel at mandriva.com>
+
+	* : - fix displaying @sorted whereas some elements have been
+	  removed from it
+	  - more complete error message
+
+2007-09-05 09:37  Pixel <pixel at mandriva.com>
+
+	* : add debug code
+
+2007-09-03 15:21  Pixel <pixel at mandriva.com>
+
+	* : 1.80, bugfix release
+
+2007-09-03 15:21  Pixel <pixel at mandriva.com>
+
+	* : - fix bug in sort_graph (used by build_transaction_set)
+
+2007-09-03 15:20  Pixel <pixel at mandriva.com>
+
+	* : 1.79
+
+2007-09-03 12:59  Pixel <pixel at mandriva.com>
+
+	* : add a test
+
+2007-09-03 08:08  Pixel <pixel at mandriva.com>
+
+	* : - fix bug in sort_graph (used by build_transaction_set)
+
+2007-09-03 08:07  Pixel <pixel at mandriva.com>
+
+	* : 1.78
+
+2007-08-31 15:54  Pixel <pixel at mandriva.com>
+
+	* : fix dead-loop in build_transaction_set (#33020)
+	  
+	  and ensure the resulting graph is correct by checking it
+
+2007-08-31 07:02  Pixel <pixel at mandriva.com>
+
+	* : add a comment
+
+2007-08-29 09:33  Pixel <pixel at mandriva.com>
+
+	* : 1.77
+
+2007-08-29 09:33  Pixel <pixel at mandriva.com>
+
+	* : - disable "dropping tags from rpm header" until we can safely
+	  use it
+
+2007-08-29 09:32  Pixel <pixel at mandriva.com>
+
+	* : 1.76
+
+2007-08-28 14:12  Pixel <pixel at mandriva.com>
+
+	* : ensure #31969 doesn't occur anymore. if somethings goes wrong:
+	  - display error message
+	  - then default to one big transaction
+	  
+	  also display error message "using one big transaction" in the old
+	  check (which
+	  i don't really know what it does)
+
+2007-08-28 13:54  Pixel <pixel at mandriva.com>
+
+	* : - build_transaction_set: new sort algorithm which allow
+	  returning sets of
+	  circular dependent packages, taking into account obsoleted
+	  packages
+	  (fixes #31969). It may still fail in presence of conflicts
+	  
+	  a better fix would be to make ->resolve_requested__no_suggests
+	  handle
+	  obsolete. ie:
+	  - a requires b : bb or b
+	  - bb requires c-1
+	  - b requires c-2
+	  - b obsoletes bb
+	  => with a, bb and c-1 installed, "urpmi c" should upgrade bb into
+	  b instead of
+	  removing a and bb.
+
+2007-08-28 11:03  Pixel <pixel at mandriva.com>
+
+	* : - spec2srcheader: workaround parseSpec returning a header where
+	  ->arch is set
+	  to %{_target_cpu} whereas we really want a header similar to
+	  .src.rpm
+	  (see #32824)
+
+2007-08-24 12:01  Pixel <pixel at mandriva.com>
+
+	* : - fix split_length > 1
+	  (eg: "urpmi --split-length 2 a b c" will only install 2 pkgs)
+	  (this bug has not been reported, just discovered it while reading
+	  the code)
+	  
+	  - cleanup
+
+2007-08-24 11:50  Pixel <pixel at mandriva.com>
+
+	* : - more debug messages
+	  - little rewrite
+
+2007-08-23 13:22  Pixel <pixel at mandriva.com>
+
+	* : - allow running transaction with justdb option
+
+2007-08-12 20:45  Pixel <pixel at mandriva.com>
+
+	* : 1.75
+
+2007-08-12 20:44  Pixel <pixel at mandriva.com>
+
+	* : - fix dropping tags from rpm header.
+	  it hasn't work since MDK8.1 and rpm 4.0.
+	  it may break urpmi!! but potentially allows a much smaller
+	  hdlist.cz :)
+
+2007-08-12 11:32  Pixel <pixel at mandriva.com>
+
+	* : 1.74
+
+2007-08-12 11:29  Pixel <pixel at mandriva.com>
+
+	* : - sort choices per media, then per version
+	  
+	  nb:
+	  
+	  on 2004-12-13, rgs replaced "$a->id <=> $b->id" with
+	  "$b->compare_pkg($a) || $a->id <=> $b->id"
+	  
+	  Return the list of chosen packages sorted by descending
+	  version (bug #12645).
+	  
+	  the end result is the sorting by media was dropped :-/
+
+2007-08-12 10:15  Pixel <pixel at mandriva.com>
+
+	* : cleanup (easier to read)
+
+2007-08-11 12:21  Pixel <pixel at mandriva.com>
+
+	* : 1.73
+
+2007-08-11 12:21  Pixel <pixel at mandriva.com>
+
+	* : - allow running transaction with replagekgs option
+
+2007-08-10 18:01  Pixel <pixel at mandriva.com>
+
+	* : 1.72
+
+2007-08-10 17:50  Pixel <pixel at mandriva.com>
+
+	* : - modify parse_hdlist so that partial hdlist reading can be
+	  used
+	  (needed when some stuff is already done in the callback)
+
+2007-08-10 17:35  Pixel <pixel at mandriva.com>
+
+	* : add documentation
+
+2007-08-10 17:34  Pixel <pixel at mandriva.com>
+
+	* : there is no use retrying after a headerRead failure since
+	  headerRead may have
+	  consumed part of the input, and so next headerRead will read in
+	  the middle of
+	  a header, and so always fail. The only real solution is to ensure
+	  rpmlib don't
+	  timeout too quickly (and fd->rd_timeoutsecs is rpmlib internal
+	  only, so we
+	  can't hint it from here. in any case 1sec timeout is really too
+	  low)
+
+2007-08-09 15:25  Pixel <pixel at mandriva.com>
+
+	* : 1.71
+
+2007-08-09 15:24  Pixel <pixel at mandriva.com>
+
+	* : - compilation fixes on rpm < 4.4.8
+
+2007-08-09 14:58  Pixel <pixel at mandriva.com>
+
+	* : 1.70
+
+2007-08-09 14:58  Pixel <pixel at mandriva.com>
+
+	* : compilation fixes on rpm < 4.4.8
+
+2007-08-09 13:24  Pixel <pixel at mandriva.com>
+
+	* : 1.69
+
+2007-08-09 13:24  Pixel <pixel at mandriva.com>
+
+	* : - "suggests" are no more handled as "requires"
+	  - resolve_requested support "suggests": a newly suggested package
+	  is installed
+	  as if required (can be disabled with option no_suggests)
+	  
+	  nb: URPM.xs change is quite complex since suggests are mostly
+	  seen as requires
+	  inside rpmlib.
+
+2007-08-08 18:18  Pixel <pixel at mandriva.com>
+
+	* : factorize some code into with_db_unsatisfied_requires:
+	  
+	  #- this function is "suggests vs requires" safe:
+	  #- 'whatrequires' will give both requires & suggests, but
+	  unsatisfied_requires
+	  #- will check $p->requires and so filter out suggests
+
+2007-08-08 17:38  Pixel <pixel at mandriva.com>
+
+	* : "nopromoteepoch => 1" is the default option in
+	  ->unsatisfied_requires
+
+2007-08-03 14:43  Pixel <pixel at mandriva.com>
+
+	* : 1.68
+
+2007-08-03 14:42  Pixel <pixel at mandriva.com>
+
+	* : - add $trans->Element_version and $trans->Element_release
+
+2007-07-05 13:36  nanardon
+
+	* : - 0.67
+
+2007-07-04 22:26  nanardon
+
+	* : - Urpm_read_config_files properly return the value to perl
+	  - kill useless var dcl
+
+2007-07-04 22:21  nanardon
+
+	* : - fix parseSpec argument
+
+2007-07-04 16:43  nanardon
+
+	* : - add osscore() and archscore() function to evaluate computer
+	  compatiblity to an arbitrary value
+
+2007-07-04 15:53  nanardon
+
+	* : - add Pkg_is_platform_compat() and Urpm_platformscore() coming
+	  with rpm 4.4.8
+
+2007-07-02 15:14  Pixel <pixel at mandriva.com>
+
+	* : 1.66
+
+2007-07-02 15:11  Pixel <pixel at mandriva.com>
+
+	* : - fix --auto-select skipping some packages because of other
+	  packages providing
+	  a more recent version, but no obsolete between those packages.
+	  the fix is to revert commit from Aug 2002:
+	  "fixed propable old package (according provides) requested by
+	  request_packages_to_upgrade."
+	  
+	  hopefully this change won't break too much...
+	  
+	  for the record, a few issues:
+	  - skipping java-1.5.0-gcj-1.5.0.0-14.7mdv2008.0.i586 since
+	  java-1.7.0-icedtea-1.7.0.0-1.3mdv2008.0.i586 provides a more
+	  recent version of jre (1.7.0 vs 1.5.0)
+	  - skipping emacs-common-22.1-2mdv2008.0.i586 since
+	  gnus-emacs-5.10.8-1mdv2007.0.noarch provides a more recent vers
+	  whereas java-1.5.0-gcj-1.5.0.0-14.6mdv and emacs-common-22.1-1mdv
+	  are installed
+
+2007-07-02 15:05  Pixel <pixel at mandriva.com>
+
+	* : help perl_checker
+
+2007-07-02 14:38  Pixel <pixel at mandriva.com>
+
+	* : help debugging the strange behaviour of this code
+
+2007-06-21 14:13  nanardon
+
+	* : - 1.42
+
+2007-06-19 14:44  nanardon
+
+	* : - make is_arch_compat rpm 4.4.8 compliant
+
+2007-06-15 20:00  Pixel <pixel at mandriva.com>
+
+	* : document the fact that build_synthesis returns true on success
+
+2007-06-12 14:03  Pixel <pixel at mandriva.com>
+
+	* : fix release date
+
+2007-06-12 13:57  Pixel <pixel at mandriva.com>
+
+	* : 1.64
+
+2007-06-12 13:56  Pixel <pixel at mandriva.com>
+
+	* : - hack on $pkg->is_arch_compat to make it return true for
+	  noarch packages
+	  when using rpm 4.4.8 (#31314)
+
+2007-05-09 16:00  Pixel <pixel at mandriva.com>
+
+	* : - new release, 1.63
+	  - add $trans->Element_fullname
+
+2007-05-03 14:51  Pixel <pixel at mandriva.com>
+
+	* : 1.61 has not been released
+
+2007-05-03 14:49  Pixel <pixel at mandriva.com>
+
+	* : 1.62
+
+2007-05-03 14:49  Pixel <pixel at mandriva.com>
+
+	* : - pass the virtual package name as a parameter to
+	  {callback_choices} in
+	  ->resolve_requested
+
+2007-04-27 12:37  Pixel <pixel at mandriva.com>
+
+	* : re-sync after the big svn loss
+
+2007-04-27 12:37  Pixel <pixel at mandriva.com>
+
+	* : re-sync after the big svn loss
+
+2007-04-27 12:31  Pixel <pixel at mandriva.com>
+
+	* : - 1.61
+	  - add $trans->NElements and $trans->Element_name
+	  to be able to display name of uninstalled package in
+	  callback_uninst
+	  - fix b--obsoletes-->a and c--conflicts-->a prompting for
+	  upgrading a
+	  (need a fix in urpmi which rely on the $state->{rejected}
+	  to upgrade (-U) b instead of installing (-i) it)
+
+2007-04-27 12:30  Pixel <pixel at mandriva.com>
+
+	* : re-sync after the big svn loss
+
+2007-04-24 19:11  Pixel <pixel at mandriva.com>
+
+	* : re-sync after the big svn loss
+
+2006-12-04 10:28  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: correctly set "\0"
+
+2006-12-04 10:23  Pixel <pixel at mandriva.com>
+
+	* t/parse.t: remove temp file
+
+2006-12-04 09:43  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: correctly handle gzread error code
+
+2006-12-01 16:21  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: rpmReadPackageFile() can return ok but no header :-/
+
+2006-12-01 16:14  Pixel <pixel at mandriva.com>
+
+	* URPM.pm, URPM.xs: rpmReadPackageFile() can return ok but no
+	  header :-/
+
+2006-11-29 22:24  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) factorize size to allocate
+
+2006-11-29 22:23  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) adjust allocated memory
+
+2006-11-29 22:22  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) remove guard, proper fix is now enough
+
+2006-11-29 22:21  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) fix segfault on ia32 (when one replace
+	  "struct foobar" by
+	  "foobar*", he should expect sizeof() to *slightly* differ in
+	  results)
+
+2006-11-29 17:08  Pixel <pixel at mandriva.com>
+
+	* URPM.pm: 1.50 new release
+
+2006-11-29 16:59  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) fix segfault when using --excludepath
+
+2006-11-29 15:36  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) fix the segfault when using --excludepath
+	  (introduced in
+	  r32435:32440). however, using --excludepath will still
+	  segfaults, but
+	  later, in rpmtsAddInstallElement() ...
+
+2006-11-29 13:56  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (Trans_add) fix segfault
+
+2006-11-24 10:12  Pixel <pixel at mandriva.com>
+
+	* URPM.pm, URPM/Resolve.pm: strict-arch should not imply that
+	  noarch can't upgrade the real arch (#22558)
+
+2006-11-21 07:59  Pixel <pixel at mandriva.com>
+
+	* ChangeLog: - default to strict-arch on 64bits (tvignaud)
+	  - handle empty hdlist.cz/synthesis.cz (in build_hdlist,
+	  build_synthesis, parse_hdlist, parse_synthesis)
+	  - parse_rpms_build_headers: allow asking for packing (and so
+	  fixing an error in urpmi)
+	  - documentation & comments enhancement
+	  - release 1.48
+
+2006-11-21 07:54  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm: resolve_rejected: nodeps is also recognised
+	  (through backtrack_selected)
+
+2006-11-21 07:54  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm: resolve_rejected: nodeps is also recognised
+	  (through backtrack_selected)
+
+2006-11-17 17:46  Pixel <pixel at mandriva.com>
+
+	* URPM/Build.pm: parse_rpms_build_headers: allow asking for
+	  packing (fixes an error in urpmi)
+
+2006-11-17 16:43  Pixel <pixel at mandriva.com>
+
+	* t/parse.t: add some tests on empty header, buggy header, empty
+	  hdlist
+
+2006-11-17 16:42  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: at least one good header is needed for non compressed
+	  hdlist and non empty file
+	* URPM/Build.pm: allow building empty hdlist & synthesis
+
+2006-11-17 16:25  Pixel <pixel at mandriva.com>
+
+	* URPM.xs, t/parse.t: - parse_hdlist on a simple header was broken
+	  because pid was left unset,
+	  - add some tests for this
+
+2006-11-15 12:21  Pixel <pixel at mandriva.com>
+
+	* t/rpmdb.t: do display on which pkgs the 2 sorted lists disagree
+
+2006-11-15 11:49  Pixel <pixel at mandriva.com>
+
+	* URPM.pm, URPM.xs: add a wrapper in perl around parse_hdlist and
+	  parse_synthesis
+
+2006-11-15 11:47  Pixel <pixel at mandriva.com>
+
+	* t/rpmdb.t: remove debug stuff
+
+2006-11-15 11:28  Pixel <pixel at mandriva.com>
+
+	* URPM.pm: make the prototype of parse_synthesis more clear in the
+	  pod
+
+2006-11-15 11:14  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: parse_synthesis, parse_hdlist: handle gzip error status
+	  instead of relying on
+	  wether we did read at least one header. This allow "empty"
+	  hdlist/synthesis.
+	  But it means it is getting stricter, and the headers added to
+	  {depslist} would
+	  need to be removed if an error occured. Alas i don't know how to
+	  do it (a
+	  simple splice) in XS. If no better solution, i'll create a
+	  wrapper function in
+	  perl.
+
+2006-11-10 14:18  Pixel <pixel at mandriva.com>
+
+	* URPM/Build.pm: use the documented way to call ->parse_hdlist,
+	  not the deprecated one
+
+2006-11-09 15:05  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM/Resolve.pm: (find_chosen_packages) default to strict-arch
+	  on 64bits
+
+2006-11-07 13:27  Pixel <pixel at mandriva.com>
+
+	* ChangeLog, URPM.pm: new release, no real change except
+	  perl_checker compliant
+
+2006-11-03 15:41  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm: perl_checker compliance
+
+2006-11-03 15:21  Pixel <pixel at mandriva.com>
+
+	* .perl_checker, URPM.pm, URPM/.perl_checker, URPM/Build.pm,
+	  URPM/Resolve.pm: perl_checker compliance
+
+2006-11-03 15:41  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm: perl_checker compliance
+
+2006-11-03 15:21  Pixel <pixel at mandriva.com>
+
+	* .perl_checker, URPM.pm, URPM/.perl_checker, URPM/Build.pm,
+	  URPM/Resolve.pm: perl_checker compliance
+
+2006-10-16 10:11  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Patch by Pixel to ignore self-obsoletes
+
+2006-09-21 09:49  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Invert bogus check
+
+2006-09-07 09:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST, URPM/Build.pm, t/pod.t: Add POD test, remove sole pod
+	  fragment in URPM::Build
+
+2006-09-06 11:37  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm: Bump version to 1.46
+
+2006-09-06 09:15  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Oops, remove debug code
+
+2006-09-06 09:13  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: prefer kernel-source-stripped over kernel-source
+
+2006-09-05 16:14  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Micro-optimisation, and make comments more
+	  explicit
+
+2006-08-07 14:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm: Bump version, regen changelog
+
+2006-08-07 14:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST, perl-URPM.spec: Remove perl-URPM.spec, checked in in
+	  repsys
+
+2006-08-07 14:30  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - cleanup useless imported rpm dcl
+
+2006-08-07 14:25  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - remove useless declaration
+
+2006-08-07 14:30  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - cleanup useless imported rpm dcl
+
+2006-08-07 14:25  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - remove useless declaration
+
+2006-08-04 09:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix a FD leak (patch by Pascal Terjan, bug #24112)
+
+2006-08-01 13:21  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: strict-arch doesn't apply to src packages
+
+2006-07-25 21:50  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - add comment into code, need review
+
+2006-07-04 12:35  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: One might have an undefined package in the
+	  depslist (not sure why)
+
+2006-06-14 10:08  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM/Signature.pm: Verify if we can open the rpmdb, and
+	  abort if we can't (bug #22527)
+
+2006-06-12 10:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: That wasn't actually necessary
+
+2006-06-12 10:31  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: Bump version number
+
+2006-06-12 10:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix passing of rpmRelocation structure with new layout
+	  in 4.4.6
+
+2006-06-12 10:20  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Fix rpm version detection. Generate ChangeLog under
+	  C locale.
+
+2006-06-07 09:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* .cvsignore: Remove cvsignore file
+
+2006-06-07 09:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, Makefile.PL: Use svn2cl to generate ChangeLog, and
+	  regenerate it
+
+2006-06-01 11:47  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL, URPM.xs: It's nice to be able to compile with rpm
+	  4.4.6, but it's nice to be able to
+	  compile with older rpms too.
+
+2006-05-31 21:10  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - rpm 4.4.6 fixes
+
+2006-05-23 21:53  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* META.yml: Add metafile
+
+2006-05-23 21:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.43
+
+2006-05-23 21:32  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - fix urpmi .spec: aka ensure the rpm config is read
+	  with all macros before parsing a spec
+
+2006-05-22 13:43  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Don't clobber rpm's changelog with too many
+	  details, there is a real changelog for that
+
+2006-05-22 13:32  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* perl-URPM.spec: add bug reference in 1.42-1mdk's changelog
+
+2006-05-22 11:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.42
+
+2006-05-22 10:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Patch by Pascal Terjan to fix a FD leak (bug #22632)
+
+2006-05-02 08:33  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.41
+
+2006-04-07 10:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add function to traverse transactions
+
+2006-04-02 23:02  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: RPMTAG_SOURCEPACKAGE is going to be obsolete. Replace
+	  it by RPMTAG_SOURCERPM.
+
+2006-03-15 12:42  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.40
+
+2006-03-13 16:51  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Get version comparison right
+
+2006-03-13 16:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Define new symbol in Makefile.PL depending on
+	  detected rpm version
+	  (no simpler way to get it from the C preprocessor, it seems)
+
+2006-03-13 16:37  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix for undocumented ABI changes in rpm 4.4.5 callback
+	  interface
+
+2006-03-13 15:56  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Protection when no data is passed to transaction
+	  callbacks
+
+2006-03-13 14:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix misplaced break in switch statement
+
+2006-03-10 16:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: "triggeredby" in traverse_tag never worked.
+
+2006-03-08 15:51  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix small memleak on db open error
+
+2006-03-07 10:35  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.39
+
+2006-03-07 10:27  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Clean up gcc options
+
+2006-03-07 10:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Protect rpmtsRun with a new link to the transaction
+	  object
+
+2006-03-06 14:11  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Spec file nit.
+	* URPM.xs: Also, increase refcounts.
+
+2006-03-06 13:59  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.38
+
+2006-03-06 13:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/rpmdb.t: Perform this test faster
+
+2006-03-06 13:45  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/parse.t: Be more Test::More-ish, add a TODO test
+
+2006-03-06 13:31  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: It wasn't a good idea to completely remove the
+	  refcount, because it's used to
+	  free the underlying C glue structure.
+	  Also, and rpmtsLink was misplaced.
+
+2006-03-06 11:09  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Don't use our own reference counter, but the rpmlib's,
+	  for transactions.
+
+2006-03-03 15:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.37
+
+2006-03-03 15:08  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document URPM::verify_signature()
+
+2006-03-03 15:05  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Include key id in verify_signature()'s OK output. Also,
+	  avoid a header leak.
+
+2006-03-03 14:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: New function verify_signature
+
+2006-03-03 13:50  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Don't display error messages from rpmVerifySignatures
+
+2006-03-03 13:14  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document (new-ish) return value of verify_rpm()
+
+2006-03-03 13:00  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Reimplement verify_rpm, using the rpm cli
+	  interface
+
+2006-03-03 10:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Remove support for the (broken) db option to
+	  verify_rpm
+
+2006-03-03 09:26  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Use a smaller buffer for the return value of
+	  verify_rpm, and guard against overflows
+
+2006-03-02 17:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Honor verification flags in verif_rpm() even when
+	  reading from a file without
+	  having open the rpmdb
+
+2006-03-02 17:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Nits in verify_rpm.
+
+2006-03-01 11:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix a couple of compilation warnings. URPM.xs is now
+	  warning-clean.
+
+2006-03-01 11:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Make sure -fno-strict-aliasing is used (gcc option)
+
+2006-02-13 13:17  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document the is_arch_compat package method
+
+2006-02-13 10:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: 1.36-1mdk
+
+2006-02-13 10:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document new ignorearch flag
+
+2006-02-13 10:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Add ignorearch option to run transactions
+
+2006-02-10 17:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.35-1mdk
+
+2006-02-10 17:06  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: repackage also when only the rpm macro is defined.
+	  Maybe rpm ought to do this,
+	  but obviously, as of 4.4.4, it does not.
+
+2006-02-10 09:03  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.34-1mdk
+
+2006-02-10 08:55  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Doc nits
+
+2006-02-10 08:53  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Remove unused variable
+
+2006-02-09 17:33  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Fix code example in URPM's synopsis
+
+2006-02-09 17:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add installtid method
+
+2006-02-09 14:47  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document keep_all_tags option to parse rpms
+
+2006-02-09 13:57  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: No need to make an explicit dependency on
+	  perl-base
+
+2006-02-09 13:56  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog: Update Changelog
+
+2006-02-09 13:52  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, perl-URPM.spec: 1.33-1mdk
+
+2006-02-09 13:50  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document new flag repackage in run()
+
+2006-02-09 13:25  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix repackage option, oops
+
+2006-02-09 12:57  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Add repackage flag to run transactions
+
+2006-01-25 14:21  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, URPM.xs, perl-URPM.spec: 1.32-1mdk
+
+2006-01-25 14:18  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Flag headers returned by spec2srcheader() as source
+	  packages
+
+2006-01-24 11:38  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Pod formatting fix
+
+2006-01-19 13:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.31
+
+2006-01-19 13:31  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Rewrite and relocate doc at a more proper place. Update
+	  copyright notice.
+
+2006-01-19 13:24  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs, t/parse.t: In spec2srcheader(): extend stack; fudge
+	  with errno.
+
+2006-01-19 13:05  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs, t/parse.t: Return undef on spec parsing failure
+
+2006-01-19 12:52  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.pm: - add doc for Urpm_spec2srcheader
+
+2006-01-19 11:36  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* Makefile.PL, URPM.xs, t/parse.t: - add Urpm_spec2srcheader():
+	  return header of src.rpm from a specfile
+
+2006-01-06 16:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.30-2mdk
+
+2006-01-06 11:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, t/rpmdb.t: Use --qf in test to accomodate variations
+	  in %_query_all_fmt values
+
+2005-12-08 09:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Update copyrights
+
+2005-12-07 16:54  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.30
+
+2005-12-07 16:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm, perl-URPM.spec: Fix longstanding epoch
+	  promotion bug, caused by braindead API design
+
+2005-12-07 16:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Document trap in that braindead stupid API.
+
+2005-12-01 16:53  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Be verbose about the detected RPM version
+
+2005-12-01 13:57  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: RPMTAG_SERIAL (old name of RPMTAG_EPOCH) has been
+	  removed in rpm 4.4.3
+
+2005-11-30 13:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix a couple of compilation warnings
+
+2005-11-30 13:45  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Fix cast error
+
+2005-11-30 13:21  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: libbzip2 is actually not used by URPM.
+
+2005-11-15 16:14  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Add an URPM::Package::dump_flags method, to help
+	  debugging the depsolver
+
+2005-11-15 10:45  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ., .cvsignore: Ignore MakeMaker build files
+
+2005-11-02 14:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.29-1mdk
+
+2005-11-02 10:42  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Mention noscripts option in docs
+
+2005-10-28 14:30  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Doc neatification
+
+2005-10-28 14:15  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Require MDV::Packdrakeng in Makefile.PL
+
+2005-10-28 14:10  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm, t/parse.t: Use new MDV namespace
+
+2005-10-18 16:46  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: More docs for confusing method names
+
+2005-10-10 18:21  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Add the RPMPROB_FILTER_DISKNODES flag for running
+	  transactions with the
+	  nosize option. Although rpm doesn't seem to use it internally,
+	  it sets
+	  it on the --ignoresize command-line option.
+
+2005-10-04 12:19  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/parse.t: Don't require Packdrakeng for running tests
+
+2005-10-04 12:00  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Remove buildrequires on bzip2.
+	  Simplify buildreq_perl_devel conditional dependency per Buchan's
+	  suggestion.
+
+2005-10-03 09:25  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.28-1mdk
+
+2005-10-03 09:19  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Documentation encoding fix
+
+2005-10-03 09:17  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST, Makefile.PL, t/00prepare.t, t/parse.t,
+	  test-rpm-1.0-1mdk.noarch.rpm: Rebuild test rpm when running
+	  tests. Add cleanup to files.
+
+2005-10-03 08:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST: Update MANIFEST
+
+2005-10-03 08:38  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* build_rpm: Remove obsolete script
+
+2005-10-03 08:36  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Add an rpm makefile target
+
+2005-10-03 08:20  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Makefile.PL cleanup
+
+2005-09-14 13:17  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - add some options to parse_rpm (nomd5, nopayload)
+
+2005-09-12 15:13  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Minor comment fixes
+
+2005-09-09 12:54  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: 1.27-1mdk
+
+2005-09-09 12:53  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Make URPM::add_macro expand literal \n to \\\n
+	  in macro definitions.
+	  add URPM::add_macro_noexpand to get the old (rpmlib like)
+	  behaviour
+
+2005-09-01 16:19  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, perl-URPM.spec: 1.26-1mdk
+
+2005-09-01 15:43  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Add a "noscripts" option to run transactions. Inhibits
+	  pre, preun, post and
+	  postun scritps.
+
+2005-08-23 12:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.25-1mdk
+
+2005-08-23 12:15  Pixel <pixel at mandriva.com>
+
+	* URPM.xs: correctly handle -1 fileno returned by callback_open
+
+2005-08-23 10:33  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Doc fixes
+
+2005-08-18 15:54  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.24-3mdk
+
+2005-08-18 15:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Allow to rebuild URPM under non-C locales (Boris
+	  Filipovic)
+
+2005-07-28 05:06  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.24-2mdk
+
+2005-07-28 02:26  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Doc bits
+
+2005-07-28 02:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* README, URPM.pm, URPM.xs: update copyright and maintainer
+
+2005-07-04 09:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Documentation fix
+
+2005-06-30 05:01  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.24
+
+2005-06-30 04:58  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add function rpmErrorWriteTo($fd)
+
+2005-06-30 04:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: add rpmErrorString function
+
+2005-06-29 09:02  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Doclet
+
+2005-06-16 10:27  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Forgot to commit changelog
+
+2005-06-16 10:05  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.23-1mdk
+
+2005-06-16 10:03  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add a binding for rpm internal debugging
+	  function setVerbosity()
+
+2005-06-07 01:43  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.22-1mdk
+
+2005-06-01 09:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Warning fixes and documentation
+
+2005-06-01 03:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Ensure archs are identical
+
+2005-06-01 03:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Integrate a function to produce deltarpms
+
+2005-05-31 09:33  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.21-1mdk
+
+2005-05-31 08:45  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Removes obsolete code
+
+2005-05-30 09:37  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add the URPM::Package::payload_format method
+
+2005-05-11 06:58  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Remove the return value of
+	  compute_installed_flags, it's not used anywhere
+
+2005-05-10 13:11  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* perl-URPM.spec: - 0.3 for amd64
+
+2005-05-09 10:09  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.20-mdk
+
+2005-05-09 06:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Update buildrequires
+
+2005-05-09 05:37  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Make spec mandriva-compliant
+
+2005-05-04 03:06  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Don't hardcode distribution name
+
+2005-05-04 03:01  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.20-1mdk
+
+2005-05-02 10:58  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL, URPM.xs: Remove rpm 4.0 support
+
+2005-05-02 10:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Remove dead code
+
+2005-05-02 10:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Patch by Olivier Thauvin to adapt URPM for rpm 4.4
+
+2005-04-28 23:50  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* perl-URPM.spec: - use mkrel
+
+2005-04-28 16:44  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Fix bug 15628 : when no preferred locale is
+	  found, put locales-en in front of
+	  choice list
+
+2005-03-09 16:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: More RPMSENSE_PREREQ deprecation. (this should do
+	  nothing with rpm 4.2)
+
+2005-03-07 09:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.11-1mdk
+
+2005-03-03 09:37  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Speed optimisation for updating media
+
+2005-03-02 15:13  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.10-1mdk
+
+2005-03-02 14:38  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Prepare for obsolescence of PREREQ, introduce
+	  equivalent RPMSENSE_SCRIPT_* tags
+
+2005-02-15 12:54  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.09-1mdk
+
+2005-02-15 12:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Comments and indentation
+
+2005-02-15 11:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Force recomputation of rejected packages when
+	  deleting some in installation
+	  dependency resolution
+
+2005-02-11 14:17  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: POD fix.
+
+2005-02-11 14:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.08-1mdk
+
+2005-02-11 13:59  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Add macro handling code from Olivier Thauvin
+
+2005-02-02 09:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.07-4mdk
+
+2005-02-02 09:00  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Ooops, missing epoch
+
+2005-01-21 09:53  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.07-3mdk
+
+2005-01-20 20:35  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Require perl-base >= 5.8.6, so perl will be
+	  upgraded early in the process
+	  10.1 to 10.2
+
+2005-01-04 11:06  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Croak if build_base_files can't write files
+
+2004-12-21 15:38  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Typos in documentation
+
+2004-12-21 14:25  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Indentation and comments
+
+2004-12-13 17:21  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.07-2mdk
+
+2004-12-13 13:43  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.07-1mdk
+
+2004-12-13 13:34  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Return the list of chosen packages sorted by
+	  descending version
+	  (bug #12645).
+
+2004-12-09 15:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.06-1mdk
+
+2004-12-09 15:16  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: trust packdrake's defaults
+
+2004-12-09 15:10  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Remove external call to packdrake.
+
+2004-12-09 14:27  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/parse.t: Silence warnings
+
+2004-12-09 14:24  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/parse.t: Adjust test count
+
+2004-11-26 07:45  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.05-1mdk
+
+2004-11-25 19:18  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM/Build.pm: Inspired changes on top of Olivier's
+	  changes
+
+2004-11-25 14:28  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.pm, URPM/Build.pm, URPM/Resolve.pm: - allow to use an array
+	  of id instead (start .. end) in functions.
+
+2004-11-10 17:31  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.04-1mdk
+
+2004-11-10 17:26  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm: Version bump
+
+2004-11-10 17:14  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: When resolving dependencies, keep track of the
+	  packages that we just
+	  deselected because newer versions were found, but that were not
+	  actually
+	  installed.
+
+2004-11-10 14:17  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Indentation, documentation
+
+2004-10-27 09:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: Release for amd64
+
+2004-10-27 08:18  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Support for the 'strict-arch' option : upgrade
+	  only packages that have
+	  the same architecture than the one of the already-installed
+	  version.
+
+2004-10-25 12:04  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Comments
+
+2004-10-19 14:47  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, perl-URPM.spec: 1.03-2mdk
+
+2004-10-18 08:34  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: A few perl_checker fixes
+
+2004-10-18 08:31  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Patch by Gwenole Beauchesne to prefer packages
+	  which have the closest
+	  architecture compatibility over others when version/release are
+	  the same
+	  (using rpm's scoring system).
+
+2004-10-14 03:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Fix method description
+
+2004-10-13 02:35  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Small comment fixes
+
+2004-09-03 05:06  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: If $TMPDIR is not writable, don't use it
+
+2004-08-29 12:33  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* ChangeLog: Rebuild
+
+2004-08-29 12:29  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.pm, perl-URPM.spec: - 1.03
+
+2004-08-29 11:56  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs, t/parse.t: - backport rpmvercmp binding from perl-Hdlist
+
+2004-08-24 09:43  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.02-1mdk
+
+2004-08-24 09:29  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: From now, the nopromoteepoch argument will always
+	  default to 1
+
+2004-08-24 08:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, URPM.xs: Minor doc fixes
+
+2004-08-11 05:07  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.01-1mdk
+
+2004-08-11 04:57  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Don't panic on bad rpm fullnames
+
+2004-08-02 10:42  Fançois Pons
+
+	* URPM/Resolve.pm: fixed deadlock caused with libgc1 obsoleting
+	  itself ;-) and in the case were an
+	  older package is already installed and an older package is
+	  present in urpmi
+	  db. The problems comes with a badly interpreted comparison
+	  without an operator
+	  checked.
+
+2004-08-02 09:24  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 1.00 !
+
+2004-08-02 09:01  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Protection against packages that obsolete
+	  themselves.
+
+2004-08-02 08:42  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs, t/parse.t: - remove test that can't works
+
+2004-08-02 07:22  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - backward compatibility with perl 5.6
+
+2004-08-02 07:14  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* Makefile.PL: - don't check rpm rpm version but rpm binary version
+
+2004-08-02 00:27  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Silence a compilation warning
+
+2004-08-02 00:03  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm, URPM/Query.pm, URPM/Resolve.pm: Make perl_checker
+	  a bit more happy
+
+2004-07-30 09:03  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* perl-URPM.spec: put back lost 0.98-2mdk's changelog
+
+2004-07-30 07:48  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: 0.99-1mdk
+
+2004-07-30 06:10  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Resolution of requested packages: by default,
+	  don't propose a choice when
+	  multiple found packages are already installed.
+
+2004-07-28 08:47  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Build.pm: Use lexical filehandles.
+
+2004-07-22 09:39  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: Version 0.98
+
+2004-07-22 03:15  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs, t/parse.t: Add URPM::stream2header (borrowed from
+	  perl-Hdlist, thanks to Olivier
+	  Thauvin)
+
+2004-07-14 09:14  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* Makefile.PL, URPM.pm, perl-URPM.spec: - generate the manpage
+	  - 0.97
+
+2004-07-12 06:12  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* ChangeLog, URPM.pm, perl-URPM.spec: Version 0.96
+
+2004-07-12 01:23  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Don't use keys() in scalar context
+
+2004-07-12 01:04  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Add a ChangeLog target in the makefile
+
+2004-07-09 08:56  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Simplify the compute_flags function (used for
+	  the {skip,inst}.list files)
+
+2004-06-27 18:31  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - fix segfault in queryformat if tag does not exist
+	  (return nothing instead)
+
+2004-06-23 06:47  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs, t/fatal.t: Clarify error message when a synthesis file
+	  can't be read or gunzipped
+
+2004-05-21 11:33  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: 0.95-2mdk
+
+2004-05-21 11:19  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: Allow urpmi to downgrade packages if it was
+	  invoked with --allow-force
+
+2004-05-19 15:28  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Resolve.pm: When an rpm installed locally had a version
+	  greater than the one found
+	  in the update media, urpmi was trying to downgrade it.
+
+2004-05-06 09:42  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, perl-URPM.spec: Version 0.95
+
+2004-05-06 09:22  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST, URPM.pm, URPM.xs, URPM/Resolve.pm, t/fatal.t: Add a
+	  way to downgrade some errors (file not found) to non-fatal
+
+2004-04-30 08:32  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: 0.94-13mdk
+
+2004-04-27 05:56  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Query.pm: - fix tag2id on old mdk, ensure all test are ok
+	  on 9.1
+
+2004-04-26 14:40  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* t/parse.t: Silence warnings
+
+2004-04-25 21:33  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs, t/parse.t: - make parse.t pass all test
+	  - add $pkg->queryformat test
+
+2004-04-25 10:44  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.pm, URPM.xs, URPM/Query.pm: - add $pkg->queryformat()
+	  function
+	  - $ûrpm->list_rpm_tag show all tag, value for unparsable tag is
+	  'undef' in hash
+
+2004-04-23 13:55  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* ChangeLog: *** empty log message ***
+
+2004-04-23 08:01  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - urpm optional arg to Urpm_list_rpm_tag function
+
+2004-04-22 14:14  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Better diagnostics in $package->build_info()
+
+2004-04-22 09:54  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* t/parse.t: - test rpm parsing and hdlist generation
+
+2004-04-22 09:28  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST: Add missing files in the MANIFEST
+	* perl-URPM.spec: Remove hardcoded packager
+
+2004-04-22 06:40  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Build.pm: - Don't pass whole %options to parse_rpm in
+	  parse_rpms_build_headers
+
+2004-04-22 06:34  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.xs: (return_list_tag) factorize common local variables
+	  declaration (though
+	  it wastes 4 pointer slots on stack in RPMTAG_SUMMARY case)
+
+2004-04-22 05:43  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Query.pm, t/parse.t, test-rpm-1.0-1mdk.noarch.rpm,
+	  test-rpm.spec: - remove unusefull function
+	  - start to add parsing test
+
+2004-04-22 05:33  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Build.pm: - export keep_all_tags trought function in
+	  parse_rpm_build_headers
+
+2004-04-22 05:32  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - return_list_tag is able to return some basic tags
+	  from synthesis
+
+2004-04-21 13:13  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.xs: - cleaning return_list_tag
+
+2004-04-21 09:25  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM.pm, URPM.xs, URPM/Query.pm: - add list_rpm_tag function
+
+2004-04-21 09:17  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* perl-URPM.spec: 0.94-12mdk
+
+2004-04-21 09:16  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Signature.pm: More cleanup.
+
+2004-04-21 09:15  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Don't install manpages.
+
+2004-04-21 08:08  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM/Signature.pm: Minor cleanup
+
+2004-04-18 23:15  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Build.pm, URPM/Query.pm: - add query_pkg function
+	  - transmit %options to parse_rpm in parse_rpms_build_headers
+
+2004-04-17 23:31  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Build.pm, URPM/Query.pm: - add Query.pm (starting to code)
+	  - add fuzzy_parse function, transparency parse hdlist,
+	  synthesis, rpms or dir (dir/*.rpm)
+	  - add parse_rpms function to have same behaviours than
+	  parse_{hdlists,synthesis}
+
+2004-04-15 09:34  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.xs: Improve some diagnostics
+
+2004-04-09 15:51  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* Makefile.PL: Force INSTALLDIRS=vendor in the Makefile.PL, for
+	  local testing
+
+2004-04-06 14:41  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* URPM.pm, t/rpmdb.t, t/synthesis.t: Deprecate the pseudo-packages
+	  URPM::Build, URPM::Resolve and URPM::Signature.
+	  Documentation fixes. Tidy up the tests (and add a few ones.)
+
+2004-04-02 14:02  Rafael Garcia-Suarez <rgarciasuarez at mandriva.com>
+
+	* MANIFEST, Makefile.PL, URPM.pm, t/synthesis.t: Add some API
+	  documentation for the URPM module.
+	  Plus, some minor nits in auxiliary files.
+
+2004-04-01 10:40  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* ChangeLog: *** empty log message ***
+
+2004-02-25 22:35  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* perl-URPM.spec: 0.94-11mdk
+
+2004-01-18 02:25  Olivier Thauvin <thauvin at aerov.jussieu.fr>
+
+	* URPM/Build.pm: - parse_rpm_build_headers have same behaviour
+	  with dontdie and callback
+	  when using cache or the rpm
+
+2004-01-15 18:20  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* ChangeLog: *** empty log message ***
+
+2003-12-09 19:40  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: added support for RH
+	  7.3
+
+2003-11-17 21:01  Fançois Pons
+
+	* perl-URPM.spec: 0.98-9mdk
+
+2003-11-17 20:59  Fançois Pons
+
+	* URPM/Build.pm: fixed bad use of option idlist for checking its
+	  presence
+
+2003-11-15 19:47  Fançois Pons
+
+	* perl-URPM.spec: 0.94-8mdk
+
+2003-11-15 19:44  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm: fixed indentation and reworked code to
+	  be simpler
+
+2003-11-15 19:33  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm: applied patch from Olivier Thauvin
+
+2003-10-13 12:36  Fançois Pons
+
+	* perl-URPM.spec: 0.94-7mdk
+
+2003-10-13 12:34  Fançois Pons
+
+	* URPM/Resolve.pm: fixed to find package with full provides on
+	  whatrequires obsoleted, so that
+	  pam-devel is upgraded correctly for example.
+
+2003-09-10 15:12  Fançois Pons
+
+	* perl-URPM.spec: 0.94-6mdk
+
+2003-09-10 15:11  Fançois Pons
+
+	* URPM/Resolve.pm: removed STDERR log.
+	* URPM/Resolve.pm: diff_provides on obsoleted provides are needed.
+
+2003-09-10 11:46  Fançois Pons
+
+	* perl-URPM.spec: 0.94-5mdk
+
+2003-09-10 11:45  Fançois Pons
+
+	* URPM/Resolve.pm: fixed bad ARRAY reference (promote).
+
+2003-09-05 10:33  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.94-4mdk
+
+2003-09-02 17:19  Fançois Pons
+
+	* perl-URPM.spec: 0.94-3mdk
+	* URPM/Resolve.pm: removed log.
+
+2003-09-02 17:18  Fançois Pons
+
+	* URPM/Resolve.pm: fixed package badly removed.
+
+2003-08-22 13:53  Fançois Pons
+
+	* perl-URPM.spec: 0.94-2mdk
+
+2003-08-22 13:52  Fançois Pons
+
+	* URPM/Resolve.pm: removed potential deadlock.
+
+2003-08-21 13:04  Fançois Pons
+
+	* URPM.pm, URPM/Signature.pm, perl-URPM.spec: 0.94-1mdk
+	  (URPM::Signature fixes and changes)
+
+2003-08-21 11:25  Fançois Pons
+
+	* URPM/Signature.pm: fixed with gc suggestion which are really
+	  fine (and right).
+
+2003-08-20 16:17  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: final 0.93-7mdk
+
+2003-08-20 15:10  Fançois Pons
+
+	* URPM.pm, URPM/Signature.pm, perl-URPM.spec: 0.93-7mdk (signature
+	  comparison workaround)
+
+2003-08-19 16:33  Fançois Pons
+
+	* perl-URPM.spec: 0.93-6mdk
+
+2003-08-19 16:32  Fançois Pons
+
+	* URPM.xs: added URPM::import_pubkey to import a key (only one)
+	  directly to opened rpm
+	  database or by opening the database on the fly.
+
+2003-08-19 16:31  Fançois Pons
+
+	* URPM/Signature.pm: fixed URPM::import_armored_file to use
+	  internal XS function to import directly
+	  to database, handle importation of multiple keys by file.
+
+2003-08-18 15:29  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm, perl-URPM.spec: perl_checker compliance
+
+2003-08-13 12:04  Guillaume Cottenceau
+
+	* perl-URPM.spec: provide URPM::Signature as well
+
+2003-08-11 15:27  Fançois Pons
+
+	* perl-URPM.spec: 0.93-3mdk
+	* URPM.xs: fixed files_md5sum returning not the same number as
+	  files method.
+	  removed unsatisfied_requires2 not used (and doing nothing
+	  usefull).
+
+2003-08-11 14:04  Fançois Pons
+
+	* URPM/Signature.pm, perl-URPM.spec: 0.93-2mdk
+
+2003-08-06 17:45  Fançois Pons
+
+	* URPM/Signature.pm: final 0.93-1mdk
+
+2003-08-06 15:54  Fançois Pons
+
+	* URPM.pm, URPM/Build.pm, URPM/Signature.pm, perl-URPM.spec:
+	  0.93-1mdk
+
+2003-08-06 09:52  Fançois Pons
+
+	* MANIFEST: added signature management.
+
+2003-08-06 09:50  Fançois Pons
+
+	* URPM/Signature.pm: initial support for parsing armored file
+	  (without gpg) and registering rpmdb pubkeys.
+
+2003-08-04 17:51  Fançois Pons
+
+	* MANIFEST, URPM/Resolve.pm, perl-URPM.spec: 0.92-4mdk
+
+2003-08-01 19:29  Pixel <pixel at mandriva.com>
+
+	* perl-URPM.spec: - rebuild for new perl (it helps DrakX build
+	  script)
+	  - use DESTDIR
+
+2003-07-30 16:59  Fançois Pons
+
+	* perl-URPM.spec: 0.92-2mdk
+
+2003-07-30 16:57  Fançois Pons
+
+	* URPM/Resolve.pm: fixed some missing unsatisfied in reason of
+	  rejected packages.
+	  fixed provide obsoleted which should not be taken into account
+	  when looking for
+	  obsoletes.
+
+2003-07-28 15:13  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.92-1mdk
+
+2003-07-24 15:28  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-14mdk
+
+2003-07-24 10:10  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm, URPM/Resolve.pm, perl-URPM.spec:
+	  0.91-13mdk
+
+2003-07-16 13:34  Fançois Pons
+
+	* perl-URPM.spec: 0.91-12mdk
+
+2003-07-16 13:10  Fançois Pons
+
+	* URPM/Build.pm: fixed cache not taken into account.
+
+2003-07-16 12:07  Fançois Pons
+
+	* URPM/Resolve.pm: fixed small typo on regex for
+	  URPM::compute_flags
+
+2003-07-10 16:09  Fançois Pons
+
+	* URPM.xs: fixed SvPV typos.
+
+2003-07-10 16:05  Fançois Pons
+
+	* perl-URPM.spec: 0.91-11mdk
+
+2003-07-10 16:04  Fançois Pons
+
+	* Makefile.PL: removed -f-no-rtti as no C++ code is used.
+
+2003-07-10 16:03  Fançois Pons
+
+	* URPM.xs: starting coding unsatisfied_requires in C, incomplete.
+	  modified return_list_str to allow getting strings list in C
+	  easily and quickly.
+
+2003-07-10 16:02  Fançois Pons
+
+	* URPM/Resolve.pm: optimized URPM::compute_flags method by an
+	  almost unlimited factor.
+
+2003-07-07 17:28  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-10mdk
+
+2003-07-07 15:14  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-9mdk
+
+2003-07-04 12:18  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-8mdk
+
+2003-06-26 15:26  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-7mdk
+
+2003-06-19 14:24  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-6mdk
+
+2003-06-19 11:12  Fançois Pons
+
+	* URPM.xs: make sure a callback parameter is taken into account
+	  only if a reference is
+	  used.
+
+2003-06-19 10:31  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-5mdk
+
+2003-06-18 17:02  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: added missing fix on bad
+	  conflicts listing,
+	  removed stderr logs.
+
+2003-06-18 16:53  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-4mdk
+
+2003-06-18 16:14  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-4mdk
+
+2003-06-18 11:52  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.91-3mdk
+
+2003-06-17 15:59  Fançois Pons
+
+	* perl-URPM.spec: added compilable on rpm-4.0.4 of rpm.
+
+2003-06-17 15:54  Fançois Pons
+
+	* URPM.xs: fixed compilation on rpm 4.0.4.
+
+2003-06-17 15:35  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: fixed 0.91-2mdk
+
+2003-06-17 13:39  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.91-2mdk
+
+2003-06-16 17:57  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec, t/rpmdb.t:
+	  0.91-1mdk
+
+2003-06-12 15:52  Fançois Pons
+
+	* perl-URPM.spec: 0.90-10mdk
+	* URPM.xs: improved return value of verify_rpm.
+
+2003-06-11 15:42  Fançois Pons
+
+	* URPM/Resolve.pm: removed $v-> (for rejected hash value) by $rv
+	  in order to avoid name clash
+	  with $v (version).
+
+2003-06-11 11:34  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.90-9mdk
+
+2003-06-05 18:41  Fançois Pons
+
+	* URPM.xs: fixed memory leak in parse_rpm.
+
+2003-06-05 17:46  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.90-8mdk
+
+2003-06-05 13:53  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.90-7mdk
+
+2003-06-05 08:47  Fançois Pons
+
+	* URPM/Build.pm, URPM/Resolve.pm: added clever cache header
+	  management during build of hdlist.
+	  removed no_flag_update obsoleted.
+
+2003-06-04 09:47  Warly <warly at mandriva.com>
+
+	* URPM.xs, perl-URPM.spec: Add Pkg_buildtime to get
+	  RPMTAG_BUILDTIME
+
+2003-06-03 10:21  Fançois Pons
+
+	* perl-URPM.spec: a newer version for a newer package.
+
+2003-06-03 10:14  Fançois Pons
+
+	* URPM.xs: fixed sutpid typo (strange compiler didn't notice
+	  anything)
+
+2003-06-02 16:38  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.90-4mdk
+
+2003-05-30 11:32  Warly <warly at mandriva.com>
+
+	* URPM.xs: move packing and keep_all_tags declaration in
+	  Urpm_parse_rpm to the begining of the function in order to get
+	  the argument initialisation correctly working (otherwize they
+	  were overriden and systematically set to 0).
+
+2003-05-30 10:11  Warly <warly at mandriva.com>
+
+	* URPM.xs, perl-URPM.spec: add Pkg_license function to URPM.xs
+	  (URPM::Package)
+
+2003-05-26 15:13  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.90-2mdk
+
+2003-05-23 15:26  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.90-1mdk
+	  first backtrackable method, still lacking backtrack of remove and
+	  better handling of choices during backtrack, too much simplist.
+
+2003-05-16 15:11  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.84-1mdk
+
+2003-05-14 17:43  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.83-4mdk
+
+2003-05-13 21:02  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm, perl-URPM.spec: 0.83-3mdk
+
+2003-05-13 20:46  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM/Build.pm: perl_checker fixes
+
+2003-05-13 20:35  Thierry Vignaud <tvignaud at mandriva.com>
+
+	* URPM.pm: perl_checker fix
+
+2003-05-12 16:43  Guillaume Cottenceau
+
+	* perl-URPM.spec: - rebuild for new perl requires/provides
+	  - provide perl packages URPM::Resolve and URPM::Build since the
+	  perl packages are URPM for object export
+
+2003-04-29 17:16  Fançois Pons
+
+	* Makefile.PL, URPM.pm, URPM.xs, build_rpm, perl-URPM.spec: first
+	  try of 4.2 compatible perl-URPM,
+	  missing verify_signature,
+	  new version 0.83
+
+2003-04-24 15:51  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.82-4mdk
+
+2003-04-22 14:35  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.82-3mdk
+
+2003-04-14 13:07  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.82-2mdk
+
+2003-04-11 16:29  Fançois Pons
+
+	* URPM/Resolve.pm: fixed stupid typo in compute_skip_flags
+
+2003-04-11 16:06  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: brand new
+	  0.82 version (flag_skip, excludedocs, fix NULL get_name)
+
+2003-03-12 18:16  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.81-13mdk
+
+2003-03-10 16:44  Fançois Pons
+
+	* URPM.pm, URPM/Build.pm, URPM/Resolve.pm, perl-URPM.spec:
+	  0.81-12mdk
+
+2003-03-03 13:09  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.81-11mdk
+
+2003-02-27 13:22  Fançois Pons
+
+	* perl-URPM.spec: 0.81-10mdk
+
+2003-02-27 13:13  Fançois Pons
+
+	* URPM/Resolve.pm: allow choices to return multiple selection.
+
+2003-02-19 13:28  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.81-9mdk
+
+2003-02-13 18:37  Fançois Pons
+
+	* perl-URPM.spec: 0.81-8mdk
+
+2003-02-13 17:53  Fançois Pons
+
+	* URPM/Resolve.pm: fix rpmdrake woes on incompatible arch.
+
+2003-01-23 14:29  Fançois Pons
+
+	* URPM/Build.pm, URPM/Resolve.pm, perl-URPM.spec: 0.81-7mdk
+
+2003-01-06 16:33  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.81-6mdk
+
+2003-01-06 11:25  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.81-5mdk
+
+2002-12-20 11:05  Pixel <pixel at mandriva.com>
+
+	* URPM/Resolve.pm, perl-URPM.spec: perl_checker fixes (syntax only)
+
+2002-12-18 14:57  Pixel <pixel at mandriva.com>
+
+	* URPM.pm, perl-URPM.spec: help perl_checker recognise packages
+	  used as classes
+
+2002-12-18 12:54  Pixel <pixel at mandriva.com>
+
+	* URPM.pm, perl-URPM.spec: perl_checker fixes
+
+2002-12-17 13:57  Fançois Pons
+
+	* URPM.pm, perl-URPM.spec: added very faster code, 3 times faster
+	  on traverse_tag with --env.
+
+2002-12-17 13:46  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.81-1mdk
+
+2002-12-11 11:27  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.80-2mdk
+
+2002-12-05 17:58  Fançois Pons
+
+	* URPM.pm, URPM.xs, perl-URPM.spec: 0.80-1mdk
+
+2002-12-03 14:43  Fançois Pons
+
+	* URPM.pm, URPM.xs, perl-URPM.spec: 0.71-1mdk
+
+2002-09-17 13:16  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-10mdk
+
+2002-09-09 14:25  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-9mdk
+
+2002-09-02 14:46  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-8mdk
+
+2002-08-30 15:52  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-7mdk
+
+2002-08-30 13:08  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-6mdk
+
+2002-08-29 15:48  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-5mdk
+
+2002-08-29 09:41  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.70-4mdk
+
+2002-08-28 14:15  Fançois Pons
+
+	* perl-URPM.spec: added URL (cvsweb at least).
+
+2002-08-28 14:06  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.70-3mdk
+
+2002-08-26 18:29  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.70-2mdk
+
+2002-08-23 13:08  Fançois Pons
+
+	* URPM.pm: fixed VERSION to 0.70.
+
+2002-08-23 13:06  Fançois Pons
+
+	* URPM.pm, perl-URPM.spec: 0.70-1mdk.
+
+2002-08-13 10:05  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-8mdk
+
+2002-08-12 16:00  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-7mdk
+
+2002-08-12 13:34  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-6mdk
+
+2002-08-09 17:12  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-5mdk
+
+2002-08-09 16:47  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-4mdk
+
+2002-08-07 14:25  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.60-3mdk
+
+2002-08-06 15:04  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.60-2mdk
+
+2002-08-05 16:57  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.60-1mdk
+
+2002-07-25 11:19  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.50-6mdk
+
+2002-07-25 07:27  Fançois Pons
+
+	* perl-URPM.spec: 0.50-5mdk
+
+2002-07-25 07:08  Fançois Pons
+
+	* URPM/Build.pm: fixed typo (stupid).
+
+2002-07-24 12:36  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm, URPM/Resolve.pm, perl-URPM.spec:
+	  0.50-4mdk
+
+2002-07-24 09:18  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.50-3mdk
+
+2002-07-23 15:14  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.50-2mdk
+
+2002-07-23 13:17  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.50-1mdk
+
+2002-07-23 11:59  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.20-2mdk
+
+2002-07-22 17:53  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.20-1mdk
+
+2002-07-22 08:35  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.11-2mdk
+
+2002-07-19 08:50  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.11-1mdk
+
+2002-07-16 18:07  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.10-2mdk
+
+2002-07-15 16:53  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.10-1mdk
+
+2002-07-11 13:14  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.09-2mdk
+
+2002-07-10 10:19  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.09-1mdk
+
+2002-07-09 15:06  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm, perl-URPM.spec: 0.08-4mdk
+
+2002-07-09 10:55  Pixel <pixel at mandriva.com>
+
+	* perl-URPM.spec: adapt to perl 5.8.0
+
+2002-07-08 14:47  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.08-2mdk
+
+2002-07-08 09:55  Fançois Pons
+
+	* URPM.pm, URPM.xs, perl-URPM.spec: 0.08-1mdk
+
+2002-07-05 15:25  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.07-2mdk
+
+2002-07-04 17:53  Fançois Pons
+
+	* URPM.pm, URPM.xs, perl-URPM.spec, typemap: 0.07-1mdk
+
+2002-07-03 16:11  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.06-2mdk
+
+2002-07-03 12:40  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Build.pm, URPM/Resolve.pm,
+	  perl-URPM.spec: 0.06-1mdk
+
+2002-07-01 11:55  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.05-2mdk
+
+2002-06-28 08:44  Fançois Pons
+
+	* URPM.pm, URPM/Resolve.pm, perl-URPM.spec: 0.05-1mdk
+
+2002-06-26 12:37  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.04-6mdk
+
+2002-06-18 14:17  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.04-5mdk
+
+2002-06-13 17:56  Fançois Pons
+
+	* URPM/Resolve.pm, perl-URPM.spec: 0.04-4mdk
+
+2002-06-13 16:16  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec: 0.04-3mdk
+
+2002-06-13 15:19  Fançois Pons
+
+	* URPM/Resolve.pm: added compute_installed_flags for yoyotte.
+
+2002-06-13 10:48  Fançois Pons
+
+	* perl-URPM.spec: 0.04-2mdk
+
+2002-06-13 10:24  Fançois Pons
+
+	* URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.04-1mdk
+
+2002-06-11 18:02  Fançois Pons
+
+	* MANIFEST: added missing entry Resolve.pm
+
+2002-06-11 17:59  Fançois Pons
+
+	* URPM.pm, URPM.xs, URPM/Resolve.pm, perl-URPM.spec: 0.04-1mdk
+
+2002-06-06 15:44  Fançois Pons
+
+	* URPM.pm, URPM.xs, perl-URPM.spec: 0.03-2mdk
+
+2002-06-06 09:57  Fançois Pons
+
+	* URPM.pm, URPM.xs, build_rpm, perl-URPM.spec: 0.03-1mdk
+
+2002-06-05 16:44  Fançois Pons
+
+	* URPM.xs, perl-URPM.spec, t/rpmdb.t: 0.02-3mdk
+
+2002-06-05 08:03  Fançois Pons
+
+	* URPM.xs, URPM/Build.pm, perl-URPM.spec: log on rpmdb open/close.
+
+2002-06-03 11:00  Fançois Pons
+
+	* URPM.pm, URPM/Build.pm, perl-URPM.spec: cleaned URPM::Build to
+	  accept extended parameter list and -w clean.
+	  0.02.
+
+2002-05-31 10:48  Fançois Pons
+
+	* perl-URPM.spec: added Packager field.
+
+2002-05-31 10:45  Fançois Pons
+
+	* build_rpm, perl-URPM.spec: initial revision.
+
+2002-05-31 10:21  Fançois Pons
+
+	* MANIFEST, Makefile.PL, README, URPM, URPM.pm, URPM.xs,
+	  URPM/Build.pm, t, t/rpmdb.t, t/synthesis.t, typemap: initial
+	  revision.
+
+2002-05-31 10:21  
+
+	* soft/rpm/perl-URPM/branches, soft/rpm/perl-URPM/tags, .: New
+	  repository initialized by cvs2svn.
+

Added: rpm/perl-URPM/trunk/MANIFEST
===================================================================
--- rpm/perl-URPM/trunk/MANIFEST	                        (rev 0)
+++ rpm/perl-URPM/trunk/MANIFEST	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,22 @@
+README
+MANIFEST
+Makefile.PL
+typemap
+URPM.xs
+URPM.pm
+URPM/Build.pm
+URPM/Query.pm
+URPM/Resolve.pm
+URPM/Signature.pm
+t/00prepare.t
+t/buggy_synthesis.cz
+t/empty_synthesis.cz
+t/fatal.t
+t/parse.t
+t/pod.t
+t/rpmdb.t
+t/sort_graph.t
+t/synthesis.t
+t/test-rpm.spec
+ChangeLog
+META.yml                                 Module meta-data (added by MakeMaker)

Added: rpm/perl-URPM/trunk/META.yml
===================================================================
--- rpm/perl-URPM/trunk/META.yml	                        (rev 0)
+++ rpm/perl-URPM/trunk/META.yml	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,11 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
+name:         URPM
+version:      1.43
+version_from: URPM.pm
+installdirs:  site
+requires:
+    MDV::Packdrakeng:              1.00
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.30_01

Added: rpm/perl-URPM/trunk/Makefile.PL
===================================================================
--- rpm/perl-URPM/trunk/Makefile.PL	                        (rev 0)
+++ rpm/perl-URPM/trunk/Makefile.PL	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,74 @@
+use strict;
+use ExtUtils::MakeMaker;
+
+# where to find the rpm utility
+
+my $rpm_path = $ENV{RPM_PATH}; # this overrides
+
+unless (defined $rpm_path) {
+    for (qw(/bin/rpm /usr/bin/rpm)) {
+	if (-x) {
+	    $rpm_path = $_;
+	    last;
+	}
+    }
+}
+
+defined $rpm_path or die "Can't find rpm on this system\n";
+
+sub hexversion {
+	my ($major, $minor, $micro) = (@_[0] =~ /(\d+)\.(\d+)\.?(\d+)?/);
+	return int($major<<16) + int($minor<<8) + int($micro<<0)
+}
+
+my $version = `LC_ALL=C $rpm_path --version`;
+# fix compiling with RCs:
+$version =~ s/(-.*)|(\.DEVEL)//;
+chomp $version;
+$version =~ s/(RPM version )|(rpm \(RPM\) )//;
+my $hversion = hexversion($version);
+$hversion ge hexversion("4.2") or die "Unable to build URPM with too old (or undetected) rpm version $version\n";
+
+# to generate the ChangeLog depending on the checkout layout
+my $commonusername = "../common/";
+-d $commonusername or do {
+    $commonusername = "../../common/";
+    -d $commonusername or do {
+	$commonusername = "../../../common/";
+	-d $commonusername or $commonusername = "";
+    };
+};
+
+sub MY::postamble {
+    <<"**MM**";
+.PHONY: ChangeLog
+
+ChangeLog:
+	LC_ALL=C svn2cl --accum --strip-prefix=soft/rpm/perl-URPM/trunk --authors ${commonusername}username.xml
+	rm -f *.bak
+**MM**
+}
+
+my @rpmflags;
+my $ldflags = `pkg-config --libs rpm`;
+if ($hversion ge hexversion("4.4.90") && $hversion lt hexversion("5.0")) {
+    # rpm.org version
+    push @rpmflags, "-DRPM_ORG";
+    $ldflags .= ' -lrpmbuild';
+}
+my $ccflags = join(' ', '-Wall -Wextra -fno-strict-aliasing', @rpmflags);
+
+print "Found RPM version $version (compiling with flags: $ccflags)\n";
+
+WriteMakefile(
+    NAME	=> 'URPM',
+    PREREQ_PM	=> {
+	'MDV::Packdrakeng' => '1.00',
+    },
+    CCFLAGS	=> $ccflags,
+    VERSION_FROM	=> 'URPM.pm',
+    LIBS	=> [ $ldflags ],
+    INC		=> '-I/usr/include/rpm',
+    dist	=> { COMPRESS => "bzip2", SUFFIX => ".bz2" },
+    realclean	=> { FILES => "t/RPMS/noarch/*" },
+);

Added: rpm/perl-URPM/trunk/NEWS
===================================================================
--- rpm/perl-URPM/trunk/NEWS	                        (rev 0)
+++ rpm/perl-URPM/trunk/NEWS	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,426 @@
+Version 3.38 - 16 November 2010
+
+- fix the key parsing to handle PEM encapsulated header portion (bug
+#61636)
+
+Version 3.37 - 20 September 2010
+
+- fix crashing on undefined packages (#54521)
+
+Version 3.36 - 23 July 2010
+
+- Fix wrong deferencement on HASH (warning triggered by perl 5.12)
+
+Version 3.35 - 23 April 2010
+
+- when using auto-select, honour search-medias if some were specified
+
+Version 3.34.1 - 23 March 2010
+
+- check selected packages for unsatisfied requires when a promoted package is
+  backtracked and no replacement is found (#57224, Anssi Hannula)
+
+Version 3.34 - 24 February 2010
+
+- check for conflicting selected packages before selecting a package (#57224)
+  (by Anssi Hannula)
+
+Version 3.33 - 5 October 2009, by Christophe Fergeau
+
+- fix lookup of existing pubkeys (#53710) (by Pascal Terjan)
+
+Version 3.32 - 10 August 2009, by Christophe Fergeau
+
+- backtrack_selected: use set_rejected_and_compute_diff_provides for package
+  removal (Anssi Hannula)
+- obey options (keep, nodeps) when unselecting current package in the case
+  that was added in 3.31 (Anssi Hannula)
+
+Version 3.31 - 28 July 2009, by Christophe Fergeau
+
+- add support for querying %disttag & %distepoch (by Per Øyvind Karlsen)
+- clean up and bring back rpm5.org support (by Per Øyvind Karlsen)
+- keep track of sources for obsoleted/removed levels (#50666) Anssi Hannula)
+- keep psel/promote info and remove deadlocked pkg instead of aborting upgrade
+  (#52105, Anssi Hannula)
+- _handle_conflicts: check all provides for conflicts, not just package name
+  (#52135, Anssi Hannula)
+- unselect current package if an avoided package is already selected (#52145,
+  Anssi Hannula)
+- do not try to promote to an older package (#52460, Anssi Hannula)
+- add a backtrack entry "conflicts" for avoided packages in backtrack_selected
+  (#52153, Anssi Hannula)
+
+Version 3.30 - 11 May 2009, by Christophe Fergeau
+
+- rework public key handling since librpm behaviour has changed. It's no longer
+  possible to tell it to add the same key multiple times which was causing
+  weird "unable to import pubkey" messages when a mirror contains different
+  pubkeys for the same key, fixes #50383
+
+Version 3.29 - 27 March 2009, by Christophe Fergeau
+
+- fix regression introduced by fix for bug #47803 (fix by Anssi Hannula).
+  Without this patch, urpmi got stuck in an infinite loop when trying 
+  to upgrade from 2008.1.
+
+Version 3.28 - 25 March 2009, by Christophe Fergeau
+
+- postpone user choices as much as possible to avoid asking the user
+  unnecessary questions, (bug #48100, Anssi Hannula)
+
+Version 3.27 - 24 March 2009, by Christophe Fergeau
+
+- don't silently install suggests (bug #47934)
+- fix _handle_diff_provides in case of impossible-to-satisfy selected 
+  packages (bug #48223, Anssi Hannula)
+- check rep for another pkg providing X if the prev pkg gets removed 
+  due to a conflict (bug #47803, Anssi Hannula)
+
+Version 3.26 - 5 March 2009, by Thierry Vignaud
+
+- verify_signature: enable to check signatures against a chrooted rpmdb
+  (especially important for installer where there's no rpmdb in / and thus no
+  keys to check against)
+
+Version 3.25 - 16 January 2009, by Christophe Fergeau
+
+- previous fix for bug #46874 was bogus, really fix it this time
+
+Version 3.24 - 13 January 2009, by Christophe Fergeau
+
+- fix sorting choices on provided version (feature introduced in 3.08, 
+  but was not working if packages were coming from different repository)
+- when a "Requires:" can be fullfilled by several different packages and
+  one of those packages is explicitly required by another package which
+  is also being installed, silently choose this package instead of letting
+  the choice up to perl-URPM user (fixes bug #46874)
+
+Version 3.23 - 12 December 2008, by Pascal "Pixel" Rigaux
+
+- fix bad free() (thanks to glibc for detecting it)
+
+Version 3.22 - 12 December 2008, by Pascal "Pixel" Rigaux
+
+- fix scriptlet failing:
+  adapt to librpm4.6, rpmtsSetRootDir(ts, "") is forbidden 
+
+Version 3.21 - 9 December 2008, by Pascal "Pixel" Rigaux
+
+- adapt to librpm4.6
+- drop list_rpm_tag()
+
+Version 3.20 - 14 October 2008, by Pascal "Pixel" Rigaux
+
+- $trans->run can now return both the translated errors, and some parsable
+  errors (useful for example to detect diskspace issues)
+ 
+Version 3.19 - 7 October 2008, by Pascal "Pixel" Rigaux
+
+- handle flag "replacefiles"
+
+Version 3.18 - 7 July 2008, by Pascal "Pixel" Rigaux
+
+- revert change introduced in 3.16 (it breaks too much, eg
+  superuser--priority-upgrade.t test case), and introduce
+  $state->{rejected_already_installed} instead
+
+Version 3.17 - 4 July 2008, by Pascal "Pixel" Rigaux
+
+- add traverse_tag_find(), removed_or_obsoleted_packages()
+- handle $state->{orphans_to_remove} in selected_size() and
+  build_transaction_set()
+
+Version 3.16 - 26 June 2008, by Pascal "Pixel" Rigaux
+
+- when not selecting a package because already installed,
+  put it in $state->{rejected} with flags {installed}
+
+Version 3.15 - 23 June 2008, by Pascal "Pixel" Rigaux
+
+- fix urpmi wrongly considering epochless conflicts to match any epoch in a
+  case when urpmi should upgrade a conflicting package to an actually
+  non-conflicting version (cf epochless-conflict-with-promotion urpmi test)
+  (Anssi)
+
+Version 3.14 - 23 May 2008, by Pascal "Pixel" Rigaux
+
+- add is_package_installed() in URPM/Resolve.pm
+  (to be used in urpmi 5.20)
+
+Version 3.13 - 20 May 2008, by Pascal "Pixel" Rigaux
+
+- do not ignore dropped provide from updated package (mdvbz#40842)
+
+Version 3.12 - 7 March 2008, by Pascal "Pixel" Rigaux
+
+- do allow to promoting a pkg even if it has unsatisfied require (since the
+  code will then fix the unsatisfied require). fixes "big transaction" 
+  (cf urpmi split-transactions--strict-require.t test_efgh())
+- rpm5.org port done (by Per Øyvind Karlsen)
+
+Version 3.11 - 26 February 2008, by Pascal "Pixel" Rigaux
+
+- restore FILENAME_TAG in generated hdlist (to be compatible with older
+  distros where ->filename can rely on it) (thanks to Nanar)
+
+Version 3.10 - 26 February 2008, by Pascal "Pixel" Rigaux
+
+- add filesize to synthesis, add ->filesize to get it, and add
+  selected_size_filesize() to compute the sum
+- allow urpmi to know a package was not selected because a newer version is
+  installed (#29838)
+- handle new package providing xxx which conflicts with an installed package (#17106)
+- fix sort choices changed in perl-URPM 3.08
+- allow fixing "using one big transaction" that occurs when using --keep 
+  (#30198)
+- do not add FILENAME_TAG and FILESIZE_TAG to hdlist anymore,
+  deprecate ->header_filename,
+  deprecate URPM::Build::parse_rpms_build_headers
+
+Version 3.08 - 25 February 2008, by Pascal "Pixel" Rigaux
+
+- sort choices on virtual package by provided version (#12645)
+
+Version 3.07 - 11 January 2008, by Pascal "Pixel" Rigaux
+
+- add URPM::Package->changelogs, a wrapper around ->changelog_time, ->changelog_name, ->changelog_text
+- resolve kmod requires even if first choice is a source dkms
+
+Version 3.05 - 8 January 2008, by Pascal "Pixel" Rigaux
+
+- fix regression in ->parse_rpm (introduced in 3.00) 
+  (was breaking genhdlist2 and mkcd)
+
+Version 3.04 - 20 December 2007, by Pascal "Pixel" Rigaux
+
+- fix regression in parse_pubkeys() (introduced in 3.00) (#36121)
+
+Version 3.03 - 14 December 2007, by Pascal "Pixel" Rigaux
+
+- suggests: 
+  handle both RPMTAG_SUGGESTSNAME (as done in SuSE and in Mandriva > 2008.0)
+  and RPMTAG_REQUIRENAME + RPMSENSE_MISSINGOK (as done in Mandriva 2008.0)
+
+Version 3.02 - 14 December 2007, by Pascal "Pixel" Rigaux
+
+- fix "make test" on rpm 4.4.2.2
+- fix rpm 4.5 support
+
+Version 3.01 - 11 December 2007, by Pascal "Pixel" Rigaux
+
+- add URPM::DB::verify()
+
+Version 3.00 - 11 December 2007, by Pascal "Pixel" Rigaux
+
+- replace ->import_needed_pubkeys and ->import_pubkey in favor of
+  import_needed_pubkeys_from_file() and ->import_pubkey_file
+  (! this breaks API !)
+- drop $package->upgrade_files() (unused for a long time afaik)
+- rpm.org HEAD support
+
+Version 2.10 - 22 November 2007, by Pascal "Pixel" Rigaux
+
+- much simpler --auto-select algorithm 
+  (fixes #35718, ie auto-selecting with strict-arch)
+  (!! DANGEROUS CHANGE !!)
+- rpm 4.5 support (thanks to peroyvind) (#35323)
+
+Version 2.09 - 8 November 2007, by Pascal "Pixel" Rigaux
+
+- use a simple function to return simple string list from header 
+  (fixes getting >4096 long rpm changelogs)
+  (!! static buffer size limitation in callback_list_str_xpush() should be fixed !!)
+
+Version 2.08 - 24 October 2007, by Pascal "Pixel" Rigaux
+
+- fix build on rpm 4.4.2.2
+
+Version 2.07 - 1 October 2007, by Pascal "Pixel" Rigaux
+
+- prefer precompiled kmod packages corresponding to installed kernels
+- don't resolve suggested virtual packages if already installed (#34376)
+
+Version 2.06 - 28 September 2007, by Pascal "Pixel" Rigaux
+
+- also handle promotion via obsolete for conflicts
+
+Version 2.05 - 28 September 2007, by Pascal "Pixel" Rigaux
+
+- package promotion must respect strict_arch
+- enhance sorted graph by better taking into account conflicts from state->{rejected}
+  (fixes "big transaction" in urpmi split-transactions--strict-require.t test)
+
+Version 2.04 - 27 September 2007, by Pascal "Pixel" Rigaux
+
+- handle promotion via obsolete, not only provides
+
+Version 2.03 - 20 September 2007, by Pascal "Pixel" Rigaux
+
+- fix bug doing "urpmi kernel-source"
+
+Version 2.02 - 18 September 2007, by Pascal "Pixel" Rigaux
+
+- prefer every kernel-<flavor>-devel-<version> packages for which
+  kernel-<flavor>-<version> is selected
+- fix regression in 2.00: we can't cache the platform, cache the result of
+  is_arch_compat instead
+
+Version 2.01 - 14 September 2007, by Pascal "Pixel" Rigaux
+
+- fix bug occurring with --keep
+- fix regression in 2.00: keep_unrequested_dependencies is still used by
+  installer. restore it, but must now be set trough
+  $urpm->{keep_unrequested_dependencies}
+
+Version 2.00 - 13 September 2007, by Pascal "Pixel" Rigaux
+
+- speedup is_arch_compat (7 times faster) by keeping the platform in a cache
+- do not propose packages for non installed locales
+- pass the prefered choices to {callback_choices}: this allows urpmi to select
+  all the prefered packages according to installed locales
+- handle promote for conflict from installed package 
+  (fixes test_gh() from urpmi split-transactions--promote test case)
+- handle promote from installed package which require a unselected package,
+  whereas new package does not require it anymore 
+  (cf test_d & test_e from split-transactions--conflict urpmi test case)
+
+Version 1.80 - 3 September 2007, by Pascal "Pixel" Rigaux
+
+- fix bug in sort_graph (used by build_transaction_set)
+
+Version 1.78 - 31 August 2007, by Pascal "Pixel" Rigaux
+
+- fix dead-loop in build_transaction_set (#33020)
+
+Version 1.77 - 29 August 2007, by Pascal "Pixel" Rigaux
+
+- disable "dropping tags from rpm header" until we can safely use it
+
+Version 1.76 - 28 August 2007, by Pascal "Pixel" Rigaux
+
+- build_transaction_set: new sort algorithm which allow returning sets of
+  circular dependent packages, taking into account obsoleted packages
+  (fixes #31969). It may still fail in presence of conflicts
+- allow running transaction with justdb option
+- fix split_length > 1 
+  (eg: "urpmi --split-length 2 a b c" will only install 2 pkgs)
+- spec2srcheader: workaround parseSpec returning a header where ->arch is set
+  to %{_target_cpu} whereas we really want a header similar to .src.rpm
+  (see #32824)
+
+Version 1.75 - 12 August 2007, by Pascal "Pixel" Rigaux
+
+- fix dropping tags from rpm header.
+  it hasn't work since MDK8.1 and rpm 4.0. 
+  it may break urpmi!! but potentially allows a much smaller hdlist.cz :)
+
+Version 1.74 - 12 August 2007, by Pascal "Pixel" Rigaux
+
+- sort choices per media, then per version
+
+Version 1.73 - 11 August 2007, by Pascal "Pixel" Rigaux
+
+- allow running transaction with replagekgs option
+
+Version 1.72 - 10 August 2007, by Pascal "Pixel" Rigaux
+
+- modify parse_hdlist so that partial hdlist reading can be used
+  (needed when some stuff is already done in the callback)
+
+Version 1.71 - 9 August 2007, by Pascal "Pixel" Rigaux
+
+- compilation fixes on rpm < 4.4.8
+
+Version 1.69 - 9 August 2007, by Pascal "Pixel" Rigaux
+
+- "suggests" are no more handled as "requires"
+- resolve_requested support "suggests": a newly suggested package is installed
+  as if required (can be disabled with option no_suggests)
+
+Version 1.68 - 3 August 2007, by Pascal "Pixel" Rigaux
+
+- add $trans->Element_version and $trans->Element_release
+
+Version 1.67 - 22 June 2007, by Olivier "Nanar" Thauvin
+
+- add osscore, archscore and platformscore function to URPM
+- is_platform_compat function to Pkg object
+- fix call to rpm function in spec2header()
+- fix some compilation warnings
+
+Version 1.66 - 2 July 2007, by Pascal "Pixel" Rigaux
+
+- fix --auto-select skipping some packages because of other packages providing
+  a more recent version, but no obsolete between those packages.
+  the fix is to revert commit from Aug 2002:
+    "fixed propable old package (according provides) requested by
+     request_packages_to_upgrade."
+
+Version 1.65 - 22 June 2007, by Olivier Thauvin
+
+- really fix arch_score evaluation
+
+Version 1.64 - 12 June 2007, by Pascal "Pixel" Rigaux
+
+- hack on $pkg->is_arch_compat to make it return true for noarch packages
+  when using rpm 4.4.8 (#31314)
+
+Version 1.63 - 9 May 2007, by Pascal "Pixel" Rigaux
+
+- add $trans->Element_fullname
+
+Version 1.62 - 3 May 2007, by Pascal "Pixel" Rigaux
+
+- pass the virtual package name as a parameter to {callback_choices} in
+  ->resolve_requested
+- add $trans->NElements and $trans->Element_name
+  to be able to display name of uninstalled package in callback_uninst
+- fix b--obsoletes-->a and c--conflicts-->a prompting for upgrading a
+  (need a fix in urpmi which rely on the $state->{rejected} 
+   to upgrade (-U) b instead of installing (-i) it)
+
+Version 1.60 - 8 March 2007, by Pascal "Pixel" Rigaux
+
+- more debugging hooks
+- create $urpm->packages_providing($name) and use it
+- create $urpm->packages_by_name($name)
+
+Version 1.59 - 1 March 2007, by Olivier Thauvin
+
+- rpm 4.4.8 adaptions
+- load rpm config files at module load, improve the mechanism
+
+Version 1.58 - 14 February 2007, by Pascal "Pixel" Rigaux
+
+- don't check signature and digest in ->traverse and ->traverse_tag
+  (=> x15 speedup, ie 2.5 speedup on urpmi --auto-select and rpmdrake)
+
+Version 1.57 - 9 February 2007, by Pascal "Pixel" Rigaux
+
+- allow upgrading from noarch to x86_64 even if strict-arch
+
+Version 1.56 - 19 January 2007, by Pascal "Pixel" Rigaux
+
+- tell perl that strings from rpm headers are utf8
+- add URPM::bind_rpm_textdomain_codeset() to set encoding of messages returned
+  by rpmlib, and tell perl that those strings are utf8
+- really use strict-arch by default on x86_64
+
+Version 1.55 - 10 January 2007, by Pascal "Pixel" Rigaux
+
+- bug fix release
+- fix "not selecting foo-1 since the more recent foo-1 is installed" causing
+  urpmi to try to remove the package it wants to install (#28076)
+
+Version 1.54 - 9 January 2007, by Pascal "Pixel" Rigaux
+
+- if we have a choice between foo-1 and bar-1 and foo-2 is installed,
+  prefering bar-1 instead of foo-1
+  (otherwise we can hit: "the more recent foo-2 is installed, but does not
+  provide xxx whereas foo-1 does", cf bug #27991)
+- bar is needed, foo-1 does provide bar, installed foo-2 does not provide bar:
+  do not let the algorithm use foo-2 as if it also provides bar
+- allow understanding what ->resolve_requested is doing through a callback ($urpm->{debug_URPM})
+- cleanup some code in ->resolve_requested
+- make the documentation for ->is_arch_compat more clear

Added: rpm/perl-URPM/trunk/README
===================================================================
--- rpm/perl-URPM/trunk/README	                        (rev 0)
+++ rpm/perl-URPM/trunk/README	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,7 @@
+The URPM module allows you to manipulate rpm files, rpm header files and
+hdlist files and manage them in memory.
+
+Copyright 2002-2007 Mandrakesoft
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.

Added: rpm/perl-URPM/trunk/URPM/.perl_checker
===================================================================
--- rpm/perl-URPM/trunk/URPM/.perl_checker	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM/.perl_checker	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1 @@
+Basedir ..

Added: rpm/perl-URPM/trunk/URPM/Build.pm
===================================================================
--- rpm/perl-URPM/trunk/URPM/Build.pm	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM/Build.pm	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,528 @@
+package URPM;
+
+# $Id: Build.pm 270395 2010-07-30 00:55:59Z nanardon $
+
+use strict;
+use warnings;
+
+sub _get_tmp_dir () {
+    my $t = $ENV{TMPDIR};
+    $t && -w $t or $t = '/tmp';
+    "$t/.build_hdlist";
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#
+#- prepare build of an hdlist from a list of files.
+#- it can be used to start computing depslist.
+#- parameters are :
+#-   rpms     : array of all rpm file name to parse (mandatory)
+#-   dir      : directory which will contain headers (defaults to /tmp/.build_hdlist)
+#-   callback : perl code to be called for each package read (defaults pack_header)
+#-   clean    : bool to clean cache before (default no).
+#-   packing  : bool to create info (default is weird)
+#
+# deprecated
+sub parse_rpms_build_headers {
+    my ($urpm, %options) = @_;
+    my ($dir, %cache, @headers);
+
+    #- check for mandatory options.
+    if (@{$options{rpms} || []} > 0) {
+	#- build a working directory which will hold rpm headers.
+	$dir = $options{dir} || _get_tmp_dir();
+	$options{clean} and system($ENV{LD_LOADER} ? $ENV{LD_LOADER} : @{[]}, "rm", "-rf", $dir);
+	-d $dir or mkdir $dir, 0755 or die "cannot create directory $dir\n";
+
+	#- examine cache if it contains any headers which will be much faster to read
+	#- than parsing rpm file directly.
+	unless ($options{clean}) {
+	    my $dirh;
+	    opendir $dirh, $dir;
+	    while (defined (my $file = readdir $dirh)) {
+		my ($fullname, $filename) = $file =~ /(.+?-[^:\-]+-[^:\-]+\.[^:\-\.]+)(?::(\S+))?$/ or next;
+		my @stat = stat "$dir/$file";
+		$cache{$filename || $fullname} = {
+		    file => $file,
+		    size => $stat[7],
+		    'time' => $stat[9],
+		};
+	    }
+	    closedir $dirh;
+	}
+
+	foreach (@{$options{rpms}}) {
+	    my ($key) = m!([^/]*)\.rpm$! or next; #- get rpm filename.
+	    my ($id, $filename);
+
+	    if ($cache{$key} && $cache{$key}{time} > 0 && $cache{$key}{time} >= (stat $_)[9]) {
+		($id, undef) = $urpm->parse_hdlist("$dir/$cache{$key}{file}", packing => $options{packing}, keep_all_tags => $options{keep_all_tags});
+		unless (defined $id) {
+		  if ($options{dontdie}) {
+		    print STDERR "bad header $dir/$cache{$key}{file}\n";
+		    next;
+		  } else {
+		    die "bad header $dir/$cache{$key}{file}\n";
+		  }
+		}
+
+		$options{callback} and $options{callback}->($urpm, $id, %options, (file => $_));
+
+		$filename = $cache{$key}{file};
+	    } else {
+		($id, undef) = $urpm->parse_rpm($_, keep_all_tags => $options{keep_all_tags});
+		unless (defined $id) {
+		    if ($options{dontdie}) {
+			print STDERR "bad rpm $_\n";
+			next;
+		    } else {
+			die "bad rpm $_\n";
+		    }
+		}
+		
+		my $pkg = $urpm->{depslist}[$id];
+
+		$filename = $pkg->fullname;
+
+		unless (-s "$dir/$filename") {
+		    open my $fh, ">$dir/$filename" or die "unable to open $dir/$filename for writing\n";
+		    $pkg->build_header(fileno $fh);
+		    close $fh;
+		}
+		-s "$dir/$filename" or unlink("$dir/$filename"), die "can create header $dir/$filename\n";
+
+		#- make smart use of memory (no need to keep header in memory now).
+		if ($options{callback}) {
+		    $options{callback}->($urpm, $id, %options, (file => $_));
+		} else {
+			$pkg->pack_header;
+		}
+
+		# Olivier Thauvin <thauvin at aerov.jussieu.fr>
+		# isn't this code better, but maybe it will break some tools:
+		# $options{callback}->($urpm, $id, %options, (file => $_)) if ($options{callback});
+		# $pkg->pack_header;
+	    }
+
+	    #- keep track of header associated (to avoid rereading rpm filename directly
+	    #- if rereading has been made neccessary).
+	    push @headers, $filename;
+	}
+    }
+    @headers;
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#
+#- allow rereading of hdlist and clean.
+sub unresolved_provides_clean {
+    my ($urpm) = @_;
+    $urpm->{depslist} = [];
+    $urpm->{provides}{$_} = undef foreach keys %{$urpm->{provides} || {}};
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#
+#- read a list of headers (typically when building an hdlist when provides have
+#- been cleaned).
+#- parameters are :
+#-   headers  : array containing all headers filenames to parse (mandatory)
+#-   dir      : directory which contains headers (defaults to /tmp/.build_hdlist)
+#-   callback : perl code to be called for each package read (defaults to pack_header)
+sub parse_headers {
+    my ($urpm, %options) = @_;
+    my ($dir, $start, $id);
+
+    $dir = $options{dir} || _get_tmp_dir();
+    -d $dir or die "no directory $dir\n";
+
+    $start = @{$urpm->{depslist} || []};
+    foreach (@{$options{headers} || []}) {
+	#- make smart use of memory (no need to keep header in memory now).
+	($id, undef) = $urpm->parse_hdlist("$dir/$_", packing => !$options{callback});
+	defined $id or die "bad header $dir/$_\n";
+	$options{callback} and $options{callback}->($urpm, $id, %options);
+    }
+    defined $id ? ($start, $id) : @{[]};
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#- compute dependencies, result in stored in info values of urpm.
+#- operations are incremental, it is possible to read just one hdlist, compute
+#- dependencies and read another hdlist, and again.
+#- parameters are :
+#-   callback : callback to relocate reference to package id.
+sub compute_deps {
+    my ($urpm, %options) = @_;
+    my %propagated_weight = (
+	basesystem => 10000,
+	msec       => 20000,
+	filesystem => 50000,
+    );
+    my ($locales_weight, $step_weight, $fixed_weight) = (-5000, 10000, $propagated_weight{basesystem});
+
+    #- avoid recomputing already present infos, take care not to modify
+    #- existing entries, as the array here is used instead of values of infos.
+    my $start = @{$urpm->{deps} ||= []};
+    my $end = $#{$urpm->{depslist} || []};
+
+    #- check if something has to be done.
+    $start > $end and return;
+
+    #- keep track of prereqs.
+    my %prereqs;
+
+    #- take into account in which hdlist a package has been found.
+    #- this can be done by an incremental take into account generation
+    #- of depslist.ordered part corresponding to the hdlist.
+    #- compute closed requires, do not take into account choices.
+    foreach ($start .. $end) {
+	my $pkg = $urpm->{depslist}[$_];
+
+	my %required_packages;
+	my @required_packages;
+	my %requires;
+
+	foreach ($pkg->requires) {
+	    my ($n, $prereq) = /^([^\s\[]*)(\[\*\])?/;
+	    $requires{$n} = $prereq && 1;
+	}
+	my @requires = keys %requires;
+
+	while (my $req = shift @requires) {
+	    $req =~ /^basesystem/ and next; #- never need to requires basesystem directly as always required! what a speed up!
+	    my $treq = (
+		$req =~ /^\d+$/ ? [ $req ]
+		: $urpm->{provides}{$req} ? [ keys %{$urpm->{provides}{$req}} ]
+		: [ ($req !~ /NOTFOUND_/ ? "NOTFOUND_" : "") . $req ]
+	    );
+	    if (@$treq > 1) {
+		#- this is a choice, no closure need to be done here.
+		push @required_packages, $treq;
+	    } else {
+		#- this could be nothing if the provides is a file not found.
+		#- and this has been fixed above.
+		foreach (@$treq) {
+		    my $pkg_ = /^\d+$/ && $urpm->{depslist}[$_];
+		    exists $required_packages{$_} and $pkg_ = undef;
+		    $required_packages{$_} ||= $requires{$req}; $pkg_ or next;
+		    foreach ($pkg_->requires_nosense) {
+			exists $requires{$_} or push @requires, $_;
+			$requires{$_} ||= $requires{$req};
+		    }
+		}
+	    }
+	}
+	#- examine choice to remove those which are not mandatory.
+	foreach (@required_packages) {
+	    unless (grep { exists $required_packages{$_} } @$_) {
+		$required_packages{join '|', sort { $a <=> $b } @$_} = undef;
+	    }
+	}
+
+	#- store a short representation of requires.
+	$urpm->{requires}[$_] = join ' ', keys %required_packages;
+	foreach my $d (keys %required_packages) {
+	    $required_packages{$d} or next;
+	    $prereqs{$d}{$_} = undef;
+	}
+    }
+
+    #- expand choices and closure again.
+    my %ordered;
+    foreach ($start .. $end) {
+	my @requires = $_;
+	my ($dep, %requires);
+	while (defined ($dep = shift @requires)) {
+	    exists $requires{$dep} || /^[^\d\|]*$/ and next;
+	    foreach ($dep, split ' ', (defined $urpm->{deps}[$dep] ? $urpm->{deps}[$dep] : $urpm->{requires}[$dep])) {
+		if (/\|/) {
+		    push @requires, split /\|/, $_;
+		} else {
+		    /^\d+$/ and $requires{$_} = undef;
+		}
+	    }
+	}
+
+	my $pkg = $urpm->{depslist}[$_];
+	my $delta = 1 + $propagated_weight{$pkg->name};
+	foreach (keys %requires) {
+	    $ordered{$_} += $delta;
+	}
+    }
+
+    #- some package should be sorted at the beginning.
+    foreach (qw(basesystem msec rpm locales filesystem setup glibc sash bash libtermcap2 termcap readline ldconfig)) {
+	foreach (keys %{$urpm->{provides}{$_} || {}}) {
+	    /^\d+$/ and $ordered{$_} = $fixed_weight;
+	}
+	/locales/ and $locales_weight += $fixed_weight;
+	$fixed_weight += $step_weight;
+    }
+    foreach ($start .. $end) {
+	my $pkg = $urpm->{depslist}[$_];
+
+	$pkg->name =~ /locales-[a-zA-Z]/ and $ordered{$_} = $locales_weight;
+    }
+
+    #- compute base flag, consists of packages which are required without
+    #- choices of basesystem and are ALWAYS installed. these packages can
+    #- safely be removed from requires of others packages.
+    foreach (qw(basesystem glibc kernel)) {
+	foreach (keys %{$urpm->{provides}{$_} || {}}) {
+	    foreach ($_, split ' ', (defined $urpm->{deps}[$_] ? $urpm->{deps}[$_] : $urpm->{requires}[$_])) {
+		/^\d+$/ and $urpm->{depslist}[$_] and $urpm->{depslist}[$_]->set_flag_base(1);
+	    }
+	}
+    }
+
+    #- give an id to each packages, start from number of package already
+    #- registered in depslist.
+    my %remap_ids; @remap_ids{sort {
+	exists $prereqs{$b}{$a} && ! exists $prereqs{$a}{$b} ? 1 :
+	  $ordered{$b} <=> $ordered{$a} or do {
+	      my ($na, $nb) = map { $urpm->{depslist}[$_]->name } ($a, $b);
+	      my ($sa, $sb) = map { /^lib(.*)/ ? $1 : '' } ($na, $nb);
+	      $sa && $sb ? $sa cmp $sb : $sa ? -1 : $sb ? 1 : $na cmp $nb;
+	  } } ($start .. $end)} = ($start .. $end);
+
+    #- now it is possible to clean ordered and prereqs.
+    %ordered = %prereqs = ();
+
+    #- recompute requires to use packages id, drop any base packages or
+    #- reference of a package to itself.
+    my @depslist;
+    foreach ($start .. $end) {
+	my $pkg = $urpm->{depslist}[$_];
+
+	#- set new id.
+	$pkg->set_id($remap_ids{$_});
+
+	my ($id, $base, %requires_id, %not_founds);
+	foreach (split ' ', $urpm->{requires}[$_]) {
+	    if (/\|/) {
+		#- all choices are grouped together at the end of requires,
+		#- this allow computation of dropable choices.
+		my ($to_drop, @choices_base_id, @choices_id);
+		foreach (split /\|/, $_) {
+		    my ($id, $base) = (exists($remap_ids{$_}) ? $remap_ids{$_} : $_, $urpm->{depslist}[$_]->flag_base);
+		    $base and push @choices_base_id, $id;
+		    $base &&= ! $pkg->flag_base;
+		    $to_drop ||= $id == $pkg->id || exists $requires_id{$id} || $base;
+		    push @choices_id, $id;
+		}
+
+		#- package can safely be dropped as it will be selected in requires directly.
+		$to_drop and next;
+
+		#- if a base package is in a list, keep it instead of the choice.
+		if (@choices_base_id) {
+		    @choices_id = @choices_base_id;
+		    $base = 1;
+		}
+		if (@choices_id == 1) {
+		    $id = $choices_id[0];
+		} else {
+		    my $choices_key = join '|', sort { $a <=> $b } @choices_id;
+		    $requires_id{$choices_key} = undef;
+		    next;
+		}
+	    } elsif (/^\d+$/) {
+		($id, $base) =  (exists($remap_ids{$_}) ? $remap_ids{$_} : $_, $urpm->{depslist}[$_]->flag_base);
+	    } else {
+		$not_founds{$_} = undef;
+		next;
+	    }
+
+	    #- select individual package from choices or defined package.
+	    $base &&= ! $pkg->flag_base;
+	    $base || $id == $pkg->id or $requires_id{$id} = undef;
+	}
+	#- be smart with memory usage.
+	delete $urpm->{requires}[$_];
+	$urpm->{deps}[$remap_ids{$_}] = join ' ', ((sort { ($a =~ /^(\d+)/)[0] <=> ($b =~ /^(\d+)/)[0] } keys %requires_id),
+						   keys %not_founds);
+	$depslist[$remap_ids{$_}-$start] = $pkg;
+    }
+
+    #- remap all provides ids for new package position and update depslist.
+    delete $urpm->{requires};
+    @{$urpm->{depslist}}[$start .. $end] = @depslist;
+    foreach my $h (values %{$urpm->{provides}}) {
+	my %provided;
+	foreach (keys %{$h || {}}) {
+	    $provided{exists($remap_ids{$_}) ? $remap_ids{$_} : $_} = delete $h->{$_};
+	}
+	$h = \%provided;
+    }
+    $options{callback} and $options{callback}->($urpm, \%remap_ids, %options);
+
+    ($start, $end);
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#
+#- build an hdlist from existing depslist, from start to end inclusive.
+#- parameters are :
+#-   hdlist   : hdlist file to use.
+#-   dir      : directory which contains headers (defaults to /tmp/.build_hdlist)
+#-   start    : index of first package (defaults to first index of depslist).
+#-   end      : index of last package (defaults to last index of depslist).
+#-   idlist   : id list of rpm to compute (defaults is start .. end)
+#-   ratio    : compression ratio (default 4).
+#-   split    : split ratio (default 400kb, see MDV::Packdrakeng).
+sub build_hdlist {
+    my ($urpm, %options) = @_;
+    my ($dir, $ratio, @idlist);
+
+    $dir = $options{dir} || _get_tmp_dir();
+     -d $dir or die "no directory $dir\n";
+
+    @idlist = $urpm->build_listid($options{start}, $options{end}, $options{idlist});
+
+    #- compression ratio are not very high, sample for cooker
+    #- gives the following (main only and cache fed up):
+    #- ratio compression_time  size
+    #-   9       21.5 sec     8.10Mb   -> good for installation CD
+    #-   6       10.7 sec     8.15Mb
+    #-   5        9.5 sec     8.20Mb
+    #-   4        8.6 sec     8.30Mb   -> good for urpmi
+    #-   3        7.6 sec     8.60Mb
+    $ratio = $options{ratio} || 4;
+
+    require MDV::Packdrakeng;
+    my $pack = MDV::Packdrakeng->new(
+	archive => $options{hdlist},
+	compress => "gzip",
+	uncompress => "gzip -d",
+	block_size => $options{split},
+	comp_level => $ratio,
+    ) or die "Can't create archive";
+    foreach my $pkg (@{$urpm->{depslist}}[@idlist]) {
+	my $filename = $pkg->fullname;
+	-s "$dir/$filename" or die "bad header $dir/$filename\n";
+	$pack->add($dir, $filename);
+    }
+}
+
+#- build synthesis file.
+#- used by genhdlist2 and mkcd
+#-
+#- parameters are :
+#-   synthesis : synthesis file to create (mandatory if fd not given).
+#-   fd        : file descriptor (mandatory if synthesis not given).
+#-   start     : index of first package (defaults to first index of depslist).
+#-   end       : index of last package (defaults to last index of depslist).
+#-   idlist    : id list of rpm to compute (defaults is start .. end)
+#-   ratio     : compression ratio (default 9).
+#-   filter    : program to filter through (default is 'gzip -$ratio').
+#- returns true on success
+sub build_synthesis {
+    my ($urpm, %options) = @_;
+    my ($ratio, $filter, @idlist);
+
+    @idlist = $urpm->build_listid($options{start}, $options{end}, $options{idlist});
+
+    $ratio = $options{ratio} || 9;
+    $filter = $options{filter} ? $options{filter} : "gzip -$ratio";
+    $options{synthesis} || defined $options{fd} or die "invalid parameters given";
+
+    #- first pass: traverse provides to find files provided.
+    my %provided_files;
+    foreach (keys %{$urpm->{provides}}) {
+	m!^/! or next;
+	foreach my $id (keys %{$urpm->{provides}{$_} || {}}) {
+	    push @{$provided_files{$id} ||= []}, $_;
+	}
+    }
+
+
+    #- second pass: write each info including files provided.
+    $options{synthesis} and open my $fh, "| " . ($ENV{LD_LOADER} || '') . " $filter >'$options{synthesis}'";
+    foreach (@idlist) {
+	my $pkg = $urpm->{depslist}[$_];
+	my %files;
+
+	if ($provided_files{$_}) {
+	    @files{@{$provided_files{$_}}} = undef;
+	    delete @files{$pkg->provides_nosense};
+	}
+
+	$pkg->build_info($options{synthesis} ? fileno $fh : $options{fd}, join('@', keys %files));
+    }
+    close $fh; # returns true on success
+}
+
+# DEPRECATED. ONLY USED BY MKCD
+#- write depslist.ordered file according to info in params.
+#- parameters are :
+#-   depslist : depslist.ordered file to create.
+#-   provides : provides file to create.
+#-   compss   : compss file to create.
+sub build_base_files {
+    my ($urpm, %options) = @_;
+
+    if ($options{depslist}) {
+	open my $fh, ">", $options{depslist} or die "Can't write to $options{depslist}: $!\n";
+	foreach (0 .. $#{$urpm->{depslist}}) {
+	    my $pkg = $urpm->{depslist}[$_];
+
+	    printf $fh ("%s-%s-%s.%s%s %s %s\n", $pkg->fullname,
+		      ($pkg->epoch ? ':' . $pkg->epoch : ''), $pkg->size || 0, $urpm->{deps}[$_]);
+	}
+	close $fh;
+    }
+
+    if ($options{provides}) {
+	open my $fh, ">", $options{provides} or die "Can't write to $options{provides}: $!\n";
+	while (my ($k, $v) = each %{$urpm->{provides}}) {
+	    printf $fh "%s\n", join '@', $k, map { scalar $urpm->{depslist}[$_]->fullname } keys %{$v || {}};
+	}
+	close $fh;
+    }
+
+    if ($options{compss}) {
+	my %p;
+
+	open my $fh, ">", $options{compss} or die "Can't write to $options{compss}: $!\n";
+	foreach (@{$urpm->{depslist}}) {
+	    $_->group or next;
+	    push @{$p{$_->group} ||= []}, $_->name;
+	}
+	foreach (sort keys %p) {
+	    print $fh $_, "\n";
+	    foreach (@{$p{$_}}) {
+		print $fh "\t", $_, "\n";
+	    }
+	    print $fh "\n";
+	}
+	close $fh;
+    }
+
+    1;
+}
+
+our $MAKEDELTARPM = '/usr/bin/makedeltarpm';
+
+#- make_delta_rpm($old_rpm_file, $new_rpm_file)
+# Creates a delta rpm in the current directory.
+
+# DEPRECATED. UNUSED
+sub make_delta_rpm ($$) {
+    @_ == 2 or return 0;
+    -e $_[0] && -e $_[1] && -x $MAKEDELTARPM or return 0;
+    my @id;
+    my $urpm = new URPM;
+    foreach my $i (0, 1) {
+	($id[$i]) = $urpm->parse_rpm($_[$i]);
+	defined $id[$i] or return 0;
+    }
+    my $oldpkg = $urpm->{depslist}[$id[0]];
+    my $newpkg = $urpm->{depslist}[$id[1]];
+    $oldpkg->arch eq $newpkg->arch or return 0;
+    #- construct filename of the deltarpm
+    my $patchrpm = $oldpkg->name . '-' . $oldpkg->version . '-' . $oldpkg->release . '_' . $newpkg->version . '-' . $newpkg->release . '.' . $oldpkg->arch . '.delta.rpm';
+    !system($MAKEDELTARPM, @_, $patchrpm);
+}
+
+1;

Added: rpm/perl-URPM/trunk/URPM/Query.pm
===================================================================
--- rpm/perl-URPM/trunk/URPM/Query.pm	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM/Query.pm	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,40 @@
+package URPM;
+
+use strict;
+use warnings;
+
+# Olivier Thauvin <thauvin at aerov.jussieu.fr>
+# This package extend URPM functions to permit
+# URPM low level query on rpm header
+# $Id: Query.pm 270395 2010-07-30 00:55:59Z nanardon $
+
+# tag2id
+# INPUT array of rpm tag name
+# Return an array of ID tag
+
+sub tag2id {
+    my @l = @_;
+    my %taglist = URPM::list_rpm_tag();
+    map { $taglist{uc($_)} || undef } @l;
+}
+
+sub query_pkg {
+   my (undef, $pkg, $query) = @_;
+   my @tags = map {
+	   [ $pkg->get_tag(tag2id($_)) ]
+   } $query =~ m/\%\{([^{}]*)\}*/g;
+
+   $query =~ s/\%\{[^{}]*\}/%s/g;
+   $query =~ s/\\n/\n/g;
+   $query =~ s/\\t/\t/g;
+   my ($max, @res) = 0;
+
+   foreach (@tags) { $max < $#{$_} and $max = $#{$_} };
+
+   foreach my $i (0 .. $max) {
+       push(@res, sprintf($query, map { ${$_}[ $#{$_} < $i ? $#{$_} : $i ] } @tags));
+   }
+   @res
+}
+
+1;

Added: rpm/perl-URPM/trunk/URPM/Resolve.pm
===================================================================
--- rpm/perl-URPM/trunk/URPM/Resolve.pm	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM/Resolve.pm	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,2003 @@
+package URPM;
+#package URPM::Resolve;
+#use URPM;
+
+# $Id: Resolve.pm 270395 2010-07-30 00:55:59Z nanardon $
+
+use strict;
+use warnings;
+use Config;
+
+
+#- a few functions from MDK::Common copied here:
+sub listlength { scalar @_ }
+sub min { my $n = shift; $_ < $n and $n = $_ foreach @_; $n }
+sub uniq { my %l; $l{$_} = 1 foreach @_; grep { delete $l{$_} } @_ }
+sub find(&@) {
+    my $f = shift;
+    $f->($_) and return $_ foreach @_;
+    undef;
+}
+
+#- property2name* functions below parse things like "mageia-release[>= 1]"
+#- which is the format returned by URPM.xs for ->requires, ->provides, ->conflicts...
+sub property2name {
+    $_[0] =~ /^([^\s\[]*)/ && $1;
+}
+sub property2name_range {
+    $_[0] =~ /^([^\s\[]*)(?:\[\*\])?\[?([^\s\]]*\s*[^\s\]]*)/;
+}
+sub property2name_op_version {
+    $_[0] =~ /^([^\s\[]*)(?:\[\*\])?\s*\[?([^\s\]]*)\s*([^\s\]]*)/;
+}
+
+#- wrappers around $state (cf "The $state object" in "perldoc URPM")
+sub packages_to_remove {
+    my ($state) = @_;
+    grep {
+	$state->{rejected}{$_}{removed} && !$state->{rejected}{$_}{obsoleted};
+    } keys %{$state->{rejected} || {}};
+}
+sub removed_or_obsoleted_packages {
+    my ($state) = @_;
+    grep {
+	$state->{rejected}{$_}{removed} || $state->{rejected}{$_}{obsoleted};
+    } keys %{$state->{rejected} || {}};
+}
+
+#- Find candidates packages from a require string (or id).
+#- Takes care of choices using the '|' separator.
+#- (nb: see also find_required_package())
+#-
+#- side-effects: none
+sub find_candidate_packages_ {
+    my ($urpm, $id_prop, $o_rejected) = @_;
+    my @packages;
+
+    foreach (split /\|/, $id_prop) {
+	if (/^\d+$/) {
+	    my $pkg = $urpm->{depslist}[$_];
+	    $pkg->flag_skip and next;
+	    $pkg->arch eq 'src' || $pkg->is_arch_compat or next;
+	    $o_rejected && exists $o_rejected->{$pkg->fullname} and next;
+	    push @packages, $pkg;
+	} elsif (my $name = property2name($_)) {
+	    my $property = $_;
+	    foreach (keys %{$urpm->{provides}{$name} || {}}) {
+		my $pkg = $urpm->{depslist}[$_];
+		$pkg->flag_skip and next;
+		$pkg->is_arch_compat or next;
+		$o_rejected && exists $o_rejected->{$pkg->fullname} and next;
+		#- check if at least one provide of the package overlap the property.
+		!$urpm->{provides}{$name}{$_} || $pkg->provides_overlap($property, 1)
+		    and push @packages, $pkg;
+	    }
+	}
+    }
+    @packages;
+}
+
+#- deprecated, use find_candidate_packages_() directly
+#-
+#- side-effects: none
+sub find_candidate_packages {
+    my ($urpm, $id_prop, $o_rejected) = @_;
+
+    my %packages;
+    foreach (find_candidate_packages_($urpm, $id_prop, $o_rejected)) {
+	push @{$packages{$_->name}}, $_;
+    }
+    \%packages;
+}
+
+#- returns the "arch" of package $n in rpm db
+sub get_installed_arch {
+    my ($db, $n) = @_;
+    my $arch;
+    $db->traverse_tag('name', [ $n ], sub { $arch = $_[0]->arch });
+    $arch;
+}
+
+#- is "strict-arch" wanted? (cf "man urpmi")
+#- since it's slower we only force it on bi-arch
+sub strict_arch {
+    my ($urpm) = @_;
+    defined $urpm->{options}{'strict-arch'} ? $urpm->{options}{'strict-arch'} : $Config{archname} =~ /x86_64|sparc64|ppc64/;
+}
+my %installed_arch;
+
+#- checks wether $pkg could be installed under strict-arch policy
+#- (ie check wether $pkg->name with different arch is not installed)
+#-
+#- side-effects: none (but uses a cache)
+sub strict_arch_check_installed {
+    my ($db, $pkg) = @_;
+    if ($pkg->arch ne 'src' && $pkg->arch ne 'noarch') {
+	my $n = $pkg->name;
+	defined $installed_arch{$n} or $installed_arch{$n} = get_installed_arch($db, $n);
+	if ($installed_arch{$n} && $installed_arch{$n} ne 'noarch') {
+	    $pkg->arch eq $installed_arch{$n} or return;
+	}
+    }
+    1;
+}
+
+#- check wether $installed_pkg and $pkg have same arch
+#- (except for src/noarch of course)
+#-
+#- side-effects: none
+sub strict_arch_check {
+    my ($installed_pkg, $pkg) = @_;
+    if ($pkg->arch ne 'src' && $pkg->arch ne 'noarch') {
+	if ($installed_pkg->arch ne 'noarch') {
+	    $pkg->arch eq $installed_pkg->arch or return;
+	}
+    }
+    1;
+}
+
+#- is $pkg->name installed?
+#-
+#- side-effects: none
+sub is_package_installed {
+    my ($db, $pkg) = @_;
+
+    my $found;
+    $db->traverse_tag('name', [ $pkg->name ], sub {
+	my ($p) = @_;
+	$found ||= $p->fullname eq $pkg->fullname;
+    });
+    $found;
+}
+
+sub _is_selected_or_installed {
+    my ($urpm, $db, $name) = @_;
+
+    (grep { $_->flag_available } $urpm->packages_providing($name)) > 0 ||
+      $db->traverse_tag('name', [ $name ], undef) > 0;
+}
+
+#- finds $pkg "provides" that matches $provide_name, and returns the version provided
+#- eg: $pkg provides "a = 3", $provide_name is "a > 1", returns "3"
+sub provided_version_that_overlaps {
+    my ($pkg, $provide_name) = @_;
+
+    my $version;
+    foreach my $property ($pkg->provides) {
+	my ($n, undef, $v) = property2name_op_version($property) or next;
+	$n eq $provide_name or next;
+
+	if ($version) {
+	    $version = $v if URPM::rpmvercmp($v, $version) > 0;
+	} else {
+	    $version = $v;
+	}
+    }
+    $version;
+}
+
+#- deprecated function, use find_required_package()
+sub find_chosen_packages { &find_required_package }
+
+#- find the package (or packages) to install matching $id_prop
+#- returns (list ref of matches, list ref of preferred matches)
+#- (see also find_candidate_packages_())
+#-
+#- side-effects: flag_install, flag_upgrade (and strict_arch_check_installed cache)
+sub find_required_package {
+    my ($urpm, $db, $state, $id_prop) = @_;
+    my (%packages, %provided_version);
+    my $strict_arch = strict_arch($urpm);
+
+    my $may_add_to_packages = sub {
+	my ($pkg) = @_;
+
+	if (my $p = $packages{$pkg->name}) {
+	    $pkg->flag_requested > $p->flag_requested ||
+	      $pkg->flag_requested == $p->flag_requested && $pkg->compare_pkg($p) > 0 and $packages{$pkg->name} = $pkg;
+	} else {
+	    $packages{$pkg->name} = $pkg;
+	}
+    };
+
+    #- search for possible packages, try to be as fast as possible, backtrack can be longer.
+    foreach (split /\|/, $id_prop) {
+	if (/^\d+$/) {
+	    my $pkg = $urpm->{depslist}[$_];
+	    $pkg->arch eq 'src' || $pkg->is_arch_compat or next;
+	    $pkg->flag_skip || $state->{rejected}{$pkg->fullname} and next;
+	    #- determine if this package is better than a possibly previously chosen package.
+	    $pkg->flag_selected || exists $state->{selected}{$pkg->id} and return [$pkg];
+	    !$strict_arch || strict_arch_check_installed($db, $pkg) or next;
+	    $may_add_to_packages->($pkg);
+	} elsif (my $name = property2name($_)) {
+	    my $property = $_;
+	    foreach (keys %{$urpm->{provides}{$name} || {}}) {
+		my $pkg = $urpm->{depslist}[$_];
+		$pkg->is_arch_compat or next;
+		$pkg->flag_skip || $state->{rejected}{$pkg->fullname} and next;
+		#- check if at least one provide of the package overlaps the property
+		if (!$urpm->{provides}{$name}{$_} || $pkg->provides_overlap($property)) {
+		    #- determine if this package is better than a possibly previously chosen package.
+		    $pkg->flag_selected || exists $state->{selected}{$pkg->id} and return [$pkg];
+		    !$strict_arch || strict_arch_check_installed($db, $pkg) or next;
+		    $provided_version{$pkg} = provided_version_that_overlaps($pkg, $name);
+		    $may_add_to_packages->($pkg);		    
+		}
+	    }
+	}
+    }
+    my @packages = values %packages;
+
+    if (@packages > 1) {
+	#- packages should be preferred if one of their provides is referenced
+	#- in the "requested" hash, or if the package itself is requested (or
+	#- required).
+	#- If there is no preference, choose the first one by default (higher
+	#- probability of being chosen) and ask the user.
+	#- Packages with more compatibles architectures are always preferred.
+	#- Puts the results in @chosen. Other are left unordered.
+	foreach my $pkg (@packages) {
+	    _set_flag_installed_and_upgrade_if_no_newer($db, $pkg);
+	}
+
+	if (my @kernel_source = _find_required_package__kernel_source($urpm, $db, \@packages)) {
+	    $urpm->{debug_URPM}("packageCallbackChoices: kernel source chosen " . join(",", map { $_->name } @kernel_source) . " in " . join(",", map { $_->name } @packages)) if $urpm->{debug_URPM};
+	    return \@kernel_source, \@kernel_source;
+	}
+	if (my @kmod = _find_required_package__kmod($urpm, $db, \@packages)) {
+	    $urpm->{debug_URPM}("packageCallbackChoices: kmod packages " . join(",", map { $_->name } @kmod) . " in " . join(",", map { $_->name } @packages)) if $urpm->{debug_URPM};
+	    return \@kmod, \@kmod;
+	}
+
+	_find_required_package__sort($urpm, $db, \@packages, \%provided_version);
+    } else {
+	\@packages;
+    }
+}
+
+# nb: _set_flag_installed_and_upgrade_if_no_newer must be done on $packages
+sub _find_required_package__sort {
+    my ($urpm, $db, $packages, $provided_version) = @_;
+
+	my ($best, @other) = sort {
+	      $a->[1] <=> $b->[1] #- we want the lowest (ie preferred arch)
+	      || $b->[2] <=> $a->[2]; #- and the higher score
+	} map {
+	    my $score = 0;
+	    $score += 2 if $_->flag_requested;
+	    $score += $_->flag_upgrade ? 1 : -1 if $_->flag_installed;
+	    [ $_, $_->is_arch_compat, $score ];
+	} @$packages;
+
+	my @chosen_with_score = ($best, grep { $_->[1] == $best->[1] && $_->[2] == $best->[2] } @other);
+	my @chosen = map { $_->[0] } @chosen_with_score;
+
+	#- return immediately if there is only one chosen package
+	if (@chosen == 1) { return \@chosen }
+
+	#- if several packages were selected to match a requested installation,
+	#- and if --more-choices wasn't given, trim the choices to the first one.
+	if (!$urpm->{options}{morechoices} && $chosen_with_score[0][2] == 3) {
+	    return [ $chosen[0] ];
+	}
+
+    if ($urpm->{media}) {
+	@chosen_with_score = sort {
+	    $a->[2] != $b->[2] ? 
+	       $a->[0]->id <=> $b->[0]->id : 
+	       $b->[1] <=> $a->[1] || $b->[0]->compare_pkg($a->[0]);
+	} map { [ $_, _score_for_locales($urpm, $db, $_), pkg2media($urpm->{media}, $_) ] } @chosen;
+    } else {
+	# obsolete code which should not happen, kept just in case
+	$urpm->{debug_URPM}("can't sort choices by media") if $urpm->{debug_URPM};
+	@chosen_with_score = sort {
+	    $b->[1] <=> $a->[1] ||
+	      $b->[0]->compare_pkg($a->[0]) || $a->[0]->id <=> $b->[0]->id;
+	} map { [ $_, _score_for_locales($urpm, $db, $_) ] } @chosen;
+    }
+    if (!$urpm->{options}{morechoices}) {
+	if (my @valid_locales = grep { $_->[1] } @chosen_with_score) {
+	    #- get rid of invalid locales
+	    @chosen_with_score = @valid_locales;
+	}
+    }
+    # propose to select all packages for installed locales
+    my @prefered = grep { $_->[1] == 3 } @chosen_with_score;
+
+    @chosen = map { $_->[0] } @chosen_with_score;
+    if (%$provided_version) {
+	# highest provided version first
+	# (nb: this sort overrules the sort on media (cf ->id above))
+	@chosen = sort { URPM::rpmvercmp($provided_version->{$b} || 0, $provided_version->{$a} || 0) } @chosen;
+    }
+    \@chosen, [ map { $_->[0] } @prefered ];
+}
+
+#- prefer the pkgs corresponding to installed/selected kernels
+sub _find_required_package__kernel_source {
+    my ($urpm, $db, $choices) = @_;
+
+    $choices->[0]->name =~ /^kernel-(.*source-|.*-devel-)/ or return;
+
+    grep {
+	if ($_->name =~ /^kernel-.*source-stripped-(.*)/) {
+	    my $version = quotemeta($1);
+	    find {
+		$_->name =~ /-$version$/ && ($_->flag_installed || $_->flag_selected);
+	    } $urpm->packages_providing('kernel');
+	} elsif ($_->name =~ /(kernel-.*)-devel-(.*)/) {
+	    my $kernel = "$1-$2";
+	    _is_selected_or_installed($urpm, $db, $kernel);
+	} elsif ($_->name =~ /^kernel-.*source-/) {
+	    #- hopefully we don't have a media with kernel-source but not kernel-source-stripped nor kernel-.*-devel
+	    0;
+	} else {
+	    $urpm->{debug_URPM}("unknown kernel-source package " . $_->fullname) if $urpm->{debug_URPM};
+	    0;
+	}
+    } @$choices;
+}
+
+#- prefer the pkgs corresponding to installed/selected kernels
+sub _find_required_package__kmod {
+    my ($urpm, $db, $choices) = @_;
+
+    $choices->[0]->name =~ /^dkms-|-kernel-2\./ or return;
+
+    grep {
+	if (my ($_name, $version, $flavor, $release) = $_->name =~ /(.*)-kernel-(2\..*)-(.*)-(.*)/) {
+	    my $kernel = "kernel-$flavor-$version-$release";
+	    _is_selected_or_installed($urpm, $db, $kernel);
+	} elsif ($_->name =~ /^dkms-/) {
+	    0; # we prefer precompiled dkms
+	} else {
+	    $urpm->{debug_URPM}("unknown kmod package " . $_->fullname) if $urpm->{debug_URPM};
+	    0;
+	}
+    } @$choices;
+}
+
+#- Packages that require locales-xxx when the corresponding locales are
+#- already installed should be preferred over packages that require locales
+#- which are not installed.
+#-
+#- eg: locales-fr & locales-de are installed, 
+#-     prefer firefox-fr & firefox-de which respectively require locales-fr & locales-de
+sub _score_for_locales {
+    my ($urpm, $db, $pkg) = @_;
+
+    my @r = $pkg->requires_nosense;
+
+    if (my ($specific_locales) = grep { /locales-(?!en)/ } @r) {
+	if (_is_selected_or_installed($urpm, $db, $specific_locales)) {
+	      3; # good locale
+	  } else {
+	      0; # bad locale
+	  }
+    } elsif (grep { /locales-en/ } @r) {
+	2; # 
+    } else {
+	1;
+    }
+}
+
+#- side-effects: $properties, $choices
+#-   + those of backtrack_selected ($state->{backtrack}, $state->{rejected}, $state->{selected}, $state->{whatrequires}, flag_requested, flag_required)
+sub _choose_required {
+    my ($urpm, $db, $state, $dep, $properties, $choices, $diff_provides, %options) = @_;
+
+    #- take the best choice possible.
+    my ($chosen, $prefered) = find_required_package($urpm, $db, $state, $dep->{required});
+
+    #- If no choice is found, this means that nothing can be possibly selected
+    #- according to $dep, so we need to retry the selection, allowing all
+    #- packages that conflict or anything similar to see which strategy can be
+    #- tried. Backtracking is used to avoid trying multiple times the same
+    #- packages. If multiple packages are possible and properties is not
+    #- empty, postpone the choice for a later time as one of the packages
+    #- may be selected for another reason. Otherwise simply ask the user which
+    #- one to choose; else take the first one available.
+    if (!@$chosen) {
+	$urpm->{debug_URPM}("no packages match " . _dep_to_name($urpm, $dep) . " (it is either in skip.list or already rejected)") if $urpm->{debug_URPM};
+	unshift @$properties, backtrack_selected($urpm, $db, $state, $dep, $diff_provides, %options);
+	return; #- backtrack code choose to continue with same package or completely new strategy.
+    } elsif (@$chosen > 1) {
+	if (@$properties) {
+	    unshift @$choices, $dep;
+	    return;
+	} elsif ($options{callback_choices}) {
+	    my @l = grep { ref $_ } $options{callback_choices}->($urpm, $db, $state, $chosen, _dep_to_name($urpm, $dep), $prefered);
+	    $urpm->{debug_URPM}("replacing " . _dep_to_name($urpm, $dep) . " with " . 
+				join(' ', map { $_->name } @l)) if $urpm->{debug_URPM};
+	    unshift @$properties, map {
+		+{
+		    required => $_->id,
+		    _choices => $dep->{required},
+		    exists $dep->{from} ? (from => $dep->{from}) : @{[]},
+		    exists $dep->{requested} ? (requested => $dep->{requested}) : @{[]},
+		};
+	    } @l;
+	    return; #- always redo according to choices.
+	}
+    }
+
+
+    #- now do the real work, select the package.
+    my $pkg = shift @$chosen;
+    if ($urpm->{debug_URPM} && $pkg->name ne _dep_to_name($urpm, $dep)) {
+	$urpm->{debug_URPM}("chosen " . $pkg->fullname . " for " . _dep_to_name($urpm, $dep));
+	@$chosen and $urpm->{debug_URPM}("  (it could also have chosen " . join(' ', map { scalar $_->fullname } @$chosen));
+    }
+
+    $pkg;
+}
+
+sub pkg2media {
+   my ($mediums, $p) = @_; 
+   my $id = $p->id;
+   #- || 0 to avoid undef, but is it normal to have undef ?
+   find { $id >= ($_->{start} || 0) && $id <= ($_->{end} || 0) } @$mediums;
+}
+
+sub whatrequires {
+    my ($urpm, $state, $property_name) = @_;
+
+    map { $urpm->{depslist}[$_] } whatrequires_id($state, $property_name);
+}
+sub whatrequires_id {
+    my ($state, $property_name) = @_;
+
+    keys %{$state->{whatrequires}{$property_name} || {}};
+}
+
+#- return unresolved requires of a package (a new one or an existing one).
+#-
+#- side-effects: none (but uses a $state->{cached_installed})
+sub unsatisfied_requires {
+    my ($urpm, $db, $state, $pkg, %options) = @_;
+    my %unsatisfied;
+
+    #- all requires should be satisfied according to selected packages or installed packages,
+    #- or the package itself.
+  REQUIRES: foreach my $prop ($pkg->requires) {
+	my ($n, $s) = property2name_range($prop) or next;
+
+	if (defined $options{name} && $n ne $options{name}) {
+	    #- allow filtering on a given name (to speed up some search).
+	} elsif (exists $unsatisfied{$prop}) {
+	    #- avoid recomputing the same all the time.
+	} else {
+	    #- check for installed packages in the installed cache.
+	    foreach (keys %{$state->{cached_installed}{$n} || {}}) {
+		exists $state->{rejected}{$_} and next;
+		next REQUIRES;
+	    }
+
+	    #- check on the selected package if a provide is satisfying the resolution (need to do the ops).
+	    foreach (grep { exists $state->{selected}{$_} } keys %{$urpm->{provides}{$n} || {}}) {
+		my $p = $urpm->{depslist}[$_];
+		!$urpm->{provides}{$n}{$_} || $p->provides_overlap($prop, 1) and next REQUIRES;
+	    }
+
+	    #- check if the package itself provides what is necessary.
+	    $pkg->provides_overlap($prop) and next REQUIRES;
+
+	    #- check on installed system if a package which is not obsoleted is satisfying the require.
+	    my $satisfied = 0;
+	    if ($n =~ m!^/!) {
+		$db->traverse_tag('path', [ $n ], sub {
+		    my ($p) = @_;
+		    exists $state->{rejected}{$p->fullname} and return;
+		    $state->{cached_installed}{$n}{$p->fullname} = undef;
+		    ++$satisfied;
+		});
+	    } else {
+		$db->traverse_tag('whatprovides', [ $n ], sub {
+		    my ($p) = @_;
+		    exists $state->{rejected}{$p->fullname} and return;
+		    foreach ($p->provides) {
+			if (my ($pn, $ps) = property2name_range($_)) {
+			    $ps or $state->{cached_installed}{$pn}{$p->fullname} = undef;
+			    $pn eq $n or next;
+			    URPM::ranges_overlap($ps, $s, 1) and ++$satisfied;
+			}
+		    }
+		});
+	    }
+	    #- if nothing can be done, the require should be resolved.
+	    $satisfied or $unsatisfied{$prop} = undef;
+	}
+    }
+
+    keys %unsatisfied;
+}
+
+#- this function is "suggests vs requires" safe:
+#-   'whatrequires' will give both requires & suggests, but unsatisfied_requires
+#-   will check $p->requires and so filter out suggests
+
+#- side-effects: only those done by $do
+sub with_db_unsatisfied_requires {
+    my ($urpm, $db, $state, $name, $do) = @_;
+
+    $db->traverse_tag('whatrequires', [ $name ], sub {
+	my ($p) = @_;
+	if (my @l = unsatisfied_requires($urpm, $db, $state, $p, name => $name)) {
+	    $urpm->{debug_URPM}("installed " . $p->fullname . " is conflicting because of unsatisfied @l") if $urpm->{debug_URPM};
+	    $do->($p, @l);
+	}
+    });
+}
+
+#- side-effects: only those done by $do
+sub with_state_unsatisfied_requires {
+    my ($urpm, $db, $state, $name, $do) = @_;
+
+    foreach (whatrequires_id($state, $name)) {
+	$state->{selected}{$_} or next;
+	my $p = $urpm->{depslist}[$_];
+	if (my @l = unsatisfied_requires($urpm, $db, $state, $p, name => $name)) {
+	    $urpm->{debug_URPM}("selected " . $p->fullname . " is conflicting because of unsatisfied @l") if $urpm->{debug_URPM};
+	    $do->($p, @l);
+        }
+    }
+}
+
+sub with_any_unsatisfied_requires {
+    my ($urpm, $db, $state, $name, $do) = @_;
+    with_db_unsatisfied_requires($urpm, $db, $state, $name, sub { my ($p, @l) = @_; $do->($p, 0, @l)});
+    with_state_unsatisfied_requires($urpm, $db, $state, $name, sub { my ($p, @l) = @_; $do->($p, 1, @l)});
+}
+
+
+# used when a require is not available
+#
+#- side-effects: $state->{backtrack}, $state->{selected}
+#-   + those of disable_selected_and_unrequested_dependencies ($state->{whatrequires}, flag_requested, flag_required)
+#-   + those of _set_rejected_from ($state->{rejected})
+#-   + those of set_rejected_and_compute_diff_provides ($state->{rejected}, $diff_provides_h)
+#-   + those of _add_rejected_backtrack ($state->{rejected})
+sub backtrack_selected {
+    my ($urpm, $db, $state, $dep, $diff_provides, %options) = @_;
+
+    if (defined $dep->{required}) {
+	#- avoid deadlock here...
+	if (!exists $state->{backtrack}{deadlock}{$dep->{required}}) {
+	    $state->{backtrack}{deadlock}{$dep->{required}} = undef;
+
+	    #- search for all possible packages, first is to try the selection, then if it is
+	    #- impossible, backtrack the origin.
+	    my @packages = find_candidate_packages_($urpm, $dep->{required});
+
+	    foreach (@packages) {
+		    #- avoid dead loop.
+		    exists $state->{backtrack}{selected}{$_->id} and next;
+		    #- a package if found is problably rejected or there is a problem.
+		    if ($state->{rejected}{$_->fullname}) {
+			#- keep in mind a backtrack has happening here...
+			exists $dep->{promote} and _add_rejected_backtrack($state, $_, { promote => [ $dep->{promote} ] });
+
+			my $closure = $state->{rejected}{$_->fullname}{closure} || {};
+			foreach my $p (grep { exists $closure->{$_}{avoid} } keys %$closure) {
+				_add_rejected_backtrack($state, $_, { conflicts => [ $p ] })
+			}
+			#- backtrack callback should return a strictly positive value if the selection of the new
+			#- package is prefered over the currently selected package.
+			next;
+		    }
+		    $state->{backtrack}{selected}{$_->id} = undef;
+
+		    #- in such case, we need to drop the problem caused so that rejected condition is removed.
+		    #- if this is not possible, the next backtrack on the same package will be refused above.
+		    my @l = map { $urpm->search($_, strict_fullname => 1) }
+		      keys %{($state->{rejected}{$_->fullname} || {})->{closure}};
+
+		    disable_selected_and_unrequested_dependencies($urpm, $db, $state, @l);
+
+		    return { required => $_->id,
+			     exists $dep->{from} ? (from => $dep->{from}) : @{[]},
+			     exists $dep->{requested} ? (requested => $dep->{requested}) : @{[]},
+			     exists $dep->{promote} ? (promote => $dep->{promote}) : @{[]},
+			     exists $dep->{psel} ? (psel => $dep->{psel}) : @{[]},
+			   };
+	    }
+	}
+    }
+
+    if (defined $dep->{from}) {
+	if ($options{nodeps}) {
+	    #- try to keep unsatisfied dependencies in requested.
+	    if ($dep->{required} && exists $state->{selected}{$dep->{from}->id}) {
+		push @{$state->{selected}{$dep->{from}->id}{unsatisfied}}, $dep->{required};
+	    }
+	} else {
+	    #- at this point, dep cannot be resolved, this means we need to disable
+	    #- all selection tree, re-enabling removed and obsoleted packages as well.
+	    unless (exists $state->{rejected}{$dep->{from}->fullname}) {
+		#- package is not currently rejected, compute the closure now.
+		my @l = disable_selected_and_unrequested_dependencies($urpm, $db, $state, $dep->{from});
+		foreach (@l) {
+		    #- disable all these packages in order to avoid selecting them again.
+		    _set_rejected_from($state, $_, $dep->{from}); 
+		}
+	    }
+	    #- the package is already rejected, we assume we can add another reason here!
+	    $urpm->{debug_URPM}("adding a reason to already rejected package " . $dep->{from}->fullname . ": unsatisfied " . $dep->{required}) if $urpm->{debug_URPM};
+	    
+	    _add_rejected_backtrack($state, $dep->{from}, { unsatisfied => [ $dep->{required} ] });
+	}
+    }
+
+    my @properties;
+    if (defined $dep->{psel}) {
+	if ($options{keep}) {
+	    backtrack_selected_psel_keep($urpm, $db, $state, $dep->{psel}, $dep->{keep});
+
+	    #- the package is already rejected, we assume we can add another reason here!
+	    defined $dep->{promote} and _add_rejected_backtrack($state, $dep->{psel}, { promote => [ $dep->{promote} ] });
+	} else {
+	    #- the backtrack need to examine diff_provides promotion on $n.
+	    with_db_unsatisfied_requires($urpm, $db, $state, $dep->{promote}, sub {
+				      my ($p, @unsatisfied) = @_;
+				      my %diff_provides_h;
+				      set_rejected_and_compute_diff_provides($urpm, $state, \%diff_provides_h, {
+							      rejected_pkg => $p, removed => 1,
+							      from => $dep->{psel},
+							      why => { unsatisfied => \@unsatisfied }
+							  });
+				      push @$diff_provides, map { +{ name => $_, pkg => $dep->{psel} } } keys %diff_provides_h;
+			      });
+	    with_state_unsatisfied_requires($urpm, $db, $state, $dep->{promote}, sub {
+				      my ($p) = @_;
+				      _set_rejected_from($state, $p, $dep->{psel});
+				      disable_selected_and_unrequested_dependencies($urpm, $db, $state, $p);
+			      });
+	}
+    }
+
+    #- some packages may have been removed because of selection of this one.
+    #- the rejected flags should have been cleaned by disable_selected above.
+    @properties;
+}
+
+#- side-effects:
+#-   + those of _set_rejected_from ($state->{rejected})
+#-   + those of _add_rejected_backtrack ($state->{rejected})
+#-   + those of disable_selected_and_unrequested_dependencies ($state->{selected}, $state->{whatrequires}, flag_requested, flag_required)
+sub backtrack_selected_psel_keep {
+    my ($urpm, $db, $state, $psel, $keep) = @_;
+
+    #- we shouldn't try to remove packages, so psel which leads to this need to be unselected.
+    unless (exists $state->{rejected}{$psel->fullname}) {
+	#- package is not currently rejected, compute the closure now.
+	my @l = disable_selected_and_unrequested_dependencies($urpm, $db, $state, $psel);
+	foreach (@l) {
+	    #- disable all these packages in order to avoid selecting them again.
+	    _set_rejected_from($state, $_, $psel);
+	}
+    }
+    #- to simplify, a reference to list or standalone elements may be set in keep.
+    $keep and _add_rejected_backtrack($state, $psel, { keep => $keep });
+}
+
+#- side-effects: $state->{rejected}
+sub _remove_all_rejected_from {
+    my ($state, $from_fullname) = @_;
+
+    grep {
+	_remove_rejected_from($state, $_, $from_fullname);
+    } keys %{$state->{rejected}};
+}
+
+#- side-effects: $state->{rejected}
+sub _remove_rejected_from {
+    my ($state, $fullname, $from_fullname) = @_;
+
+    my $rv = $state->{rejected}{$fullname} or return;
+
+    foreach (qw(removed obsoleted)) {
+	if (exists $rv->{$_} && exists $rv->{$_}{$from_fullname}) {
+	    delete $rv->{$_}{$from_fullname};
+	    delete $rv->{$_} if !%{$rv->{$_}};
+	}
+    }
+
+    exists $rv->{closure}{$from_fullname} or return;
+    delete $rv->{closure}{$from_fullname};
+    if (%{$rv->{closure}}) {
+	0;
+    } else {
+	delete $state->{rejected}{$fullname};
+	1;
+    }
+}
+
+#- side-effects: $state->{rejected}
+sub _add_rejected_backtrack {
+    my ($state, $pkg, $backtrack) = @_;
+
+    my $bt = $state->{rejected}{$pkg->fullname}{backtrack} ||= {};
+
+    foreach (keys %$backtrack) {
+	push @{$bt->{$_}}, @{$backtrack->{$_}};
+    }
+}
+
+#- useful to reject packages in advance
+#- eg when selecting "a" which conflict with "b", ensure we won't select "b"
+#- but it's somewhat dangerous because it's sometimes called on installed packages,
+#- and in that case, a real resolve_rejected_ must be done
+#- (that's why set_rejected ignores the effect of _set_rejected_from)
+#-
+#- side-effects: $state->{rejected}
+sub _set_rejected_from {
+    my ($state, $pkg, $from_pkg) = @_;
+
+    $pkg->fullname ne $from_pkg->fullname or return;
+
+    $state->{rejected}{$pkg->fullname}{closure}{$from_pkg->fullname}{avoid} ||= undef;
+}
+
+#- side-effects: $state->{rejected}
+sub _set_rejected_old_package {
+    my ($state, $pkg, $new_pkg) = @_;
+
+    if ($pkg->fullname eq $new_pkg->fullname) {
+	$state->{rejected_already_installed}{$pkg->id} = $pkg;
+    } else {
+	push @{$state->{rejected}{$pkg->fullname}{backtrack}{keep}}, scalar $new_pkg->fullname;
+    }
+}
+
+#- side-effects: $state->{rejected}
+sub set_rejected {
+    my ($urpm, $state, $rdep) = @_;
+
+    my $fullname = $rdep->{rejected_pkg}->fullname;
+    my $rv = $state->{rejected}{$fullname} ||= {};
+
+    my $newly_rejected = !exists $rv->{size};
+
+    if ($newly_rejected) {
+	$urpm->{debug_URPM}("set_rejected: $fullname") if $urpm->{debug_URPM};
+	#- keep track of size of package which are finally removed.
+	$rv->{size} = $rdep->{rejected_pkg}->size;
+    }
+
+    #- keep track of what causes closure.
+    if ($rdep->{from}) {
+	my $closure = $rv->{closure}{scalar $rdep->{from}->fullname} ||= {};
+	if (my $l = delete $rdep->{why}{unsatisfied}) {
+	    my $unsatisfied = $closure->{unsatisfied} ||= [];
+	    @$unsatisfied = uniq(@$unsatisfied, @$l);
+	}
+	$closure->{$_} = $rdep->{why}{$_} foreach keys %{$rdep->{why}};
+    }
+
+    #- set removed and obsoleted level.
+    foreach (qw(removed obsoleted)) {
+	if ($rdep->{$_}) {
+	    if ($rdep->{from}) {
+		$rv->{$_}{scalar $rdep->{from}->fullname} = undef;
+	    } else {
+		$rv->{$_}{asked} = undef;
+	    }
+	}
+    }
+
+    $newly_rejected;
+}
+
+#- side-effects:
+#-   + those of set_rejected ($state->{rejected})
+#-   + those of _compute_diff_provides_of_removed_pkg ($diff_provides_h)
+sub set_rejected_and_compute_diff_provides {
+    my ($urpm, $state, $diff_provides_h, $rdep) = @_;
+
+    my $newly_rejected = set_rejected($urpm, $state, $rdep);
+
+    #- no need to compute diff_provides if package was already rejected
+    $newly_rejected or return;
+
+    _compute_diff_provides_of_removed_pkg($urpm, $state, $diff_provides_h, $rdep->{rejected_pkg});
+}
+
+#- see resolve_rejected_ below
+sub resolve_rejected {
+    my ($urpm, $db, $state, $pkg, %rdep) = @_;
+    $rdep{rejected_pkg} = $pkg;
+    resolve_rejected_($urpm, $db, $state, $rdep{unsatisfied}, \%rdep);
+}
+
+#- close rejected (as urpme previously) for package to be removable without error.
+#-
+#- side-effects: $properties
+#-   + those of set_rejected ($state->{rejected})
+sub resolve_rejected_ {
+    my ($urpm, $db, $state, $properties, $rdep) = @_;
+
+    $urpm->{debug_URPM}("resolve_rejected: " . $rdep->{rejected_pkg}->fullname) if $urpm->{debug_URPM};
+
+    #- check if the package has already been asked to be rejected (removed or obsoleted).
+    #- this means only add the new reason and return.
+    my $newly_rejected = set_rejected($urpm, $state, $rdep);
+
+    $newly_rejected or return;
+
+	my @pkgs_todo = $rdep->{rejected_pkg};
+
+	while (my $cp = shift @pkgs_todo) {
+	    #- close what requires this property, but check with selected package requiring old properties.
+	    foreach my $n ($cp->provides_nosense) {
+		    foreach my $pkg (whatrequires($urpm, $state, $n)) {
+			if (my @l = unsatisfied_requires($urpm, $db, $state, $pkg, name => $n)) {
+			    #- a selected package requires something that is no more available
+			    #- and should be tried to be re-selected if possible.
+			    if ($properties) {
+				push @$properties, map { 
+				    { required => $_, rejected => scalar $pkg->fullname }; # rejected is only there for debugging purpose (??)
+				} @l;
+			    }
+			}
+		    }
+		    with_db_unsatisfied_requires($urpm, $db, $state, $n, sub {
+			    my ($p, @unsatisfied) = @_;
+
+			    my $newly_rejected = set_rejected($urpm, $state, {
+				rejected_pkg => $p,
+				from => $rdep->{rejected_pkg}, 
+				why => { unsatisfied => \@unsatisfied },
+				obsoleted => $rdep->{obsoleted},
+				removed => $rdep->{removed},
+			    });				
+
+			    #- continue the closure unless already examined.
+			    $newly_rejected or return;
+
+			    $p->pack_header; #- need to pack else package is no longer visible...
+			    push @pkgs_todo, $p;
+		    });
+	    }
+	}
+}
+
+# see resolve_requested__no_suggests below for information about usage
+sub resolve_requested {
+    my ($urpm, $db, $state, $requested, %options) = @_;
+
+    my @selected = resolve_requested__no_suggests($urpm, $db, $state, $requested, %options);
+
+    if (!$options{no_suggests}) {
+	my @todo = @selected;
+	while (@todo) {
+	    my $pkg = shift @todo;
+	    my %suggests = map { $_ => 1 } $pkg->suggests or next;
+
+	    #- do not install a package that has already been suggested
+	    $db->traverse_tag('name', [ $pkg->name ], sub {
+		my ($p) = @_;
+		delete $suggests{$_} foreach $p->suggests;
+	    });
+
+	    # workaround: if you do "urpmi virtual_pkg" and one virtual_pkg is already installed,
+	    # it will ask anyway for the other choices
+	    foreach my $suggest (keys %suggests) {
+		$db->traverse_tag('whatprovides', [ $suggest ], sub {
+		    delete $suggests{$suggest};
+		});
+	    }
+
+	    %suggests or next;
+
+	    $urpm->{debug_URPM}("requested " . join(', ', keys %suggests) . " suggested by " . $pkg->fullname) if $urpm->{debug_URPM};
+	    
+	    my %new_requested = map { $_ => undef } keys %suggests;
+	    my @new_selected = resolve_requested__no_suggests_($urpm, $db, $state, \%new_requested, %options);
+	    $state->{selected}{$_->id}{suggested} = 1 foreach @new_selected;
+	    push @selected, @new_selected;
+	    push @todo, @new_selected;
+	}
+    }
+    @selected;
+}
+
+#- Resolve dependencies of requested packages; keep resolution state to
+#- speed up process.
+#- A requested package is marked to be installed; once done, an upgrade flag or
+#- an installed flag is set according to the needs of the installation of this
+#- package.
+#- Other required packages will have a required flag set along with an upgrade
+#- flag or an installed flag.
+#- Base flag should always be "installed" or "upgraded".
+#- The following options are recognized :
+#-   callback_choices : subroutine to be called to ask the user to choose
+#-     between several possible packages. Returns an array of URPM::Package
+#-     objects, or an empty list eventually.
+#-   keep :
+#-   nodeps :
+#-
+#- side-effects: flag_requested
+#-   + those of resolve_requested__no_suggests_
+sub resolve_requested__no_suggests {
+    my ($urpm, $db, $state, $requested, %options) = @_;
+
+    foreach (keys %$requested) {
+	#- keep track of requested packages by propating the flag.
+	foreach (find_candidate_packages_($urpm, $_)) {
+	    $_->set_flag_requested;
+	}
+    }
+
+    resolve_requested__no_suggests_($urpm, $db, $state, $requested, %options);
+}
+
+# same as resolve_requested__no_suggests, but do not modify requested_flag
+#-
+#- side-effects: $state->{selected}, flag_required, flag_installed, flag_upgrade
+#-   + those of backtrack_selected     (flag_requested, $state->{rejected}, $state->{whatrequires}, $state->{backtrack})
+#-   + those of _unselect_package_deprecated_by (flag_requested, $state->{rejected}, $state->{whatrequires}, $state->{oldpackage}, $state->{unselected_uninstalled})
+#-   + those of _handle_conflicts      ($state->{rejected})
+#-   + those of _handle_conflict ($state->{rejected})
+#-   + those of backtrack_selected_psel_keep (flag_requested, $state->{whatrequires})
+#-   + those of _handle_diff_provides  (flag_requested, $state->{rejected}, $state->{whatrequires})
+#-   + those of _no_more_recent_installed_and_providing ($state->{rejected})
+sub resolve_requested__no_suggests_ {
+    my ($urpm, $db, $state, $requested, %options) = @_;
+
+    my @properties = map {
+	{ required => $_, requested => $requested->{$_} };
+    } keys %$requested;
+
+    my (@diff_provides, @selected, @choices);
+
+    #- for each dep property evaluated, examine which package will be obsoleted on $db,
+    #- then examine provides that will be removed (which need to be satisfied by another
+    #- package present or by a new package to upgrade), then requires not satisfied and
+    #- finally conflicts that will force a new upgrade or a remove.
+    do {
+	while (my $dep = shift @properties) {
+	    #- we need to avoid selecting packages if the source has been disabled.
+	    if (exists $dep->{from} && !$urpm->{keep_unrequested_dependencies}) {
+		exists $state->{selected}{$dep->{from}->id} or next;
+	    }
+
+	    my $pkg = _choose_required($urpm, $db, $state, $dep, \@properties, \@choices, \@diff_provides, %options) or next;
+
+	    !$pkg || exists $state->{selected}{$pkg->id} and next;
+
+	    if ($pkg->arch eq 'src') {
+		$pkg->set_flag_upgrade;
+	    } else {
+		_set_flag_installed_and_upgrade_if_no_newer($db, $pkg);
+
+		if ($pkg->flag_installed && !$pkg->flag_upgrade) {
+		    _no_more_recent_installed_and_providing($urpm, $db, $state, $pkg, $dep->{required}) or next;
+		}
+	    }
+
+	    _handle_conflicts_with_selected($urpm, $db, $state, $pkg, $dep, \@properties, \@diff_provides, %options) or next;
+
+	    $urpm->{debug_URPM}("selecting " . $pkg->fullname) if $urpm->{debug_URPM};
+
+	    #- keep in mind the package has be selected, remove the entry in requested input hash,
+	    #- this means required dependencies have undef value in selected hash.
+	    #- requested flag is set only for requested package where value is not false.
+	    push @selected, $pkg;
+	    $state->{selected}{$pkg->id} = { exists $dep->{requested} ? (requested => $dep->{requested}) : @{[]},
+					     exists $dep->{from} ? (from => $dep->{from}) : @{[]},
+					     exists $dep->{promote} ? (promote => $dep->{promote}) : @{[]},
+					     exists $dep->{psel} ? (psel => $dep->{psel}) : @{[]},
+					     $pkg->flag_disable_obsolete ? (install => 1) : @{[]},
+					   };
+
+	    $pkg->set_flag_required;
+
+	    #- check if the package is not already installed before trying to use it, compute
+	    #- obsoleted packages too. This is valable only for non source packages.
+	    my %diff_provides_h;
+	    if ($pkg->arch ne 'src' && !$pkg->flag_disable_obsolete) {
+		_unselect_package_deprecated_by($urpm, $db, $state, \%diff_provides_h, $pkg);
+	    }
+
+	    #- all requires should be satisfied according to selected package, or installed packages.
+	    if (my @l = unsatisfied_requires($urpm, $db, $state, $pkg)) {
+		$urpm->{debug_URPM}("requiring " . join(',', sort @l) . " for " . $pkg->fullname) if $urpm->{debug_URPM};
+		unshift @properties, map { +{ required => $_, from => $pkg,
+					  exists $dep->{promote} ? (promote => $dep->{promote}) : @{[]},
+					  exists $dep->{psel} ? (psel => $dep->{psel}) : @{[]},
+					} } @l;
+	    }
+
+	    #- keep in mind what is requiring each item (for unselect to work).
+	    foreach ($pkg->requires_nosense) {
+		$state->{whatrequires}{$_}{$pkg->id} = undef;
+	    }
+
+	    #- cancel flag if this package should be cancelled but too late (typically keep options).
+	    my @keep;
+
+	    _handle_conflicts($urpm, $db, $state, $pkg, \@properties, \%diff_provides_h, $options{keep} && \@keep);
+
+	    #- examine if an existing package does not conflict with this one.
+	    $db->traverse_tag('whatconflicts', [ $pkg->provides_nosense ], sub {
+		@keep and return;
+		my ($p) = @_;
+		foreach my $property ($p->conflicts) {
+		    if ($pkg->provides_overlap($property)) {
+			_handle_conflict($urpm, $state, $pkg, $p, $property, $property, \@properties, \%diff_provides_h, $options{keep} && \@keep);
+		    }
+		}
+	    });
+
+	    #- keep existing package and therefore cancel current one.
+	    if (@keep) {
+		backtrack_selected_psel_keep($urpm, $db, $state, $pkg, \@keep);
+	    }
+
+	    push @diff_provides, map { +{ name => $_, pkg => $pkg } } keys %diff_provides_h;
+	}
+	if (my $diff = shift @diff_provides) {
+	    _handle_diff_provides($urpm, $db, $state, \@properties, \@diff_provides, $diff->{name}, $diff->{pkg}, %options);
+	} elsif (my $dep = shift @choices) {
+	    push @properties, $dep;
+	}
+    } while @diff_provides || @properties || @choices;
+
+    #- return what has been selected by this call (not all selected hash which may be not empty
+    #- previously. avoid returning rejected packages which weren't selectable.
+    grep { exists $state->{selected}{$_->id} } @selected;
+}
+
+#- pre-disables packages that $pkg has conflict entries for, and
+#- unselects $pkg if such a package is already selected
+#- side-effects:
+#-   + those of _set_rejected_from ($state->{rejected})
+#-   + those of _remove_all_rejected_from ($state->{rejected})
+#-   + those of backtrack_selected ($state->{backtrack}, $state->{rejected}, $state->{selected}, $state->{whatrequires}, flag_requested, flag_required)
+sub _handle_conflicts_with_selected {
+    my ($urpm, $db, $state, $pkg, $dep, $properties, $diff_provides, %options) = @_;
+    foreach ($pkg->conflicts) {
+	if (my ($n, $o, $v) = property2name_op_version($_)) {
+	    foreach my $p ($urpm->packages_providing($n)) {
+		$pkg == $p and next;
+		$p->provides_overlap($_) or next;
+		if (exists $state->{selected}{$p->id}) {
+		    $urpm->{debug_URPM}($pkg->fullname . " conflicts with already selected package " . $p->fullname) if $urpm->{debug_URPM};
+		    _remove_all_rejected_from($state, $pkg);
+		    _set_rejected_from($state, $pkg, $p);
+		    unshift @$properties, backtrack_selected($urpm, $db, $state, $dep, $diff_provides, %options);
+		    return;
+		}
+		_set_rejected_from($state, $p, $pkg);
+	    }
+	}
+    }
+    1;
+}
+
+#- side-effects:
+#-   + those of set_rejected_and_compute_diff_provides ($state->{rejected}, $diff_provides_h)
+#-   + those of _handle_conflict ($properties, $keep, $diff_provides_h)
+sub _handle_conflicts {
+    my ($urpm, $db, $state, $pkg, $properties, $diff_provides_h, $keep) = @_;
+
+    #- examine conflicts, an existing package conflicting with this selection should
+    #- be upgraded to a new version which will be safe, else it should be removed.
+    foreach ($pkg->conflicts) {
+	$keep && @$keep and last;
+	if (my ($file) = m!^(/[^\s\[]*)!) {
+	    $db->traverse_tag('path', [ $file ], sub {
+		$keep && @$keep and return;
+		my ($p) = @_;
+		if ($keep) {
+		    push @$keep, scalar $p->fullname;
+		} else {
+		    #- all these package should be removed.
+		    set_rejected_and_compute_diff_provides($urpm, $state, $diff_provides_h, {
+				      rejected_pkg => $p, removed => 1,
+				      from => $pkg,
+				      why => { conflicts => $file },
+				  });
+		}
+	    });
+	} elsif (my $name = property2name($_)) {
+	    my $property = $_;
+	    $db->traverse_tag('whatprovides', [ $name ], sub {
+		$keep && @$keep and return;
+		my ($p) = @_;
+		if ($p->provides_overlap($property)) {
+		    _handle_conflict($urpm, $state, $pkg, $p, $property, scalar($pkg->fullname), $properties, $diff_provides_h, $keep);
+		}
+	    });
+	}
+    }
+}
+
+#- side-effects:
+#-   + those of _unselect_package_deprecated_by_property (flag_requested, flag_required, $state->{selected}, $state->{rejected}, $state->{whatrequires}, $state->{oldpackage}, $state->{unselected_uninstalled})
+sub _unselect_package_deprecated_by {
+    my ($urpm, $db, $state, $diff_provides_h, $pkg) = @_;
+
+    _unselect_package_deprecated_by_property($urpm, $db, $state, $pkg, $diff_provides_h, $pkg->name, '<', $pkg->epoch . ":" . $pkg->version . "-" . $pkg->release);
+
+    foreach ($pkg->obsoletes) {
+	my ($n, $o, $v) = property2name_op_version($_) or next;
+
+	#- ignore if this package obsoletes itself
+	#- otherwise this can cause havoc if: to_install=v3, installed=v2, v3 obsoletes < v2
+	if ($n ne $pkg->name) {
+	    _unselect_package_deprecated_by_property($urpm, $db, $state, $pkg, $diff_provides_h, $n, $o, $v);
+	}
+    }
+}
+
+#- side-effects: $state->{oldpackage}, $state->{unselected_uninstalled}
+#-   + those of set_rejected ($state->{rejected})
+#-   + those of _set_rejected_from ($state->{rejected})
+#-   + those of disable_selected (flag_requested, flag_required, $state->{selected}, $state->{rejected}, $state->{whatrequires})
+sub _unselect_package_deprecated_by_property {
+    my ($urpm, $db, $state, $pkg, $diff_provides_h, $n, $o, $v) = @_;
+
+    #- populate avoided entries according to what is selected.
+    foreach my $p ($urpm->packages_providing($n)) {
+	if ($p->name eq $pkg->name) {
+	    #- all packages with the same name should now be avoided except when chosen.
+	} else {
+	    #- in case of obsoletes, keep track of what should be avoided
+	    #- but only if package name equals the obsolete name.
+	    $p->name eq $n && (!$o || eval($p->compare($v) . $o . 0)) or next;
+	}
+	#- these packages are not yet selected, if they happen to be selected,
+	#- they must first be unselected.
+	_set_rejected_from($state, $p, $pkg);
+    }
+	
+    #- examine rpm db too (but only according to package names as a fix in rpm itself)
+    $db->traverse_tag('name', [ $n ], sub {
+	my ($p) = @_;
+
+	#- without an operator, anything (with the same name) is matched.
+	#- with an operator, check package EVR with the obsoletes EVR.
+	#- $satisfied is true if installed package has version newer or equal.
+	my $comparison = $p->compare($v);
+	my $satisfied = !$o || eval($comparison . $o . 0);
+
+	my $obsoleted;
+	if ($p->name eq $pkg->name) {
+	    #- all packages older than the current one are obsoleted,
+	    #- the others are simply removed (the result is the same).
+	    if ($o && $comparison > 0) {
+		#- installed package is newer
+		#- remove this package from the list of packages to install,
+		#- unless urpmi was invoked with --allow-force (in which
+		#- case rpm could be invoked with --oldpackage)
+		if (!$urpm->{options}{'allow-force'}) {
+		    #- since the originally requested packages (or other
+		    #- non-installed ones) could be unselected by the following
+		    #- operation, remember them, to warn the user
+		    $state->{unselected_uninstalled} = [ grep {
+			!$_->flag_installed;
+		    } disable_selected($urpm, $db, $state, $pkg) ];
+
+		    return;
+		}
+	    } elsif ($satisfied) {
+		$obsoleted = 1;
+	    }
+	} elsif ($satisfied) {
+	    $obsoleted = 1;
+	} else {
+	    return;
+	}
+
+	set_rejected_and_compute_diff_provides($urpm, $state, $diff_provides_h, { 
+	    rejected_pkg => $p,
+	    obsoleted => $obsoleted, removed => !$obsoleted,
+	    from => $pkg, why => $obsoleted ? undef : { old_requested => 1 },
+	});
+	$obsoleted or ++$state->{oldpackage};
+    });
+}
+
+#- side-effects: $diff_provides
+sub _compute_diff_provides_of_removed_pkg {
+    my ($urpm, $state, $diff_provides_h, $p) = @_;
+
+	foreach ($p->provides) {
+	    #- check differential provides between obsoleted package and newer one.
+	    my ($pn, $ps) = property2name_range($_) or next;
+
+	    my $not_provided = 1;
+	    foreach (grep { exists $state->{selected}{$_} }
+		       keys %{$urpm->{provides}{$pn} || {}}) {
+		my $pp = $urpm->{depslist}[$_];
+		foreach ($pp->provides) {
+		    my ($ppn, $pps) = property2name_range($_) or next;
+		    $ppn eq $pn && $pps eq $ps
+		      and $not_provided = 0;
+		}
+	    }
+	    $not_provided and $diff_provides_h->{$pn} = undef;
+	}
+}
+
+#- side-effects: none
+sub _find_packages_obsoleting {
+    my ($urpm, $state, $p) = @_;
+
+    grep {
+	!$_->flag_skip
+	  && $_->is_arch_compat
+	    && !exists $state->{rejected}{$_->fullname}
+	      && $_->obsoletes_overlap($p->name . " == " . $p->epoch . ":" . $p->version . "-" . $p->release)
+		&& $_->fullname ne $p->fullname
+		  && (!strict_arch($urpm) || strict_arch_check($p, $_));
+    } $urpm->packages_obsoleting($p->name);
+}
+
+#- side-effects: $properties
+#-   + those of backtrack_selected_psel_keep ($state->{rejected}, $state->{selected}, $state->{whatrequires}, flag_requested, flag_required)
+#-   + those of resolve_rejected_ ($state->{rejected}, $properties)
+#-   + those of disable_selected_and_unrequested_dependencies (flag_requested, flag_required, $state->{selected}, $state->{whatrequires}, $state->{rejected})
+#-   + those of _set_rejected_from ($state->{rejected})
+sub _handle_diff_provides {
+    my ($urpm, $db, $state, $properties, $diff_provides, $n, $pkg, %options) = @_;
+
+    with_any_unsatisfied_requires($urpm, $db, $state, $n, sub {
+	my ($p, $from_state, @unsatisfied) = @_;
+
+	#- try if upgrading the package will be satisfying all the requires...
+	#- there is no need to avoid promoting epoch as the package examined is not
+	#- already installed.
+	my @packages = find_candidate_packages_($urpm, $p->name, $state->{rejected});
+	@packages = 
+	  grep { ($_->name eq $p->name ? $p->compare_pkg($_) < 0 :
+		    $_->obsoletes_overlap($p->name . " == " . $p->epoch . ":" . $p->version . "-" . $p->release))
+		   && (!strict_arch($urpm) || strict_arch_check($p, $_))
+	     } @packages;
+
+	if (!@packages) {
+	    @packages = _find_packages_obsoleting($urpm, $state, $p);
+	}
+
+	if (@packages) {
+	    my $best = join('|', map { $_->id } @packages);
+	    $urpm->{debug_URPM}("promoting " . $urpm->{depslist}[$best]->fullname . " because of conflict above") if $urpm->{debug_URPM};
+	    push @$properties, { required => $best, promote => $n, psel => $pkg };
+	} else {
+	    #- no package have been found, we may need to remove the package examined unless
+	    #- there exists enough packages that provided the unsatisfied requires.
+	    my @best;
+	    foreach (@unsatisfied) {
+		my @packages = find_candidate_packages_($urpm, $_, $state->{rejected});
+		if (@packages = grep { $_->fullname ne $p->fullname } @packages) {
+		    push @best, join('|', map { $_->id } @packages);
+		}
+	    }
+
+	    if (@best == @unsatisfied) {
+		$urpm->{debug_URPM}("promoting " . join(' ', _ids_to_fullnames($urpm, @best)) . " because of conflict above") if $urpm->{debug_URPM};
+		push @$properties, map { +{ required => $_, promote => $n, psel => $pkg } } @best;
+	    } else {
+		if ($from_state) {
+		    disable_selected_and_unrequested_dependencies($urpm, $db, $state, $p);
+		    _set_rejected_from($state, $p, $pkg);
+		} elsif ($options{keep}) {
+		    backtrack_selected_psel_keep($urpm, $db, $state, $pkg, [ scalar $p->fullname ]);
+		} else {
+		    my %diff_provides_h;
+		    set_rejected_and_compute_diff_provides($urpm, $state, \%diff_provides_h, {
+				      rejected_pkg => $p, removed => 1,
+				      from => $pkg,
+				      why => { unsatisfied => \@unsatisfied },
+				  });
+		    push @$diff_provides, map { +{ name => $_, pkg => $pkg } } keys %diff_provides_h;
+		}
+	    }
+	}
+    });
+}
+
+#- side-effects: $properties, $keep
+#-   + those of set_rejected_and_compute_diff_provides ($state->{rejected}, $diff_provides_h)
+sub _handle_conflict {
+    my ($urpm, $state, $pkg, $p, $property, $reason, $properties, $diff_provides_h, $keep) = @_;
+    
+    $urpm->{debug_URPM}("installed package " . $p->fullname . " is conflicting with " . $pkg->fullname . " (Conflicts: $property)") if $urpm->{debug_URPM};
+
+    #- the existing package will conflict with the selection; check
+    #- whether a newer version will be ok, else ask to remove the old.
+    my $need_deps = $p->name . " > " . ($p->epoch ? $p->epoch . ":" : "") .
+      $p->version . "-" . $p->release;
+    my @packages = grep { $_->name eq $p->name } find_candidate_packages_($urpm, $need_deps, $state->{rejected});
+    @packages = grep { ! $_->provides_overlap($property) } @packages;
+
+    if (!@packages) {
+	@packages = _find_packages_obsoleting($urpm, $state, $p);
+	@packages = grep { ! $_->provides_overlap($property) } @packages;
+    }
+
+    if (@packages) {
+	my $best = join('|', map { $_->id } @packages);
+	$urpm->{debug_URPM}("promoting " . join('|', map { scalar $_->fullname } @packages) . " because of conflict above") if $urpm->{debug_URPM};
+	unshift @$properties, { required => $best, promote_conflicts => $reason };
+    } else {
+	if ($keep) {
+	    push @$keep, scalar $p->fullname;
+	} else {
+	    #- no package has been found, we need to remove the package examined.
+	    set_rejected_and_compute_diff_provides($urpm, $state, $diff_provides_h, {
+		rejected_pkg => $p, removed => 1,
+		from => $pkg,
+		why => { conflicts => $reason },
+	    });
+	}
+    }
+}
+
+#- side-effects: none
+sub _dep_to_name {
+    my ($urpm, $dep) = @_;
+    join('|', map { _id_to_name($urpm, $_) } split('\|', $dep->{required}));
+}
+#- side-effects: none
+sub _id_to_name {
+    my ($urpm, $id_prop) = @_;
+    if ($id_prop =~ /^\d+/) {
+	my $pkg = $urpm->{depslist}[$id_prop];
+	$pkg && $pkg->name;
+    } else {
+	$id_prop;
+    }
+}
+#- side-effects: none
+sub _ids_to_names {
+    my $urpm = shift;
+
+    map { $urpm->{depslist}[$_]->name } @_;
+}
+#- side-effects: none
+sub _ids_to_fullnames {
+    my $urpm = shift;
+
+    map { scalar $urpm->{depslist}[$_]->fullname } @_;
+}
+
+#- side-effects: flag_installed, flag_upgrade
+sub _set_flag_installed_and_upgrade_if_no_newer {
+    my ($db, $pkg) = @_;
+
+    !$pkg->flag_upgrade && !$pkg->flag_installed or return;
+
+    my $upgrade = 1;
+    $db->traverse_tag('name', [ $pkg->name ], sub {
+	my ($p) = @_;
+	$pkg->set_flag_installed;
+	$upgrade &&= $pkg->compare_pkg($p) > 0;
+    });
+    $pkg->set_flag_upgrade($upgrade);
+}
+
+#- side-effects:
+#-   + those of _set_rejected_old_package ($state->{rejected})
+sub _no_more_recent_installed_and_providing {
+    my ($urpm, $db, $state, $pkg, $required) = @_;
+
+    my $allow = 1;
+    $db->traverse_tag('name', [ $pkg->name ], sub {
+	my ($p) = @_;
+	#- allow if a less recent package is installed,
+	if ($allow && $pkg->compare_pkg($p) <= 0) {
+	    if ($required =~ /^\d+/ || $p->provides_overlap($required)) {
+		$urpm->{debug_URPM}("not selecting " . $pkg->fullname . " since the more recent " . $p->fullname . " is installed") if $urpm->{debug_URPM};
+		_set_rejected_old_package($state, $pkg, $p);
+		$allow = 0;
+	    } else {
+		$urpm->{debug_URPM}("the more recent " . $p->fullname . 
+		  " is installed, but does not provide $required whereas " . 
+		    $pkg->fullname . " does") if $urpm->{debug_URPM};
+	    }
+	}
+    });
+    $allow;
+}
+
+#- do the opposite of the resolve_requested:
+#-   unselect a package and extend to any package not requested that is no
+#-   longer needed by any other package.
+#- return the packages that have been deselected.
+#-
+#- side-effects: flag_requested, flag_required, $state->{selected}, $state->{whatrequires}
+#-   + those of _remove_all_rejected_from ($state->{rejected})
+sub disable_selected {
+    my ($urpm, $db, $state, @pkgs_todo) = @_;
+    my @unselected;
+
+    #- iterate over package needing unrequested one.
+    while (my $pkg = shift @pkgs_todo) {
+	exists $state->{selected}{$pkg->id} or next;
+
+	#- keep a trace of what is deselected.
+	push @unselected, $pkg;
+
+	#- perform a closure on rejected packages (removed, obsoleted or avoided).
+	my @rejected_todo = scalar $pkg->fullname;
+	while (my $fullname = shift @rejected_todo) {
+	    push @rejected_todo, _remove_all_rejected_from($state, $fullname);
+	}
+
+	#- the package being examined has to be unselected.
+	$urpm->{debug_URPM}("unselecting " . $pkg->fullname) if $urpm->{debug_URPM};
+	$pkg->set_flag_requested(0);
+	$pkg->set_flag_required(0);
+	delete $state->{selected}{$pkg->id};
+
+	#- determine package that requires properties no longer available, so that they need to be
+	#- unselected too.
+	foreach my $n ($pkg->provides_nosense) {
+	    foreach my $p (whatrequires($urpm, $state, $n)) {
+		exists $state->{selected}{$p->id} or next;
+		if (unsatisfied_requires($urpm, $db, $state, $p, name => $n)) {
+		    #- this package has broken dependencies and is selected.
+		    push @pkgs_todo, $p;
+		}
+	    }
+	}
+
+	#- clean whatrequires hash.
+	foreach ($pkg->requires_nosense) {
+	    delete $state->{whatrequires}{$_}{$pkg->id};
+	    %{$state->{whatrequires}{$_}} or delete $state->{whatrequires}{$_};
+	}
+    }
+
+    #- return all unselected packages.
+    @unselected;
+}
+
+#- determine dependencies that can safely been removed and are not requested
+#- return the packages that have been deselected.
+#-
+#- side-effects:
+#-   + those of disable_selected (flag_requested, flag_required, $state->{selected}, $state->{whatrequires}, $state->{rejected})
+sub disable_selected_and_unrequested_dependencies {
+    my ($urpm, $db, $state, @pkgs_todo) = @_;
+    my @all_unselected;
+
+    #- disable selected packages, then extend unselection to all required packages
+    #- no longer needed and not requested.
+    while (my @unselected = disable_selected($urpm, $db, $state, @pkgs_todo)) {
+	my %required;
+
+	#- keep in the packages that had to be unselected.
+	@all_unselected or push @all_unselected, @unselected;
+
+	if ($urpm->{keep_unrequested_dependencies}) {
+	    last;
+	}
+
+	#- search for unrequested required packages.
+	foreach (@unselected) {
+	    foreach ($_->requires_nosense) {
+		foreach my $pkg (grep { $_ } $urpm->packages_providing($_)) {
+		    $state->{selected}{$pkg->id} or next;
+		    $state->{selected}{$pkg->id}{psel} && $state->{selected}{$state->{selected}{$pkg->id}{psel}->id} and next;
+		    $pkg->flag_requested and next;
+		    $required{$pkg->id} = undef;
+		}
+	    }
+	}
+
+	#- check required packages are not needed by another selected package.
+	foreach (keys %required) {
+	    my $pkg = $urpm->{depslist}[$_] or next;
+	    foreach ($pkg->provides_nosense) {
+		foreach my $p_id (whatrequires_id($state, $_)) {
+		    exists $required{$p_id} and next;
+		    $state->{selected}{$p_id} and $required{$pkg->id} = 1;
+		}
+	    }
+	}
+
+	#- now required values still undefined indicates packages than can be removed.
+	@pkgs_todo = map { $urpm->{depslist}[$_] } grep { !$required{$_} } keys %required;
+    }
+
+    @all_unselected;
+}
+
+#- compute selected size by removing any removed or obsoleted package.
+#-
+#- side-effects: none
+sub selected_size {
+    my ($urpm, $state) = @_;
+    my ($size) = _selected_size_filesize($urpm, $state, 0);
+    $size;
+}
+#- side-effects: none
+sub selected_size_filesize {
+    my ($urpm, $state) = @_;
+    _selected_size_filesize($urpm, $state, 1);
+}
+#- side-effects: none
+sub _selected_size_filesize {
+    my ($urpm, $state, $compute_filesize) = @_;
+    my ($size, $filesize, $bad_filesize);
+
+    foreach (keys %{$state->{selected} || {}}) {
+	my $pkg = $urpm->{depslist}[$_];
+	$size += $pkg->size;
+	$compute_filesize or next;
+
+	if (my $n = $pkg->filesize) {
+	    $filesize += $n;
+	} elsif (!$bad_filesize) {
+	    $urpm->{debug} and $urpm->{debug}("no filesize for package " . $pkg->fullname);
+	    $bad_filesize = 1;
+	}
+    }
+
+    foreach (values %{$state->{rejected} || {}}) {
+	$_->{removed} || $_->{obsoleted} or next;
+	$size -= $_->{size};
+    }
+
+    foreach (@{$state->{orphans_to_remove} || []}) {
+	$size -= $_->size;
+    }
+
+    $size, $bad_filesize ? 0 : $filesize;
+}
+
+#- compute installed flags for all packages in depslist.
+#-
+#- side-effects: flag_upgrade, flag_installed
+sub compute_installed_flags {
+    my ($urpm, $db) = @_;
+
+    #- first pass to initialize flags installed and upgrade for all packages.
+    foreach (@{$urpm->{depslist}}) {
+	$_->is_arch_compat or next;
+	$_->flag_upgrade || $_->flag_installed or $_->set_flag_upgrade;
+    }
+
+    #- second pass to set installed flag and clean upgrade flag according to installed packages.
+    $db->traverse(sub {
+	my ($p) = @_;
+	#- compute flags.
+	foreach my $pkg ($urpm->packages_providing($p->name)) {
+	    next if !defined $pkg;
+	    $pkg->is_arch_compat && $pkg->name eq $p->name or next;
+	    #- compute only installed and upgrade flags.
+	    $pkg->set_flag_installed; #- there is at least one package installed (whatever its version).
+	    $pkg->flag_upgrade and $pkg->set_flag_upgrade($pkg->compare_pkg($p) > 0);
+	}
+    });
+}
+
+#- side-effects: flag_skip, flag_disable_obsolete
+sub compute_flag {
+    my ($urpm, $pkg, %options) = @_;
+    foreach (qw(skip disable_obsolete)) {
+	if ($options{$_} && !$pkg->flag($_)) {
+	    $pkg->set_flag($_, 1);
+	    $options{callback} and $options{callback}->($urpm, $pkg, %options);
+	}
+    }
+}
+
+#- Adds packages flags according to an array containing packages names.
+#- $val is an array reference (as returned by get_packages_list) containing
+#- package names, or a regular expression matching against the fullname, if
+#- enclosed in slashes.
+#- %options :
+#-   callback : sub to be called for each package where the flag is set
+#-   skip : if true, set the 'skip' flag
+#-   disable_obsolete : if true, set the 'disable_obsolete' flag
+#-
+#- side-effects: 
+#-   + those of compute_flag (flag_skip, flag_disable_obsolete)
+sub compute_flags {
+    my ($urpm, $val, %options) = @_;
+    if (ref $val eq 'HASH') { $val = [ keys %$val ] } #- compatibility with urpmi <= 4.5-13mdk
+    my @regex;
+
+    #- unless a regular expression is given, search in provides
+    foreach my $name (@$val) {
+	if ($name =~ m,^/(.*)/$,) {
+	    push @regex, $1;
+	} else {
+	    foreach my $pkg ($urpm->packages_providing($name)) {
+		compute_flag($urpm, $pkg, %options);
+	    }
+	}
+    }
+
+    #- now search packages which fullname match given regexps
+    if (@regex) {
+	#- very costly :-(
+	foreach my $pkg (@{$urpm->{depslist}}) {
+	    if (grep { $pkg->fullname =~ /$_/ } @regex) {
+		compute_flag($urpm, $pkg, %options);
+	    }
+	}
+    }
+}
+
+#- side-effects: none
+sub _choose_best_pkg {
+    my ($urpm, $pkg_installed, @pkgs) = @_;
+
+    _choose_best_pkg_($urpm, $pkg_installed, grep {
+	$_->compare_pkg($pkg_installed) > 0;
+    } @pkgs);
+}
+
+#- side-effects: none
+sub _choose_best_pkg_ {
+    my ($urpm, $pkg_installed, @pkgs) = @_;
+
+    my $best;
+    foreach my $pkg (grep {
+	!strict_arch($urpm) || strict_arch_check($pkg_installed, $_);
+    } @pkgs) {
+	if (!$best || ($pkg->compare_pkg($best) || $pkg->id < $best->id) > 0) {
+	    $best = $pkg;
+	}
+    }
+    $best;
+}
+
+#- side-effects: none
+sub _choose_bests_obsolete {
+    my ($urpm, $db, $pkg_installed, @pkgs) = @_;
+
+    _set_flag_installed_and_upgrade_if_no_newer($db, $_) foreach @pkgs;
+
+    my %by_name;
+    push @{$by_name{$_->name}}, $_ foreach grep { $_->flag_upgrade } @pkgs;
+
+    map { _choose_best_pkg_($urpm, $pkg_installed, @$_) } values %by_name;
+}
+
+#- select packages to upgrade, according to package already registered.
+#- by default, only takes best package and its obsoleted and compute
+#- all installed or upgrade flag.
+#- (used for --auto-select)
+#-
+#- side-effects: $requisted, flag_installed, flag_upgrade
+sub request_packages_to_upgrade {
+    my ($urpm, $db, $state, $requested, %options) = @_;
+
+    my %by_name;
+
+    #- now we can examine all existing packages to find packages to upgrade.
+    $db->traverse(sub {
+	my ($pkg_installed) = @_;
+	my $name = $pkg_installed->name;
+	my $pkg;
+	if (exists $by_name{$name}) {
+	    if (my $p = $by_name{$name}) {
+		#- here a pkg with the same name is installed twice
+		if ($p->compare_pkg($pkg_installed) > 0) {
+		    #- we selected $p, and it is still a valid choice
+		    $pkg = $p;
+		} else {
+		    #- $p is no good since $pkg_installed is higher version,
+		}
+	    }
+	} elsif ($pkg = _choose_best_pkg($urpm, $pkg_installed, $urpm->packages_by_name($name))) {
+	    #- first try with package using the same name.
+	    $pkg->set_flag_installed;
+	    $pkg->set_flag_upgrade;
+	}
+	if (my @pkgs = _choose_bests_obsolete($urpm, $db, $pkg_installed, _find_packages_obsoleting($urpm, $state, $pkg_installed))) {
+	    if (@pkgs == 1) {
+		$pkg and $urpm->{debug_URPM}("auto-select: prefering " . $pkgs[0]->fullname . " obsoleting " .  $pkg_installed->fullname . " over " . $pkg->fullname) if $urpm->{debug_URPM};
+		$pkg = $pkgs[0];
+	    } elsif (@pkgs > 1) {
+		$urpm->{debug_URPM}("auto-select: multiple packages (" . join(' ', map { scalar $_->fullname } @pkgs) . ") obsoleting " . $pkg_installed->fullname) if $urpm->{debug_URPM};
+		$pkg = undef;
+	    }
+	}
+	if ($pkg && $options{idlist} && !grep { $pkg->id == $_ } @{$options{idlist}}) {
+		$urpm->{debug_URPM}("not auto-selecting $pkg->fullname because it's not in search medias") if $urpm->{debug_URPM};
+		$pkg = undef;
+	} 
+
+	$pkg and $urpm->{debug_URPM}("auto-select: adding " . $pkg->fullname . " replacing " .  $pkg_installed->fullname) if $urpm->{debug_URPM};
+	    
+	$by_name{$name} = $pkg;		    
+    });
+
+    foreach my $pkg (values %by_name) {
+	$pkg or next;
+	$pkg->set_flag_upgrade;
+	$requested->{$pkg->id} = $options{requested};
+    }
+
+    $requested;
+}
+
+#- side-effects: none
+sub _sort_by_dependencies_get_graph {
+    my ($urpm, $state, $l) = @_;
+    my %edges;
+    foreach my $id (@$l) {
+	my $pkg = $urpm->{depslist}[$id];
+	my @provides = map { whatrequires_id($state, $_) } $pkg->provides_nosense;
+	if (my $from = $state->{selected}{$id}{from}) {
+	    unshift @provides, $from->id;
+	}
+	$edges{$id} = [ uniq(@provides) ];
+    }
+    \%edges;
+}
+
+#- side-effects: none
+sub reverse_multi_hash {
+    my ($h) = @_;
+    my %r;
+    my ($k, $v);
+    while (($k, $v) = each %$h) {
+	push @{$r{$_}}, $k foreach @$v;
+    }
+    \%r;
+}
+
+sub _merge_2_groups {
+    my ($groups, $l1, $l2) = @_;
+    my $l = [ @$l1, @$l2 ];
+    $groups->{$_} = $l foreach @$l;
+    $l;
+}
+sub _add_group {
+    my ($groups, $group) = @_;
+
+    my ($main, @other) = uniq(grep { $_ } map { $groups->{$_} } @$group);
+    $main ||= [];
+    if (@other) {
+	$main = _merge_2_groups($groups, $main, $_) foreach @other;
+    }
+    foreach (grep { !$groups->{$_} } @$group) {
+	$groups->{$_} ||= $main;
+	push @$main, $_;
+	my @l_ = uniq(@$main);
+	@l_ == @$main or die '';
+    }
+    # warn "# groups: ", join(' ', map { join('+', @$_) } uniq(values %$groups)), "\n";
+}
+
+#- nb: this handles $nodes list not containing all $nodes that can be seen in $edges
+#-
+#- side-effects: none
+sub sort_graph {
+    my ($nodes, $edges) = @_;
+
+    #require Data::Dumper;
+    #warn Data::Dumper::Dumper($nodes, $edges);
+
+    my %nodes_h = map { $_ => 1 } @$nodes;
+    my (%loops, %added, @sorted);
+
+    my $recurse; $recurse = sub {
+	my ($id, @ids) = @_;
+#	warn "# recurse $id @ids\n";
+
+	my $loop_ahead;
+	foreach my $p_id (@{$edges->{$id}}) {
+	    if ($p_id == $id) {
+		# don't care
+	    } elsif (exists $added{$p_id}) {
+		# already done
+	    } elsif (grep { $_ == $p_id } @ids) {
+		my $begin = 1;
+		my @l = grep { $begin &&= $_ != $p_id } @ids;
+		$loop_ahead = 1;
+		_add_group(\%loops, [ $p_id, $id, @l ]);
+	    } elsif ($loops{$p_id}) {
+		my $take;
+		if (my @l = grep { $take ||= $loops{$_} && $loops{$_} == $loops{$p_id} } reverse @ids) {
+		    $loop_ahead = 1;
+#		    warn "# loop to existing one $p_id, $id, @l\n";
+		    _add_group(\%loops, [ $p_id, $id, @l ]);
+		}
+	    } else {
+		$recurse->($p_id, $id, @ids);
+		#- we would need to compute loop_ahead. we will do it below only once, and if not already set
+	    }
+	}
+	if (!$loop_ahead && $loops{$id} && grep { exists $loops{$_} && $loops{$_} == $loops{$id} } @ids) {
+	    $loop_ahead = 1;
+	}
+
+	if (!$loop_ahead) {
+	    #- it's now a leaf or a loop we're done with
+	    my @toadd = $loops{$id} ? @{$loops{$id}} : $id;
+	    $added{$_} = undef foreach @toadd;
+#	    warn "# adding ", join('+', @toadd), " for $id\n";
+	    push @sorted, [ uniq(grep { $nodes_h{$_} } @toadd) ];
+	}
+    };
+    !exists $added{$_} and $recurse->($_) foreach @$nodes;
+
+#    warn "# result: ", join(' ', map { join('+', @$_) } @sorted), "\n";
+
+    check_graph_is_sorted(\@sorted, $nodes, $edges) or die "sort_graph failed";
+    
+    @sorted;
+}
+
+#- side-effects: none
+sub check_graph_is_sorted {
+    my ($sorted, $nodes, $edges) = @_;
+
+    my $i = 1;
+    my %nb;
+    foreach (@$sorted) {
+	$nb{$_} = $i foreach @$_;
+	$i++;
+    }
+    my $nb_errors = 0;
+    my $error = sub { $nb_errors++; warn "error: $_[0]\n" };
+
+    foreach my $id (@$nodes) {
+	$nb{$id} or $error->("missing $id in sort_graph list");
+    }
+    foreach my $id (keys %$edges) {
+	my $id_i = $nb{$id} or next;
+	foreach my $req (@{$edges->{$id}}) {
+	    my $req_i = $nb{$req} or next;
+	    $req_i <= $id_i or $error->("$req should be before $id ($req_i $id_i)");
+	}
+    }
+    $nb_errors == 0;
+}
+
+
+#- side-effects: none
+sub _sort_by_dependencies__add_obsolete_edges {
+    my ($urpm, $state, $l, $requires) = @_;
+
+    my @obsoletes = grep { $_->{obsoleted} } values %{$state->{rejected}} or return;
+    my @groups = grep { @$_ > 1 } map { [ keys %{$_->{closure}} ] } @obsoletes;
+    my %groups;
+    foreach my $group (@groups) {
+	_add_group(\%groups, $group);
+	foreach (@$group) {
+	    my $rej = $state->{rejected}{$_} or next;
+	    _add_group(\%groups, [ $_, keys %{$rej->{closure}} ]);
+	}
+    }
+
+    my %fullnames = map { scalar($urpm->{depslist}[$_]->fullname) => $_ } @$l;
+    foreach my $group (uniq(values %groups)) {
+	my @group = grep { defined $_ } map { $fullnames{$_} } @$group;
+	foreach (@group) {
+	    @{$requires->{$_}} = uniq(@{$requires->{$_}}, @group);
+	}
+    }
+}
+
+#- side-effects: none
+sub sort_by_dependencies {
+    my ($urpm, $state, @list_unsorted) = @_;
+    @list_unsorted = sort { $a <=> $b } @list_unsorted; # sort by ids to be more reproductable
+    $urpm->{debug_URPM}("getting graph of dependencies for sorting") if $urpm->{debug_URPM};
+    my $edges = _sort_by_dependencies_get_graph($urpm, $state, \@list_unsorted);
+    my $requires = reverse_multi_hash($edges);
+
+    _sort_by_dependencies__add_obsolete_edges($urpm, $state, \@list_unsorted, $requires);
+
+    $urpm->{debug_URPM}("sorting graph of dependencies") if $urpm->{debug_URPM};
+    sort_graph(\@list_unsorted, $requires);
+}
+
+sub sorted_rpms_to_string {
+    my ($urpm, @sorted) = @_;
+
+    "rpms sorted by dependencies:\n" . join("\n", map { 
+	join('+', _ids_to_names($urpm, @$_));
+    } @sorted);
+}
+
+#- build transaction set for given selection
+#- options: start, end, idlist, split_length, keep
+#-
+#- side-effects: $state->{transaction}, $state->{transaction_state}
+sub build_transaction_set {
+    my ($urpm, $db, $state, %options) = @_;
+
+    #- clean transaction set.
+    $state->{transaction} = [];
+
+    my %selected_id;
+    @selected_id{$urpm->build_listid($options{start}, $options{end}, $options{idlist})} = ();
+    
+    if ($options{split_length}) {
+	#- first step consists of sorting packages according to dependencies.
+	my @sorted = sort_by_dependencies($urpm, $state,
+	   keys(%selected_id) > 0 ? 
+	      (grep { exists($selected_id{$_}) } keys %{$state->{selected}}) : 
+	      keys %{$state->{selected}});
+	$urpm->{debug_URPM}(sorted_rpms_to_string($urpm, @sorted)) if $urpm->{debug_URPM};
+
+	#- second step consists of re-applying resolve_requested in the same
+	#- order computed in first step and to update a list of packages to
+	#- install, to upgrade and to remove.
+	my %examined;
+	my @todo = @sorted;
+	while (@todo) {
+	    my @ids;
+	    while (@todo && @ids < $options{split_length}) {
+		my $l = shift @todo;
+		push @ids, @$l;
+	    }
+	    my %requested = map { $_ => undef } @ids;
+
+		resolve_requested__no_suggests_($urpm,
+		    $db, $state->{transaction_state} ||= {},
+		    \%requested,
+		    defined $options{start} ? (start => $options{start}) : @{[]},
+		    defined $options{end}   ? (end   => $options{end}) : @{[]},
+		    keep => $options{keep},
+		);
+
+		my @upgrade = grep { ! exists $examined{$_} } keys %{$state->{transaction_state}{selected}};
+		my @remove = grep { ! exists $examined{$_} } packages_to_remove($state->{transaction_state});
+
+		@upgrade || @remove or next;
+
+		if (my @bad_remove = grep { !$state->{rejected}{$_}{removed} || $state->{rejected}{$_}{obsoleted} } @remove) {
+		    $urpm->{error}(sorted_rpms_to_string($urpm, @sorted)) if $urpm->{error};
+		    $urpm->{error}('transaction is too small: ' . join(' ', @bad_remove) . ' is rejected but it should not (current transaction: ' . join(' ', _ids_to_fullnames($urpm, @upgrade)) . ', requested: ' . join('+', _ids_to_fullnames($urpm, @ids)) . ')') if $urpm->{error};
+		    $state->{transaction} = [];
+		    last;
+		}
+
+		$urpm->{debug_URPM}(sprintf('transaction valid: remove=%s update=%s',
+					    join(',', @remove),
+					    join(',', _ids_to_names($urpm, @upgrade)))) if $urpm->{debug_URPM};
+    
+		$examined{$_} = undef foreach @upgrade, @remove;
+		push @{$state->{transaction}}, { upgrade => \@upgrade, remove => \@remove };
+	}
+
+	#- check that the transaction set has been correctly created.
+	#- (ie that no other package was removed)
+	if (keys(%{$state->{selected}}) == keys(%{$state->{transaction_state}{selected}}) &&
+	    listlength(packages_to_remove($state)) == listlength(packages_to_remove($state->{transaction_state}))
+	) {
+	    foreach (keys(%{$state->{selected}})) {
+		exists $state->{transaction_state}{selected}{$_} and next;
+		$urpm->{error}('using one big transaction') if $urpm->{error};
+		$state->{transaction} = []; last;
+	    }
+	    foreach (packages_to_remove($state)) {
+		$state->{transaction_state}{rejected}{$_}{removed} &&
+		  !$state->{transaction_state}{rejected}{$_}{obsoleted} and next;
+		$urpm->{error}('using one big transaction') if $urpm->{error};
+		$state->{transaction} = []; last;
+	    }
+	}
+    }
+
+    #- fallback if something can be selected but nothing has been allowed in transaction list.
+    if (%{$state->{selected} || {}} && !@{$state->{transaction}}) {
+	$urpm->{debug_URPM}('using one big transaction') if $urpm->{debug_URPM};
+	push @{$state->{transaction}}, {
+					upgrade => [ keys %{$state->{selected}} ],
+					remove  => [ packages_to_remove($state) ],
+				       };
+    }
+
+    if ($state->{orphans_to_remove}) {
+	my @l = map { scalar $_->fullname } @{$state->{orphans_to_remove}};
+	push @{$state->{transaction}}, { remove  => \@l };
+    }
+
+    $state->{transaction};
+}
+
+1;

Added: rpm/perl-URPM/trunk/URPM/Signature.pm
===================================================================
--- rpm/perl-URPM/trunk/URPM/Signature.pm	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM/Signature.pm	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,91 @@
+package URPM;
+
+use strict;
+use warnings;
+
+#- parse from rpmlib db.
+#-
+#- side-effects: $urpm
+sub parse_pubkeys {
+    my ($urpm, %options) = @_;
+
+    my $db = $options{db};
+    $db ||= URPM::DB::open($options{root}) or die "Can't open RPM DB, aborting\n";
+    my @keys = parse_pubkeys_($db);
+
+    $urpm->{keys}{$_->{id}} = $_ foreach @keys;
+}
+    
+#- side-effects: none
+sub parse_pubkeys_ {
+    my ($db) = @_;
+    
+    my ($block, $content);
+    my %keys;
+
+    $db->traverse_tag('name', [ 'gpg-pubkey' ], sub {
+	    my ($p) = @_;
+            # the first blank separates the PEM headers from key data, this
+            # flags we found it:
+            my $found_blank = 0;
+	    foreach (split "\n", $p->description) {
+		if ($block) {
+                    if (/^$/ and not $found_blank) {
+                        # All content until now were the encapsulated pem
+                        # headers...
+                        $content = '';
+                        $found_blank = 1;
+                    }
+                    elsif (/^-----END PGP PUBLIC KEY BLOCK-----$/) {
+                        $keys{$p->version} = {
+                            $p->summary =~ /^gpg\((.*)\)$/ ? (name => $1) : @{[]},
+                            id => $p->version,
+                            content => $content,
+                            block => $p->description,
+                        };
+                        $block = undef;
+                        $content = '';
+                    }
+                    else {
+                        $content .= $_;
+		    }
+		}
+		$block ||= /^-----BEGIN PGP PUBLIC KEY BLOCK-----$/;
+	    }
+	});
+
+    values %keys;
+}
+
+#- obsoleted
+sub import_needed_pubkeys {
+    warn "import_needed_pubkeys prototype has changed, please give a file directly\n";
+    return;
+}
+
+#- import pubkeys only if it is needed.
+sub import_needed_pubkeys_from_file {
+    my ($db, $pubkey_file, $o_callback) = @_;
+
+    my @keys = parse_pubkeys_($db);
+
+    my $keyid = substr get_gpg_fingerprint($pubkey_file), 8;
+    my ($kv) = grep { (hex($keyid) == hex($_->{id})) } @keys;
+    my $imported;
+    if (!$kv) {
+	    if (!import_pubkey_file($db, $pubkey_file)) {
+		#$urpm->{debug_URPM}("Couldn't import public key from ".$pubkey_file) if $urpm->{debug_URPM};
+		$imported = 0;
+	    } else {
+		$imported = 1;
+	    }
+	    @keys = parse_pubkeys_($db);
+	    ($kv) = grep { (hex($keyid) == hex($_->{id})) } @keys;
+    }
+
+    #- let the caller know about what has been found.
+    #- this is an error if the key is not found.
+    $o_callback and $o_callback->($kv?$kv->{id}:undef, $imported);
+}
+
+1;

Added: rpm/perl-URPM/trunk/URPM.pm
===================================================================
--- rpm/perl-URPM/trunk/URPM.pm	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM.pm	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,879 @@
+package URPM;
+
+use strict;
+use warnings;
+use DynaLoader;
+
+# different files, but same package
+# require them here to avoid dependencies
+use URPM::Build;
+use URPM::Resolve;
+use URPM::Signature;
+
+our @ISA = qw(DynaLoader);
+our $VERSION = '3.38';
+
+URPM->bootstrap($VERSION);
+
+sub new {
+    my ($class, %options) = @_;
+    my $self = bless {
+	depslist => [],
+	provides => {},
+	obsoletes => {},
+    }, $class;
+    $self->{nofatal} = 1 if $options{nofatal};
+    $self;
+}
+
+sub set_nofatal { $_[0]{nofatal} = $_[1] }
+
+sub packages_providing {
+    my ($urpm, $name) = @_;
+    grep { $_ } map { $urpm->{depslist}[$_] } keys %{$urpm->{provides}{$name} || {}};
+}
+
+sub packages_obsoleting {
+    my ($urpm, $name) = @_;
+    map { $urpm->{depslist}[$_] } keys %{$urpm->{obsoletes}{$name} || {}};
+}
+
+sub packages_by_name {
+    my ($urpm, $name) = @_;
+    grep { $name eq $_->name } packages_providing($urpm, $name);
+}
+
+sub search {
+    my ($urpm, $name, %options) = @_;
+    my $best;
+
+    #- tries other alternative if no strict searching.
+    unless ($options{strict_name}) {
+	if ($name =~ /^(.*)-([^\-]*)-([^\-]*)\.([^\.\-]*)$/) {
+	    foreach my $pkg (packages_providing($urpm, $1)) {
+		$pkg->fullname eq $name and return $pkg;
+	    }
+	}
+	unless ($options{strict_fullname}) {
+	    if ($name =~ /^(.*)-([^\-]*)-([^\-]*)$/) {
+		foreach my $pkg (packages_providing($urpm, $1)) {
+		    my ($n, $v, $r, $a) = $pkg->fullname;
+		    $options{src} && $a eq 'src' || $pkg->is_arch_compat or next;
+		    "$n-$v-$r" eq $name or next;
+		    !$best || $pkg->compare_pkg($best) > 0 and $best = $pkg;
+		}
+		$best and return $best;
+	    }
+	    if ($name =~ /^(.*)-([^\-]*)$/) {
+		foreach my $pkg (packages_providing($urpm, $1)) {
+		    my ($n, $v, undef, $a) = $pkg->fullname;
+		    $options{src} && $a eq 'src' || $pkg->is_arch_compat or next;
+		    "$n-$v" eq $name or next;
+		    !$best || $pkg->compare_pkg($best) > 0 and $best = $pkg;
+		}
+		$best and return $best;
+	    }
+	}
+    }
+
+    unless ($options{strict_fullname}) {
+	foreach my $pkg (packages_providing($urpm, $name)) {
+	    my ($n, undef, undef, $a) = $pkg->fullname;
+	    $options{src} && $a eq 'src' || $pkg->is_arch_compat or next;
+	    $n eq $name or next;
+	    !$best || $pkg->compare_pkg($best) > 0 and $best = $pkg;
+	}
+    }
+
+    return $best;
+}
+
+#- Olivier Thauvin:
+#- Returns @$listid, $start .. $end or the whole deplist id
+#- according to the given args
+sub build_listid {
+    my ($urpm, $start, $end, $listid) = @_;
+
+    @{$listid || []} > 0 ? @$listid :
+        (($start || 0) .. (defined($end) ? $end : $#{$urpm->{depslist}}));
+}
+
+#- this is used when faking a URPM::DB: $urpm can be used as-a $db
+#- (used for urpmi --env)
+sub traverse {
+    my ($urpm, $callback) = @_;
+
+    if ($callback) {
+	foreach my $p (@{$urpm->{depslist} || []}) {
+	    $callback->($p);
+	}
+    }
+
+    scalar @{$urpm->{depslist} || []};
+}
+
+
+#- this is used when faking a URPM::DB: $urpm can be used as-a $db
+#- (used for urpmi --env)
+sub traverse_tag {
+    my ($urpm, $tag, $names, $callback) = @_;
+    my $count = 0; 
+    my %names;
+
+    if (@{$names || []}) {
+	if ($tag eq 'name') {
+	    foreach my $n (@$names) {
+		foreach my $p (packages_providing($urpm, $n)) {
+		    $p->name eq $n or next;
+		    $callback and $callback->($p);
+		    ++$count;
+		}
+	    }
+	} elsif ($tag eq 'whatprovides') {
+	    foreach (@$names) {
+		foreach (keys %{$urpm->{provides}{$_} || {}}) {
+		    $callback and $callback->($urpm->{depslist}[$_]);
+		    ++$count;
+		}
+	    }
+	} else {
+	    @names{@$names} = ();
+	    if ($tag eq 'whatrequires') {
+		foreach (@{$urpm->{depslist} || []}) {
+		    if (grep { exists $names{$_} } $_->requires_nosense) {
+			$callback and $callback->($_);
+			++$count;
+		    }
+		}
+	    } elsif ($tag eq 'whatconflicts') {
+		foreach (@{$urpm->{depslist} || []}) {
+		    if (grep { exists $names{$_} } $_->conflicts_nosense) {
+			$callback and $callback->($_);
+			++$count;
+		    }
+		}
+	    } elsif ($tag eq 'group') {
+		foreach (@{$urpm->{depslist} || []}) {
+		    if (exists $names{$_->group}) {
+			$callback and $callback->($_);
+			++$count;
+		    }
+		}
+	    } elsif ($tag eq 'triggeredby' || $tag eq 'path') {
+		foreach (@{$urpm->{depslist} || []}) {
+		    if (grep { exists $names{$_} } $_->files, grep { m!^/! } $_->provides_nosense) {
+			$callback and $callback->($_);
+			++$count;
+		    }
+		}
+	    } else {
+		die "unknown tag";
+	    }
+	}
+    }
+
+    $count;
+}
+
+# wrapper around XS functions
+# it handles error cases
+sub _parse_hdlist_or_synthesis {
+    my ($parse_func, $urpm, $file, %options) = @_;
+
+    my $previous_indice = @{$urpm->{depslist}};
+    if (my ($start, $end) = $parse_func->($urpm, $file, %options)) {
+	($start, $end);
+    } elsif (!$options{callback}) {
+	#- parse_hdlist__XS may have added some pkgs to {depslist},
+	#- but we don't want those pkgs since reading hdlist failed later.
+	#- so we need to drop them
+	#- FIXME: {provides} would need to be reverted too!
+	splice(@{$urpm->{depslist}}, $previous_indice);
+	();
+    } else {
+	#- we need to keep them since the callback has been used
+	#- and we can't pretend we didn't parse anything
+	#- (needed for genhdlist2)
+	();
+    }
+}
+sub parse_synthesis { _parse_hdlist_or_synthesis(\&parse_synthesis__XS, @_) }
+sub parse_hdlist { _parse_hdlist_or_synthesis(\&parse_hdlist__XS, @_) }
+
+sub add_macro {
+    my ($s) = @_;
+    #- quote for rpmlib, *sigh*
+    $s =~ s/\n/\\\n/g;
+    add_macro_noexpand($s);
+}
+
+package URPM::Package;
+our @ISA = qw(); # help perl_checker
+
+#- debug help for urpmi
+sub dump_flags {
+    my ($pkg) = @_;
+    <<EODUMP;
+available:	  ${\($pkg->flag_available)}
+base:		  ${\($pkg->flag_base)}
+disable_obsolete: ${\($pkg->flag_disable_obsolete)}
+installed:	  ${\($pkg->flag_installed)}
+requested:	  ${\($pkg->flag_requested)}
+required:	  ${\($pkg->flag_required)}
+selected:	  ${\($pkg->flag_selected)}
+skip:		  ${\($pkg->flag_skip)}
+upgrade:	  ${\($pkg->flag_upgrade)}
+EODUMP
+}
+
+my %arch_cache;
+sub is_arch_compat {
+    my ($pkg) = @_;
+    my $arch = $pkg->arch;
+    exists $arch_cache{$arch} and return $arch_cache{$arch};
+
+    $arch_cache{$arch} = is_arch_compat__XS($pkg);
+}
+
+sub changelogs {
+    my ($pkg) = @_;
+
+    my @ti = $pkg->changelog_time or return;
+    my @na = $pkg->changelog_name or return;
+    my @tx = $pkg->changelog_text or return;
+    map {
+	{ time => $ti[$_], name => $na[$_], text => $tx[$_] };
+    } 0 .. $#ti;
+}
+
+package URPM::Transaction;
+our @ISA = qw(); # help perl_checker
+
+package URPM::DB;
+our @ISA = qw(); # help perl_checker
+
+1;
+
+__END__
+
+=head1 NAME
+
+URPM - Manipulate RPM files and headers
+
+=head1 SYNOPSIS
+
+    use URPM;
+
+    # using the local RPM database
+    my $db = URPM::DB::open();
+    $db->traverse(sub {
+	my ($package) = @_; # this is a URPM::Package object
+	print $package->name, "\n";
+	# ...
+    });
+
+    # loading and parsing a synthesis file
+    my $urpm = new URPM;
+    $urpm->parse_synthesis("synthesis.sample.cz");
+    $urpm->traverse(sub {
+	# retrieve all packages from the dependency list
+	# ...
+    });
+
+=head1 DESCRIPTION
+
+The URPM module allows you to manipulate RPM files, RPM header files and
+hdlist files and manage them in memory. It is notably used by the C<urpmi>
+utility. It provides four classes : C<URPM>, C<URPM::DB>, C<URPM::Package>,
+and C<URPM::Transaction>.
+
+=head2 The URPM class
+
+=over 4
+
+=item URPM->new()
+
+The constructor creates a new, empty URPM object. It's a blessed hash that
+contains two fields:
+
+B<depslist> is an arrayref containing the list of depending packages (which are
+C<URPM::Package> objects).
+
+B<provides> is an hashref containing as keys the list of property names
+provided by the URPM object. The associated value is true if the property is
+versioned.
+
+If the constructor is called with the arguments C<< nofatal => 1 >>, various
+fatal error messages are suppressed (file not found in parse_hdlist() and
+parse_synthesis()).
+
+=item URPM::read_config_files()
+
+Force the re-reading of the RPM configuration files.
+
+=item URPM::ranges_overlap($range1, $range2 [, $nopromoteepoch])
+
+This utility function compares two version ranges, in order to calculate
+dependencies properly. The ranges have roughly the form
+
+    [<|<=|==|=>|>] [epoch:]version[-release]
+
+where epoch, version and release are RPM-style version numbers.
+
+If the optional parameter $nopromoteepoch is true, and if the 2nd range has no
+epoch while the first one has one, then the 2nd range is assumed to have an
+epoch C<== 0>.
+
+B<Warning>: $nopromoteepoch actually defaults to 1, so if you're going to
+pass a variable, make sure undef is treated like 1, not 0.
+
+=item $urpm->parse_synthesis($file [, callback => sub {...} ])
+
+This method gets the B<depslist> and the B<provides> from a synthesis file
+and adds them to the URPM object.
+
+=item $urpm->parse_hdlist($file, %options)
+
+This method loads rpm informations from rpm headers contained in an hdlist
+file and adds them to the URPM object. Allowed options are 
+
+    packing => 0 / 1
+    callback => sub { ... }
+    keep_all_tags => 0 / 1
+
+The return value is a two-element array containing the first and the last id
+parsed.
+
+=item $urpm->parse_rpm($file, %options)
+
+This method gets the B<depslist> and the B<provides> from an RPM file
+and adds them to the URPM object. Allowed options are
+
+    packing => 0 / 1
+    keep_all_tags => 0 / 1
+    callback => sub { ... }
+
+If C<keep_all_tags> isn't specified, URPM will drop all memory-consuming tags
+(notably changelogs, filelists, scriptlets).
+
+=item $urpm->packages_providing($name)
+
+Returns a list of C<URPM::Package> providing <$name>
+
+=item $urpm->packages_by_name($name)
+
+Returns a list of C<URPM::Package> corresponding to the wanted <$name>
+
+=item $urpm->search($name, %options)
+
+Search an RPM by name or by part of name in the list of RPMs represented by
+this $urpm. The behaviour of the search is influenced by several options:
+
+    strict_name => 0 / 1
+    strict_fullname => 0 / 1
+    src => 0 / 1
+
+=item $urpm->traverse($callback)
+
+Executes the callback for each package in the depslist, passing a
+C<URPM::Package> object as argument the callback.
+
+This is used when faking a URPM::DB: $urpm can be used as-a $db
+
+=item $urpm->traverse_tag($tag, $names, $callback)
+
+$tag may be one of C<name>, C<whatprovides>, C<whatrequires>, C<whatconflicts>,
+C<group>, C<triggeredby>, or C<path>.
+$names is a reference to an array, holding the acceptable values of the said
+tag for the searched variables.
+Then, $callback is called for each matching package in the depslist.
+
+This is used when faking a URPM::DB: $urpm can be used as-a $db
+
+=item URPM::verify_rpm($file, %options)
+
+Verifies an RPM file.
+Returns 0 on failure, 1 on success.
+Recognized options are:
+
+    nodigests => 0 / 1
+    nosignatures => 0 / 1
+
+=item URPM::verify_signature($file)
+
+Verifies the signature of an RPM file. Returns a string that will contain "OK"
+or "NOT OK" as well as a description of the found key (if successful) or of the
+error (if signature verification failed.)
+
+=item $urpm->import_pubkey(%options)
+
+Imports a key in the RPM database.
+
+    db => $urpm_db
+    root => '...'
+    block => '...'
+    filename => '...'
+
+=item URPM::spec2srcheader($specfile)
+
+Returns a URPM::Package object containing the header of the source rpm produced
+by the evaluation of the specfile whose path is given as argument. All
+dependencies stored in this header are exactly the one needed to build the
+specfile.
+
+=back
+
+=head2 The URPM::DB class
+
+=over 4
+
+=item open($prefix, $write_perm)
+
+Returns a new C<URPM::DB> object pointing on the local RPM database (or
+C<undef> on failure).
+
+$prefix defaults to C<""> and indicates the RPM DB root directory prefix if
+any. (See the B<--root> option to rpm(1)).
+
+$write_perm is a boolean that defaults to false, and that indicates whether
+the RPM DB should be open in read/write mode.
+
+=item rebuild($prefix)
+
+Rebuilds the RPM database (like C<rpm --rebuilddb>). $prefix defaults to C<"">.
+
+=item $db->traverse($callback)
+
+Executes the specified callback (a code reference) for each package
+in the DB, passing a C<URPM::Package> object as argument the callback.
+
+=item $db->traverse_tag($tag,$names,$callback)
+
+$tag may be one of C<name>, C<whatprovides>, C<whatrequires>, C<whatconflicts>,
+C<group>, C<triggeredby>, or C<path>.
+$names is a reference to an array, holding the acceptable values of the said
+tag for the searched variables.
+Then, $callback is called for each matching package in the DB.
+
+=item $db->traverse_tag_find($tag,$name,$callback)
+
+Quite similar to C<traverse_tag>, but stops when $callback returns true.
+
+(also note that only one $name is handled)
+
+=item $db->create_transaction($prefix)
+
+Creates and returns a new transaction (an C<URPM::Transaction> object) on the
+specified DB. For $prefix, cf L<open>.
+
+=back
+
+=head2 The URPM::Package class
+
+Most methods of C<URPM::Package> are accessors for the various properties
+of an RPM package.
+
+=over 4
+
+=item $package->arch()
+
+Gives the package architecture
+
+=item $package->build_header($fileno)
+
+Writes the rpm header to the specified file ($fileno being an integer).
+
+=item $package->build_info($fileno, [$provides_files])
+
+Writes a line of information in a synthesis file.
+
+=item $package->buildarchs()
+
+=item $package->buildhost()
+
+=item $package->buildtime()
+
+=item $package->changelog_name()
+
+=item $package->changelog_text()
+
+=item $package->changelog_time()
+
+=item $package->compare($evr)
+
+=item $package->compare_pkg($other_pkg)
+
+=item $package->conf_files()
+
+=item $package->conflicts()
+
+=item $package->conflicts_nosense()
+
+=item $package->description()
+
+=item $package->dirnames()
+
+=item $package->distribution()
+
+=item $package->epoch()
+
+=item $package->excludearchs()
+
+=item $package->exclusivearchs()
+
+=item $package->filelinktos()
+
+=item $package->files()
+
+List of files in this rpm.
+
+=item $package->files_flags()
+
+=item $package->files_gid()
+
+=item $package->files_group()
+
+=item $package->files_md5sum()
+
+=item $package->files_mode()
+
+=item $package->files_mtime()
+
+=item $package->files_owner()
+
+=item $package->files_size()
+
+=item $package->files_uid()
+
+=item $package->flag($name)
+
+=item $package->flag_available()
+
+=item $package->flag_base()
+
+=item $package->flag_disable_obsolete()
+
+=item $package->flag_installed()
+
+=item $package->flag_requested()
+
+=item $package->flag_required()
+
+=item $package->flag_selected()
+
+=item $package->flag_skip()
+
+=item $package->flag_upgrade()
+
+=item $package->free_header()
+
+=item $package->fullname()
+
+Returns a 4 element list: name, version, release and architecture in an array
+context. Returns a string NAME-VERSION-RELEASE.ARCH in scalar context.
+
+=item $package->get_tag($tagid)
+
+Returns an array containing values of $tagid. $tagid is the numerical value of
+rpm tags. See rpmlib.h. 
+
+=item $package->queryformat($format)
+
+Querying the package like rpm --queryformat do. 
+
+The function calls directly the rpmlib, then use header informations, so it 
+silently failed if you use synthesis instead of hdlist/rpm/header files or rpmdb.
+
+=item $package->get_tag_modifiers($tagid)
+
+Return an array of human readable view of tag values. $tagid is the numerical value of rpm tags.
+
+=item $package->group()
+
+=item $package->id()
+
+=item $package->installtid()
+
+=item $package->is_arch_compat()
+
+Returns whether this package is compatible with the current machine's
+architecture. 0 means not compatible. The lower the result is, the preferred
+the package is.
+
+=item $package->is_platform_compat()
+
+Return whether this package is compatible with the current machine's
+platform configuration (/etc/rpm/platform). 0 mean not compatible.
+The lower the result is the preferred the package is.
+
+=item $package->license()
+
+=item $package->name()
+
+The rpm's bare name.
+
+=item $package->obsoletes()
+
+=item $package->obsoletes_nosense()
+
+=item $package->obsoletes_overlap($s, [$nopromoteepoch, [$direction] ])
+
+=item $package->os()
+
+=item $package->pack_header()
+
+=item $package->packager()
+
+=item $package->payload_format()
+
+=item $package->provides()
+
+=item $package->provides_nosense()
+
+=item $package->provides_overlap($s, [$nopromoteepoch,] [$direction])
+
+=item $package->rate()
+
+=item $package->release()
+
+=item $package->requires()
+
+=item $package->requires_nosense()
+
+=item $package->rflags()
+
+=item $package->filesize()
+
+Size of the rpm file (ie the rpm header + cpio body)
+
+=item $package->set_flag($name, $value)
+
+=item $package->set_flag_base($value)
+
+=item $package->set_flag_disable_obsolete($value)
+
+=item $package->set_flag_installed($value)
+
+=item $package->set_flag_requested($value)
+
+=item $package->set_flag_required($value)
+
+=item $package->set_flag_skip($value)
+
+=item $package->set_flag_upgrade($value)
+
+=item $package->set_id($id)
+
+=item $package->set_rate($rate)
+
+=item $package->set_rflags(...)
+
+=item $package->size()
+
+=item $package->sourcerpm()
+
+=item $package->summary()
+
+=item $package->update_header($filename, ...)
+
+=item $package->url()
+
+=item $package->vendor()
+
+=item $package->version()
+
+=back
+
+=head2 The URPM::Transaction class
+
+=over 4
+
+=item $trans->set_script_fd($fileno)
+
+Sets the transaction output filehandle.
+
+=item $trans->add($pkg, %options)
+
+Adds a package to be installed to the transaction represented by $trans.
+$pkg is an C<URPM::Package> object.
+
+Options are:
+
+    update => 0 / 1 : indicates whether this is an upgrade
+    excludepath => [ ... ]
+
+=item $trans->remove($name)
+
+Adds a package to be erased to the transaction represented by $trans.
+$name is the name of the package.
+
+=item $trans->check(%options)
+
+Checks that all dependencies can be resolved in this transaction.
+
+Options are:
+
+    translate_message => 0 / 1 (currently ignored.)
+
+In list context, returns an array of problems (an empty array indicates
+success).
+
+=item $trans->order()
+
+Determines package order in a transaction set according to dependencies. In
+list context, returns an array of problems (an empty array indicates success).
+
+=item $trans->run($data, %options)
+
+Runs the transaction.
+
+$data is an arbitrary user-provided piece of data to be passed to callbacks.
+
+Recognized options are:
+
+    callback_close  => sub { ... }
+    callback_inst   => sub { ... }
+    callback_open   => sub { ... }
+    callback_trans  => sub { ... }
+    callback_uninst => sub { ... }
+    delta => used for progress callbacks (trans, uninst, inst)
+    excludedocs => 0 / 1
+    force => 0 / 1
+    ignorearch => 0 / 1
+    nosize => 0 / 1
+    noscripts => 0 / 1
+    oldpackage => 0 / 1
+    repackage => 0 / 1
+    test => 0 / 1
+    translate_message => 1
+
+They roughly correspond to command-line options to rpm(1).
+
+=item $trans->traverse($callback)
+
+Executes the specified callback (a code reference) for each package in the
+transaction, passing a C<URPM::Package> object as argument the callback.
+
+=back
+
+=head2 Macro handling functions
+
+=over
+
+=item loadmacrosfile($filename)
+
+Load the specified macro file. Sets $! if the file can't be read.
+
+=item expand($name)
+
+Expands the specified macro.
+
+=item add_macro($macro_definition)
+
+=item add_macro_noexpand($macro_definition)
+
+Define a macro. For example,
+
+    URPM::add_macro("vendor Mageia");
+    my $vendor = URPM::expand("%vendor");
+
+The 'noexpand' version doesn't expand literal newline characters in the
+macro definition.
+
+=item del_macro($name)
+
+Delete a macro.
+
+=item resetmacros()
+
+Destroys macros.
+
+=item setVerbosity($level)
+
+Sets rpm verbosity level. $level is an integer between 2 (RPMMESS_CRIT) and 7
+(RPMMESS_DEBUG).
+
+=item rpmErrorString()
+
+=item rpmErrorWriteTo($fd)
+
+=item platformscore($platform)
+
+Return the score of $platform according computer's configuration.
+0 mean not compatible, lower is prefered.
+
+=item archscore($arch)
+
+Return the score of the given arch. 0 mean not compatible,
+lower is prefered.
+
+=item osscore($os)
+
+Return the score of the given os. 0 mean not compatible,
+lower is prefered.
+
+=back
+
+=head2 The $state object
+
+It has the following fields:
+
+B<backtrack>: { 
+   selected => { id => undef }, 
+   deadlock => { id|property => undef },
+ }
+
+B<cached_installed>: { property_name => { fullname => undef } }
+
+B<oldpackage>: int
+   # will be passed to $trans->run to set RPMPROB_FILTER_OLDPACKAGE
+
+B<selected>: { id => { 
+     requested => bool, install => bool,
+     from => pkg, psel => pkg,
+     promote => name, unsatisfied => [ id|property ]
+ } }
+
+B<rejected>: { fullname => { 
+     size => int, removed => { fullname|"asked" => undef },
+     obsoleted => { fullname|"asked" => undef },
+     backtrack => { # those info are only used to display why package is unselected
+         promote => [ name ], keep => [ fullname ], 
+         unsatisfied => [ id|property ], 
+         conflicts => [ fullname ],
+     },
+     closure => { fullname => { old_requested => bool, 
+                                unsatisfied => [ id|property ],
+                                conflicts => property },
+                                avoid => bool },
+     },
+ } }
+
+B<rejected_already_installed>: { id => pkg }
+
+B<orphans_to_remove>: [ pkg ]
+
+B<whatrequires>: { name => { id => undef } }
+   # reversed requires_nosense for selected packages
+
+B<unselected_uninstalled>: [ pkg ]
+   # (old) packages which are needed, but installed package is newer
+
+more fields only used in build_transaction_set and its callers):
+
+B<transaction>: [ { upgrade => [ id ], remove => [ fullname ] } ]
+
+B<transaction_state>: $state object
+
+=head1 COPYRIGHT
+
+Copyright 2002, 2003, 2004, 2005 MandrakeSoft SA
+
+Copyright 2005, 2006, 2007, 2008 Mandriva SA
+
+FranE<ccedil>ois Pons (original author), Rafael Garcia-Suarez, Pixel <pixel at mandriva.com> (current maintainer)
+
+This library is free software; you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut

Added: rpm/perl-URPM/trunk/URPM.xs
===================================================================
--- rpm/perl-URPM/trunk/URPM.xs	                        (rev 0)
+++ rpm/perl-URPM/trunk/URPM.xs	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,3995 @@
+/* Copyright (c) 2002, 2003, 2004, 2005 MandrakeSoft SA
+ * Copyright (c) 2005, 2006, 2007, 2008 Mandriva SA
+ *
+ * All rights reserved.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ *
+ * $Id: URPM.xs 259125 2009-08-10 14:37:07Z cfergeau $
+ * 
+ */
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <sys/utsname.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+#include <libintl.h>
+
+#undef Fflush
+#undef Mkdir
+#undef Stat
+#undef Fstat
+
+#ifdef RPM_ORG
+static inline void *_free(const void * p) { 
+  if (p != NULL) free((void *)p); 
+  return NULL;
+}
+typedef struct rpmSpec_s * Spec;
+#else
+#include <rpm/rpm46compat.h>
+#endif
+
+#include <rpm/rpmio.h>
+#include <rpm/rpmdb.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmte.h>
+#include <rpm/rpmps.h>
+#include <rpm/rpmpgp.h>
+#include <rpm/rpmcli.h>
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmlog.h>
+
+struct s_Package {
+  char *info;
+  int  filesize;
+  char *requires;
+  char *suggests;
+  char *obsoletes;
+  char *conflicts;
+  char *provides;
+  char *rflags;
+  char *summary;
+  unsigned flag;
+  Header h;
+};
+
+struct s_Transaction {
+  rpmts ts;
+  int count;
+};
+
+struct s_TransactionData {
+  SV* callback_open;
+  SV* callback_close;
+  SV* callback_trans;
+  SV* callback_uninst;
+  SV* callback_inst;
+  long min_delta;
+  SV *data; /* chain with another data user provided */
+};
+
+typedef struct s_Transaction* URPM__DB;
+typedef struct s_Transaction* URPM__Transaction;
+typedef struct s_Package* URPM__Package;
+
+#define FLAG_ID               0x001fffffU
+#define FLAG_RATE             0x00e00000U
+#define FLAG_BASE             0x01000000U
+#define FLAG_SKIP             0x02000000U
+#define FLAG_DISABLE_OBSOLETE 0x04000000U
+#define FLAG_INSTALLED        0x08000000U
+#define FLAG_REQUESTED        0x10000000U
+#define FLAG_REQUIRED         0x20000000U
+#define FLAG_UPGRADE          0x40000000U
+#define FLAG_NO_HEADER_FREE   0x80000000U
+
+#define FLAG_ID_MAX           0x001ffffe
+#define FLAG_ID_INVALID       0x001fffff
+
+#define FLAG_RATE_POS         21
+#define FLAG_RATE_MAX         5
+#define FLAG_RATE_INVALID     0
+
+
+#define FILENAME_TAG 1000000
+#define FILESIZE_TAG 1000001
+
+#define FILTER_MODE_ALL_FILES     0
+#define FILTER_MODE_CONF_FILES    2
+
+/* promote epoch sense should be :
+     0 for compability with old packages
+     1 for rpm 4.2 and better new approach. */
+#define PROMOTE_EPOCH_SENSE       1
+
+static ssize_t write_nocheck(int fd, const void *buf, size_t count) {
+  return write(fd, buf, count);
+}
+static const void* unused_variable(const void *p) {
+  return p;
+}
+
+static int rpmError_callback_data;
+
+int rpmError_callback() {
+  write_nocheck(rpmError_callback_data, rpmlogMessage(), strlen(rpmlogMessage()));
+  return RPMLOG_DEFAULT;
+}
+
+static int rpm_codeset_is_utf8 = 0;
+
+static SV*
+newSVpv_utf8(const char *s, STRLEN len)
+{
+  SV *sv = newSVpv(s, len);
+  SvUTF8_on(sv);
+  return sv;
+}
+
+static void
+get_fullname_parts(URPM__Package pkg, char **name, char **version, char **release, char **arch, char **eos) {
+  char *_version = NULL, *_release = NULL, *_arch = NULL, *_eos = NULL;
+
+  if ((_eos = strchr(pkg->info, '@')) != NULL) {
+    *_eos = 0; /* mark end of string to enable searching backwards */
+    if ((_arch = strrchr(pkg->info, '.')) != NULL) {
+      *_arch = 0;
+      if ((release != NULL || version != NULL || name != NULL) && (_release = strrchr(pkg->info, '-')) != NULL) {
+	*_release = 0;
+	if ((version != NULL || name != NULL) && (_version = strrchr(pkg->info, '-')) != NULL) {
+	  if (name != NULL) *name = pkg->info;
+	  if (version != NULL) *version = _version + 1;
+	}
+	if (release != NULL) *release = _release + 1;
+	*_release = '-';
+      }
+      if (arch != NULL) *arch = _arch + 1;
+      *_arch = '.';
+    }
+    if (eos != NULL) *eos = _eos;
+    *_eos = '@';
+  }
+}
+
+static char *
+get_name(Header header, int32_t tag) {
+  struct rpmtd_s val;
+
+  headerGet(header, tag, &val, HEADERGET_MINMEM);
+  char *name = (char *) rpmtdGetString(&val);
+  return name ? name : "";
+}
+
+static int
+get_int(Header header, int32_t tag) {
+  struct rpmtd_s val;
+
+  headerGet(header, tag, &val, HEADERGET_DEFAULT);
+  uint32_t *ep = rpmtdGetUint32(&val);
+  return ep ? *ep : 0;
+}
+
+static int
+sigsize_to_filesize(int sigsize) {
+  return sigsize + 440; /* 440 is the rpm header size (?) empirical, but works */
+}
+
+static int
+print_list_entry(char *buff, int sz, const char *name, uint32_t flags, const char *evr) {
+  int len = strlen(name);
+  char *p = buff;
+
+  if (len >= sz || !strncmp(name, "rpmlib(", 7)) return -1;
+  memcpy(p, name, len); p += len;
+
+  if (flags & (RPMSENSE_PREREQ|RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POSTUN|RPMSENSE_SCRIPT_POST)) {
+    if (p - buff + 3 >= sz) return -1;
+    memcpy(p, "[*]", 4); p += 3;
+  }
+  if (evr != NULL) {
+    len = strlen(evr);
+    if (len > 0) {
+      if (p - buff + 6 + len >= sz) return -1;
+      *p++ = '[';
+      if (flags & RPMSENSE_LESS) *p++ = '<';
+      if (flags & RPMSENSE_GREATER) *p++ = '>';
+      if (flags & RPMSENSE_EQUAL) *p++ = '=';
+      if ((flags & (RPMSENSE_LESS|RPMSENSE_EQUAL|RPMSENSE_GREATER)) == RPMSENSE_EQUAL) *p++ = '=';
+      *p++ = ' ';
+      memcpy(p, evr, len); p+= len;
+      *p++ = ']';
+    }
+  }
+  *p = 0; /* make sure to mark null char, Is it really necessary ? */
+
+  return p - buff;
+}
+
+static int
+ranges_overlap(uint32_t aflags, char *sa, uint32_t bflags, char *sb, int b_nopromote) {
+  if (!aflags || !bflags)
+    return 1; /* really faster to test it there instead of later */
+  else {
+    int sense = 0;
+    char *eosa = strchr(sa, ']');
+    char *eosb = strchr(sb, ']');
+    char *ea, *va, *ra, *eb, *vb, *rb;
+
+    if (eosa) *eosa = 0;
+    if (eosb) *eosb = 0;
+    /* parse sa as an [epoch:]version[-release] */
+    for (ea = sa; *sa >= '0' && *sa <= '9'; ++sa);
+    if (*sa == ':') {
+      *sa++ = 0; /* ea could be an empty string (should be interpreted as 0) */
+      va = sa;
+    } else {
+      va = ea; /* no epoch */
+      ea = NULL;
+    }
+    if ((ra = strrchr(sa, '-'))) *ra++ = 0;
+    /* parse sb as an [epoch:]version[-release] */
+    for (eb = sb; *sb >= '0' && *sb <= '9'; ++sb);
+    if (*sb == ':') {
+      *sb++ = 0; /* ea could be an empty string (should be interpreted as 0) */
+      vb = sb;
+    } else {
+      vb = eb; /* no epoch */
+      eb = NULL;
+    }
+    if ((rb = strrchr(sb, '-'))) *rb++ = 0;
+    /* now compare epoch */
+    if (ea && eb)
+      sense = rpmvercmp(*ea ? ea : "0", *eb ? eb : "0");
+    else if (ea && *ea && atol(ea) > 0)
+      sense = b_nopromote ? 1 : 0;
+    else if (eb && *eb && atol(eb) > 0)
+      sense = -1;
+    /* now compare version and release if epoch has not been enough */
+    if (sense == 0) {
+      sense = rpmvercmp(va, vb);
+      if (sense == 0 && ra && *ra && rb && *rb)
+	sense = rpmvercmp(ra, rb);
+    }
+    /* restore all character that have been modified inline */
+    if (rb) rb[-1] = '-';
+    if (ra) ra[-1] = '-';
+    if (eb) vb[-1] = ':';
+    if (ea) va[-1] = ':';
+    if (eosb) *eosb = ']';
+    if (eosa) *eosa = ']';
+    /* finish the overlap computation */
+    if (sense < 0 && ((aflags & RPMSENSE_GREATER) || (bflags & RPMSENSE_LESS)))
+      return 1;
+    else if (sense > 0 && ((aflags & RPMSENSE_LESS) || (bflags & RPMSENSE_GREATER)))
+      return 1;
+    else if (sense == 0 && (((aflags & RPMSENSE_EQUAL) && (bflags & RPMSENSE_EQUAL)) ||
+			    ((aflags & RPMSENSE_LESS) && (bflags & RPMSENSE_LESS)) ||
+			    ((aflags & RPMSENSE_GREATER) && (bflags & RPMSENSE_GREATER))))
+      return 1;
+    else
+      return 0;
+  }
+}
+
+static int has_old_suggests;
+int32_t is_old_suggests(int32_t flags) { 
+  int is = flags & RPMSENSE_MISSINGOK;
+  if (is) has_old_suggests = is;
+  return is;
+}
+int32_t is_not_old_suggests(int32_t flags) {
+  return !is_old_suggests(flags);
+}
+
+typedef int (*callback_list_str)(char *s, int slen, const char *name, const uint32_t flags, const char *evr, void *param);
+
+static int
+callback_list_str_xpush(char *s, int slen, const char *name, uint32_t flags, const char *evr, __attribute__((unused)) void *param) {
+  dSP;
+  if (s) {
+    XPUSHs(sv_2mortal(newSVpv(s, slen)));
+  } else {
+    char buff[4096];
+    int len = print_list_entry(buff, sizeof(buff)-1, name, flags, evr);
+    if (len >= 0)
+      XPUSHs(sv_2mortal(newSVpv(buff, len)));
+  }
+  PUTBACK;
+  /* returning zero indicates to continue processing */
+  return 0;
+}
+static int
+callback_list_str_xpush_requires(char *s, int slen, const char *name, const uint32_t flags, const char *evr, __attribute__((unused)) void *param) {
+  dSP;
+  if (s) {
+    XPUSHs(sv_2mortal(newSVpv(s, slen)));
+  } else if (is_not_old_suggests(flags)) {
+    char buff[4096];
+    int len = print_list_entry(buff, sizeof(buff)-1, name, flags, evr);
+    if (len >= 0)
+      XPUSHs(sv_2mortal(newSVpv(buff, len)));
+  }
+  PUTBACK;
+  /* returning zero indicates to continue processing */
+  return 0;
+}
+static int
+callback_list_str_xpush_old_suggests(char *s, int slen, const char *name, uint32_t flags, const char *evr, __attribute__((unused)) void *param) {
+  dSP;
+  if (s) {
+    XPUSHs(sv_2mortal(newSVpv(s, slen)));
+  } else if (is_old_suggests(flags)) {
+    char buff[4096];
+    int len = print_list_entry(buff, sizeof(buff)-1, name, flags, evr);
+    if (len >= 0)
+      XPUSHs(sv_2mortal(newSVpv(buff, len)));
+  }
+  PUTBACK;
+  /* returning zero indicates to continue processing */
+  return 0;
+}
+
+struct cb_overlap_s {
+  char *name;
+  int32_t flags;
+  char *evr;
+  int direction; /* indicate to compare the above at left or right to the iteration element */
+  int b_nopromote;
+};
+
+static int
+callback_list_str_overlap(char *s, int slen, const char *name, uint32_t flags, const char *evr, void *param) {
+  struct cb_overlap_s *os = (struct cb_overlap_s *)param;
+  int result = 0;
+  char *eos = NULL;
+  char *eon = NULL;
+  char eosc = '\0';
+  char eonc = '\0';
+
+  /* we need to extract name, flags and evr from a full sense information, store result in local copy */
+  if (s) {
+    if (slen) { eos = s + slen; eosc = *eos; *eos = 0; }
+    name = s;
+    while (*s && *s != ' ' && *s != '[' && *s != '<' && *s != '>' && *s != '=') ++s;
+    if (*s) {
+      eon = s;
+      while (*s) {
+	if (*s == ' ' || *s == '[' || *s == '*' || *s == ']');
+	else if (*s == '<') flags |= RPMSENSE_LESS;
+	else if (*s == '>') flags |= RPMSENSE_GREATER;
+	else if (*s == '=') flags |= RPMSENSE_EQUAL;
+	else break;
+	++s;
+      }
+      evr = s;
+    } else
+      evr = "";
+  }
+
+  /* mark end of name */
+  if (eon) { eonc = *eon; *eon = 0; }
+  /* names should be equal, else it will not overlap */
+  if (!strcmp(name, os->name)) {
+    /* perform overlap according to direction needed, negative for left */
+    if (os->direction < 0)
+      result = ranges_overlap(os->flags, os->evr, flags, (char *) evr, os->b_nopromote);
+    else
+      result = ranges_overlap(flags, (char *) evr, os->flags, os->evr, os->b_nopromote);
+  }
+
+  /* fprintf(stderr, "cb_list_str_overlap result=%d, os->direction=%d, os->name=%s, os->evr=%s, name=%s, evr=%s\n",
+     result, os->direction, os->name, os->evr, name, evr); */
+
+  /* restore s if needed */
+  if (eon) *eon = eonc;
+  if (eos) *eos = eosc;
+
+  return result;
+}
+
+static int
+return_list_str(char *s, Header header, int32_t tag_name, int32_t tag_flags, int32_t tag_version, callback_list_str f, void *param) {
+  int count = 0;
+
+  if (s != NULL) {
+    char *ps = strchr(s, '@');
+    if (tag_flags && tag_version) {
+      while(ps != NULL) {
+	++count;
+	if (f(s, ps-s, NULL, 0, NULL, param)) return -count;
+	s = ps + 1; ps = strchr(s, '@');
+      }
+      ++count;
+      if (f(s, 0, NULL, 0, NULL, param)) return -count;
+    } else {
+      char *eos;
+      while(ps != NULL) {
+	*ps = 0; eos = strchr(s, '['); if (!eos) eos = strchr(s, ' ');
+	++count;
+	if (f(s, eos ? eos-s : ps-s, NULL, 0, NULL, param)) { *ps = '@'; return -count; }
+	*ps = '@'; /* restore in memory modified char */
+	s = ps + 1; ps = strchr(s, '@');
+      }
+      eos = strchr(s, '['); if (!eos) eos = strchr(s, ' ');
+      ++count;
+      if (f(s, eos ? eos-s : 0, NULL, 0, NULL, param)) return -count;
+    }
+  } else if (header) {
+    struct rpmtd_s list, flags, list_evr;
+
+    if (headerGet(header, tag_name, &list, HEADERGET_DEFAULT)) {
+      if (tag_flags) headerGet(header, tag_flags, &flags, HEADERGET_DEFAULT);
+      if (tag_version) headerGet(header, tag_version, &list_evr, HEADERGET_DEFAULT);
+      while (rpmtdNext(&list) >= 0) {
+	++count;
+	uint32_t *flag = rpmtdNextUint32(&flags);
+	if (f(NULL, 0, rpmtdGetString(&list), flag ? *flag : 0, 
+	      rpmtdNextString(&list_evr), param)) {
+	  rpmtdFreeData(&list);
+	  if (tag_flags) rpmtdFreeData(&flags);
+	  if (tag_version) rpmtdFreeData(&list_evr);
+	  return -count;
+	}
+      }
+      rpmtdFreeData(&list);
+      if (tag_flags) rpmtdFreeData(&flags);
+      if (tag_version) rpmtdFreeData(&list_evr);
+    }
+  }
+  return count;
+}
+
+static int
+xpush_simple_list_str(Header header, int32_t tag_name) {
+  dSP;
+  if (header) {
+    struct rpmtd_s list;
+    const char *val;
+    int size;
+
+    if (!headerGet(header, tag_name, &list, HEADERGET_DEFAULT)) return 0;
+    size = rpmtdCount(&list);
+
+    while ((val = rpmtdNextString(&list))) {
+        XPUSHs(sv_2mortal(newSVpv(val, 0)));
+    }
+    rpmtdFreeData(&list);
+    PUTBACK;
+    return size;
+  } else return 0;
+}
+
+void
+return_list_int32_t(Header header, int32_t tag_name) {
+  dSP;
+  if (header) {
+    struct rpmtd_s list;
+
+    if (headerGet(header, tag_name, &list, HEADERGET_DEFAULT)) {
+      uint32_t *val;
+      while ((val = rpmtdNextUint32(&list)))
+	XPUSHs(sv_2mortal(newSViv(*val)));
+      rpmtdFreeData(&list);
+    }
+  }
+  PUTBACK;
+}
+
+void
+return_list_uint_16(Header header, int32_t tag_name) {
+  dSP;
+  if (header) {
+    struct rpmtd_s list;
+    if (headerGet(header, tag_name, &list, HEADERGET_DEFAULT)) {
+      int count = rpmtdCount(&list);
+      int i;
+      uint16_t *list_ = list.data;
+      for(i = 0; i < count; i++) {
+	XPUSHs(sv_2mortal(newSViv(list_[i])));
+      }
+      rpmtdFreeData(&list);
+    }
+  }
+  PUTBACK;
+}
+
+void
+return_list_tag_modifier(Header header, int32_t tag_name) {
+  dSP;
+  int i;
+  struct rpmtd_s td;
+  if (!headerGet(header, tag_name, &td, HEADERGET_DEFAULT)) return;
+  int count = rpmtdCount(&td);
+  int32_t *list = td.data;
+
+  for (i = 0; i < count; i++) {
+    char buff[15];
+    char *s = buff;
+    switch (tag_name) {
+    case RPMTAG_FILEFLAGS:
+      if (list[i] & RPMFILE_CONFIG)    *s++ = 'c';
+      if (list[i] & RPMFILE_DOC)       *s++ = 'd';
+      if (list[i] & RPMFILE_GHOST)     *s++ = 'g';
+      if (list[i] & RPMFILE_LICENSE)   *s++ = 'l';
+      if (list[i] & RPMFILE_MISSINGOK) *s++ = 'm';
+      if (list[i] & RPMFILE_NOREPLACE) *s++ = 'n';
+      if (list[i] & RPMFILE_SPECFILE)  *s++ = 'S';
+      if (list[i] & RPMFILE_README)    *s++ = 'R';
+      if (list[i] & RPMFILE_EXCLUDE)   *s++ = 'e';
+      if (list[i] & RPMFILE_ICON)      *s++ = 'i';
+      if (list[i] & RPMFILE_UNPATCHED) *s++ = 'u';
+      if (list[i] & RPMFILE_PUBKEY)    *s++ = 'p';
+    break;
+    default:
+      rpmtdFreeData(&td);
+      return;  
+    }
+    *s = '\0';
+    XPUSHs(sv_2mortal(newSVpv(buff, strlen(buff))));
+  }
+  rpmtdFreeData(&td);
+  PUTBACK;
+}
+
+void
+return_list_tag(URPM__Package pkg, int32_t tag_name) {
+  dSP;
+  if (pkg->h != NULL) {
+    struct rpmtd_s td;
+    if (headerGet(pkg->h, tag_name, &td, HEADERGET_DEFAULT)) {
+      void *list = td.data;
+      int32_t count = rpmtdCount(&td);
+      if (tag_name == RPMTAG_ARCH) {
+	XPUSHs(sv_2mortal(newSVpv(headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? (char *) list : "src", 0)));
+      } else
+	switch (rpmtdType(&td)) {
+	  case RPM_NULL_TYPE:
+	    break;
+#ifdef RPM_ORG
+	  case RPM_CHAR_TYPE:
+#endif
+	  case RPM_INT8_TYPE:
+	  case RPM_INT16_TYPE:
+	  case RPM_INT32_TYPE:
+	    {
+	      int i;
+	      int *r;
+	      r = (int *)list;
+	      for (i=0; i < count; i++) {
+		XPUSHs(sv_2mortal(newSViv(r[i])));
+	      }
+	    }
+	    break;
+	  case RPM_STRING_TYPE:
+	    XPUSHs(sv_2mortal(newSVpv((char *) list, 0)));
+	    break;
+	  case RPM_BIN_TYPE:
+	    break;
+	  case RPM_STRING_ARRAY_TYPE:
+	    {
+	      int i;
+	      char **s;
+
+	      s = (char **)list;
+	      for (i = 0; i < count; i++) {
+		XPUSHs(sv_2mortal(newSVpv(s[i], 0)));
+	      }
+	    }
+	    break;
+	  case RPM_I18NSTRING_TYPE:
+	    break;
+	  case RPM_INT64_TYPE:
+	    break;
+	}
+    }
+  } else {
+    char *name;
+    char *version;
+    char *release;
+    char *arch;
+    char *eos;
+    switch (tag_name) {
+      case RPMTAG_NAME:
+	{
+	  get_fullname_parts(pkg, &name, &version, &release, &arch, &eos);
+	  if (version - name < 1) croak("invalid fullname");
+	  XPUSHs(sv_2mortal(newSVpv(name, version-name - 1)));
+	}
+	break;
+      case RPMTAG_VERSION:
+	{
+	  get_fullname_parts(pkg, &name, &version, &release, &arch, &eos);
+	  if (release - version < 1) croak("invalid fullname");
+	  XPUSHs(sv_2mortal(newSVpv(version, release-version - 1)));
+	}
+	break;
+      case RPMTAG_RELEASE:
+	{
+	  get_fullname_parts(pkg, &name, &version, &release, &arch, &eos);
+	  if (arch - release < 1) croak("invalid fullname");
+	  XPUSHs(sv_2mortal(newSVpv(release, arch-release - 1)));
+	}
+	break;
+      case RPMTAG_ARCH:
+	{
+	  get_fullname_parts(pkg, &name, &version, &release, &arch, &eos);
+	  XPUSHs(sv_2mortal(newSVpv(arch, eos-arch)));
+	}
+	break;
+      case RPMTAG_SUMMARY:
+	XPUSHs(sv_2mortal(newSVpv(pkg->summary, 0)));
+	break;
+    }
+  }
+  PUTBACK;
+}
+
+
+void
+return_files(Header header, int filter_mode) {
+  dSP;
+  if (header) {
+    char buff[4096];
+    char *p, *s;
+    STRLEN len;
+    unsigned int i;
+
+    struct rpmtd_s td_flags, td_fmodes;
+    int32_t *flags = NULL;
+    uint16_t *fmodes = NULL;
+    if (filter_mode) {
+      headerGet(header, RPMTAG_FILEFLAGS, &td_flags, HEADERGET_DEFAULT);
+      headerGet(header, RPMTAG_FILEMODES, &td_fmodes, HEADERGET_DEFAULT);
+      flags = td_flags.data;
+      fmodes = td_fmodes.data;
+    }
+
+    struct rpmtd_s td_baseNames, td_dirIndexes, td_dirNames, td_list;
+    headerGet(header, RPMTAG_BASENAMES, &td_baseNames, HEADERGET_DEFAULT);
+    headerGet(header, RPMTAG_DIRINDEXES, &td_dirIndexes, HEADERGET_DEFAULT);
+    headerGet(header, RPMTAG_DIRNAMES, &td_dirNames, HEADERGET_DEFAULT);
+
+    char **baseNames = td_baseNames.data;
+    char **dirNames = td_dirNames.data;
+    int32_t *dirIndexes = td_dirIndexes.data;
+
+    char **list = NULL;
+    if (!baseNames || !dirNames || !dirIndexes) {
+      if (!headerGet(header, RPMTAG_OLDFILENAMES, &td_list, HEADERGET_DEFAULT)) return;
+      list = td_list.data;
+    }
+
+    for(i = 0; i < rpmtdCount(&td_baseNames); i++) {
+      if (list) {
+	s = list[i];
+	len = strlen(list[i]);
+      } else {
+	len = strlen(dirNames[dirIndexes[i]]);
+	if (len >= sizeof(buff)) continue;
+	memcpy(p = buff, dirNames[dirIndexes[i]], len + 1); p += len;
+	len = strlen(baseNames[i]);
+	if (p - buff + len >= sizeof(buff)) continue;
+	memcpy(p, baseNames[i], len + 1); p += len;
+	s = buff;
+	len = p-buff;
+      }
+
+      if (filter_mode) {
+	if ((filter_mode & FILTER_MODE_CONF_FILES) && flags && (flags[i] & RPMFILE_CONFIG) == 0) continue;
+      }
+
+      XPUSHs(sv_2mortal(newSVpv(s, len)));
+    }
+
+    free(baseNames);
+    free(dirNames);
+    free(list);
+  }
+  PUTBACK;
+}
+
+void
+return_problems(rpmps ps, int translate_message, int raw_message) {
+  dSP;
+  if (ps && rpmpsNumProblems(ps) > 0) {
+    rpmpsi iterator = rpmpsInitIterator(ps);
+    while (rpmpsNextIterator(iterator) >= 0) {
+      rpmProblem p = rpmpsGetProblem(iterator);
+
+      if (translate_message) {
+	/* translate error using rpm localization */
+	const char *buf = rpmProblemString(p);
+	SV *sv = newSVpv(buf, 0);
+	if (rpm_codeset_is_utf8) SvUTF8_on(sv);
+	XPUSHs(sv_2mortal(sv));
+	_free(buf);
+      }
+      if (raw_message) {
+	const char *pkgNEVR = rpmProblemGetPkgNEVR(p) ? rpmProblemGetPkgNEVR(p) : "";
+	const char *altNEVR = rpmProblemGetAltNEVR(p) ? rpmProblemGetAltNEVR(p) : "";
+	const char *s = rpmProblemGetStr(p) ? rpmProblemGetStr(p) : "";
+	SV *sv;
+
+	switch (rpmProblemGetType(p)) {
+	case RPMPROB_BADARCH:
+	  sv = newSVpvf("badarch@%s", pkgNEVR); break;
+
+	case RPMPROB_BADOS:
+	  sv = newSVpvf("bados@%s", pkgNEVR); break;
+
+	case RPMPROB_PKG_INSTALLED:
+	  sv = newSVpvf("installed@%s", pkgNEVR); break;
+
+	case RPMPROB_BADRELOCATE:
+	  sv = newSVpvf("badrelocate@%s@%s", pkgNEVR, s); break;
+
+	case RPMPROB_NEW_FILE_CONFLICT:
+	case RPMPROB_FILE_CONFLICT:
+	  sv = newSVpvf("conflicts@%s@%s@%s", pkgNEVR, altNEVR, s); break;
+
+	case RPMPROB_OLDPACKAGE:
+	  sv = newSVpvf("installed@%s@%s", pkgNEVR, altNEVR); break;
+
+	case RPMPROB_DISKSPACE:
+	  sv = newSVpvf("diskspace@%s@%s@%lld", pkgNEVR, s, (long long)rpmProblemGetDiskNeed(p)); break;
+	case RPMPROB_DISKNODES:
+	  sv = newSVpvf("disknodes@%s@%s@%lld", pkgNEVR, s, (long long)rpmProblemGetDiskNeed(p)); break;
+	case RPMPROB_REQUIRES:
+	  sv = newSVpvf("requires@%s@%s", pkgNEVR, altNEVR+2); break;
+
+	case RPMPROB_CONFLICT:
+	  sv = newSVpvf("conflicts@%s@%s", pkgNEVR, altNEVR+2); break;
+
+	default:
+	  sv = newSVpvf("unknown@%s", pkgNEVR); break;
+	}
+	XPUSHs(sv_2mortal(sv));
+      }
+    }
+    rpmpsFreeIterator(iterator);
+  }
+  PUTBACK;
+}
+
+static char *
+pack_list(Header header, int32_t tag_name, int32_t tag_flags, int32_t tag_version, int32_t (*check_flag)(int32_t)) {
+  char buff[65536];
+  int32_t *flags = NULL;
+  char **list_evr = NULL;
+  unsigned int i;
+  char *p = buff;
+
+  struct rpmtd_s td;
+  if (headerGet(header, tag_name, &td, HEADERGET_DEFAULT)) {
+    char **list = td.data;
+    
+    struct rpmtd_s td_flags, td_list_evr;
+    if (tag_flags   && headerGet(header, tag_flags,   &td_flags, HEADERGET_DEFAULT))    flags    = td_flags.data;
+    if (tag_version && headerGet(header, tag_version, &td_list_evr, HEADERGET_DEFAULT)) list_evr = td_list_evr.data;
+    for(i = 0; i < rpmtdCount(&td); i++) {
+      if (check_flag && !check_flag(flags[i])) continue;
+      int len = print_list_entry(p, sizeof(buff)-(p-buff)-1, list[i], flags ? flags[i] : 0, list_evr ? list_evr[i] : NULL);
+      if (len < 0) continue;
+      p += len;
+      *p++ = '@';
+    }
+    if (p > buff) p[-1] = 0;
+
+    free(list);
+    free(list_evr);
+  }
+
+  return p > buff ? memcpy(malloc(p-buff), buff, p-buff) : NULL;
+}
+
+static void
+pack_header(URPM__Package pkg) {
+  if (pkg->h) {
+    if (pkg->info == NULL) {
+      char buff[1024];
+      char *p = buff;
+      char *name = get_name(pkg->h, RPMTAG_NAME);
+      char *version = get_name(pkg->h, RPMTAG_VERSION);
+      char *release = get_name(pkg->h, RPMTAG_RELEASE);
+      char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src";
+
+      p += 1 + snprintf(buff, sizeof(buff), "%s-%s-%s.%s@%d@%d@%s", name, version, release, arch,
+		    get_int(pkg->h, RPMTAG_EPOCH), get_int(pkg->h, RPMTAG_SIZE), 
+		    get_name(pkg->h, RPMTAG_GROUP));
+      pkg->info = memcpy(malloc(p-buff), buff, p-buff);
+    }
+    if (pkg->filesize == 0) pkg->filesize = sigsize_to_filesize(get_int(pkg->h, RPMTAG_SIGSIZE));
+    if (pkg->requires == NULL && pkg->suggests == NULL)
+      has_old_suggests = 0;
+      pkg->requires = pack_list(pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, RPMTAG_REQUIREVERSION, is_not_old_suggests);
+      if (has_old_suggests)
+      pkg->suggests = pack_list(pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, RPMTAG_REQUIREVERSION, is_old_suggests);
+      else
+        pkg->suggests = pack_list(pkg->h, RPMTAG_SUGGESTSNAME, 0, 0, NULL);
+    if (pkg->obsoletes == NULL)
+      pkg->obsoletes = pack_list(pkg->h, RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEFLAGS, RPMTAG_OBSOLETEVERSION, NULL);
+    if (pkg->conflicts == NULL)
+      pkg->conflicts = pack_list(pkg->h, RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTFLAGS, RPMTAG_CONFLICTVERSION, NULL);
+    if (pkg->provides == NULL)
+      pkg->provides = pack_list(pkg->h, RPMTAG_PROVIDENAME, RPMTAG_PROVIDEFLAGS, RPMTAG_PROVIDEVERSION, NULL);
+    if (pkg->summary == NULL) {
+      char *summary = get_name(pkg->h, RPMTAG_SUMMARY);
+      int len = 1 + strlen(summary);
+
+      pkg->summary = memcpy(malloc(len), summary, len);
+    }
+
+    if (!(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h =headerFree(pkg->h);
+    pkg->h = 0;
+  }
+}
+
+static void
+update_hash_entry(HV *hash, char *name, STRLEN len, int force, IV use_sense, URPM__Package pkg) {
+  SV** isv;
+
+  if (!len) len = strlen(name);
+  if ((isv = hv_fetch(hash, name, len, force))) {
+    /* check if an entry has been found or created, it should so be updated */
+    if (!SvROK(*isv) || SvTYPE(SvRV(*isv)) != SVt_PVHV) {
+      SV* choice_set = (SV*)newHV();
+      if (choice_set) {
+	SvREFCNT_dec(*isv); /* drop the old as we are changing it */
+	if (!(*isv = newRV_noinc(choice_set))) {
+	  SvREFCNT_dec(choice_set);
+	  *isv = &PL_sv_undef;
+	}
+      }
+    }
+    if (isv && *isv != &PL_sv_undef) {
+      char id[8];
+      STRLEN id_len = snprintf(id, sizeof(id), "%d", pkg->flag & FLAG_ID);
+      SV **sense = hv_fetch((HV*)SvRV(*isv), id, id_len, 1);
+      if (sense && use_sense) sv_setiv(*sense, use_sense);
+    }
+  }
+}
+
+static void
+update_provide_entry(char *name, STRLEN len, int force, IV use_sense, URPM__Package pkg, HV *provides) {
+  update_hash_entry(provides, name, len, force, use_sense, pkg);
+}
+
+static void
+update_provides(URPM__Package pkg, HV *provides) {
+  if (pkg->h) {
+    int len;
+    struct rpmtd_s td, td_flags;
+    int32_t *flags = NULL;
+    unsigned int i;
+
+    /* examine requires for files which need to be marked in provides */
+    if (headerGet(pkg->h, RPMTAG_REQUIRENAME, &td, HEADERGET_DEFAULT)) {
+      char **list = td.data;
+      for (i = 0; i < rpmtdCount(&td); ++i) {
+	len = strlen(list[i]);
+	if (list[i][0] == '/') (void)hv_fetch(provides, list[i], len, 1);
+      }
+    }
+
+    /* update all provides */
+    if (headerGet(pkg->h, RPMTAG_PROVIDENAME, &td, HEADERGET_DEFAULT)) {
+      char **list = td.data;
+      if (headerGet(pkg->h, RPMTAG_PROVIDEFLAGS, &td_flags, HEADERGET_DEFAULT))
+	flags = td_flags.data;
+      for (i = 0; i < rpmtdCount(&td); ++i) {
+	len = strlen(list[i]);
+	if (!strncmp(list[i], "rpmlib(", 7)) continue;
+	update_provide_entry(list[i], len, 1, flags && flags[i] & (RPMSENSE_PREREQ|RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POSTUN|RPMSENSE_SCRIPT_POST|RPMSENSE_LESS|RPMSENSE_EQUAL|RPMSENSE_GREATER),
+			     pkg, provides);
+      }
+    }
+  } else {
+    char *ps, *s, *es;
+
+    if ((s = pkg->requires) != NULL && *s != 0) {
+      ps = strchr(s, '@');
+      while(ps != NULL) {
+	if (s[0] == '/') {
+	  *ps = 0; es = strchr(s, '['); if (!es) es = strchr(s, ' '); *ps = '@';
+	  (void)hv_fetch(provides, s, es != NULL ? es-s : ps-s, 1);
+	}
+	s = ps + 1; ps = strchr(s, '@');
+      }
+      if (s[0] == '/') {
+      es = strchr(s, '['); if (!es) es = strchr(s, ' ');
+	(void)hv_fetch(provides, s, es != NULL ? (U32)(es-s) : strlen(s), 1);
+      }
+    }
+
+    if ((s = pkg->provides) != NULL && *s != 0) {
+      char *es;
+
+      ps = strchr(s, '@');
+      while(ps != NULL) {
+	*ps = 0; es = strchr(s, '['); if (!es) es = strchr(s, ' '); *ps = '@';
+	update_provide_entry(s, es != NULL ? es-s : ps-s, 1, es != NULL, pkg, provides);
+	s = ps + 1; ps = strchr(s, '@');
+      }
+      es = strchr(s, '['); if (!es) es = strchr(s, ' ');
+      update_provide_entry(s, es != NULL ? es-s : 0, 1, es != NULL, pkg, provides);
+    }
+  }
+}
+
+static void
+update_obsoletes(URPM__Package pkg, HV *obsoletes) {
+  if (pkg->h) {
+    struct rpmtd_s td;
+
+    /* update all provides */
+    if (headerGet(pkg->h, RPMTAG_OBSOLETENAME, &td, HEADERGET_DEFAULT)) {
+      char **list = td.data;
+      unsigned int i;
+      for (i = 0; i < rpmtdCount(&td); ++i)
+	update_hash_entry(obsoletes, list[i], 0, 1, 0, pkg);
+    }
+  } else {
+    char *ps, *s;
+
+    if ((s = pkg->obsoletes) != NULL && *s != 0) {
+      char *es;
+
+      ps = strchr(s, '@');
+      while(ps != NULL) {
+	*ps = 0; es = strchr(s, '['); if (!es) es = strchr(s, ' '); *ps = '@';
+	update_hash_entry(obsoletes, s, es != NULL ? es-s : ps-s, 1, 0, pkg);
+	s = ps + 1; ps = strchr(s, '@');
+      }
+      es = strchr(s, '['); if (!es) es = strchr(s, ' ');
+      update_hash_entry(obsoletes, s, es != NULL ? es-s : 0, 1, 0, pkg);
+    }
+  }
+}
+
+static void
+update_provides_files(URPM__Package pkg, HV *provides) {
+  if (pkg->h) {
+    STRLEN len;
+    char **list = NULL;
+    unsigned int i;
+
+    struct rpmtd_s td_baseNames, td_dirIndexes, td_dirNames;
+    if (headerGet(pkg->h, RPMTAG_BASENAMES, &td_baseNames, HEADERGET_DEFAULT) &&
+	headerGet(pkg->h, RPMTAG_DIRINDEXES, &td_dirIndexes, HEADERGET_DEFAULT) &&
+	headerGet(pkg->h, RPMTAG_DIRNAMES, &td_dirNames, HEADERGET_DEFAULT)) {
+
+      char **baseNames = td_baseNames.data;
+      char **dirNames = td_dirNames.data;
+      int32_t *dirIndexes = td_dirIndexes.data;
+
+      char buff[4096];
+      char *p;
+
+      for(i = 0; i < rpmtdCount(&td_baseNames); i++) {
+	len = strlen(dirNames[dirIndexes[i]]);
+	if (len >= sizeof(buff)) continue;
+	memcpy(p = buff, dirNames[dirIndexes[i]], len + 1); p += len;
+	len = strlen(baseNames[i]);
+	if (p - buff + len >= sizeof(buff)) continue;
+	memcpy(p, baseNames[i], len + 1); p += len;
+
+	update_provide_entry(buff, p-buff, 0, 0, pkg, provides);
+      }
+
+      free(baseNames);
+      free(dirNames);
+    } else {
+      struct rpmtd_s td;
+      headerGet(pkg->h, RPMTAG_OLDFILENAMES, &td, HEADERGET_DEFAULT);
+      if (list) {
+	for (i = 0; i < rpmtdCount(&td); i++) {
+	  len = strlen(list[i]);
+
+	  update_provide_entry(list[i], len, 0, 0, pkg, provides);
+	}
+
+	free(list);
+      }
+    }
+  }
+}
+
+int
+open_archive(char *filename, pid_t *pid, int *empty_archive) {
+  int fd;
+  struct {
+    char header[4];
+    char toc_d_count[4];
+    char toc_l_count[4];
+    char toc_f_count[4];
+    char toc_str_size[4];
+    char uncompress[40];
+    char trailer[4];
+  } buf;
+
+  fd = open(filename, O_RDONLY);
+  if (fd >= 0) {
+    int pos = lseek(fd, -(int)sizeof(buf), SEEK_END);
+    if (read(fd, &buf, sizeof(buf)) != sizeof(buf) || strncmp(buf.header, "cz[0", 4) || strncmp(buf.trailer, "0]cz", 4)) {
+      /* this is not an archive, open it without magic, but first rewind at begin of file */
+      lseek(fd, 0, SEEK_SET);
+    } else if (pos == 0) {
+      *empty_archive = 1;
+      fd = -1;
+    } else {
+      /* this is an archive, create a pipe and fork for reading with uncompress defined inside */
+      int fdno[2];
+
+      if (!pipe(fdno)) {
+	if ((*pid = fork()) != 0) {
+	  fd_set readfds;
+	  struct timeval timeout;
+
+	  FD_ZERO(&readfds);
+	  FD_SET(fdno[0], &readfds);
+	  timeout.tv_sec = 1;
+	  timeout.tv_usec = 0;
+	  select(fdno[0]+1, &readfds, NULL, NULL, &timeout);
+
+	  close(fd);
+	  fd = fdno[0];
+	  close(fdno[1]);
+	} else {
+	  char *unpacker[22]; /* enough for 40 bytes in uncompress to never overbuf */
+	  char *p = buf.uncompress;
+	  int ip = 0;
+	  char *ld_loader = getenv("LD_LOADER");
+
+	  if (ld_loader && *ld_loader) {
+	    unpacker[ip++] = ld_loader;
+	  }
+
+	  buf.trailer[0] = 0; /* make sure end-of-string is right */
+	  while (*p) {
+	    if (*p == ' ' || *p == '\t') *p++ = 0;
+	    else {
+	      unpacker[ip++] = p;
+	      while (*p && *p != ' ' && *p != '\t') ++p;
+	    }
+	  }
+	  unpacker[ip] = NULL; /* needed for execlp */
+
+	  lseek(fd, 0, SEEK_SET);
+	  dup2(fd, STDIN_FILENO); close(fd);
+	  dup2(fdno[1], STDOUT_FILENO); close(fdno[1]);
+
+	  /* get rid of "decompression OK, trailing garbage ignored" */
+	  fd = open("/dev/null", O_WRONLY);
+	  dup2(fd, STDERR_FILENO); close(fd);
+
+	  execvp(unpacker[0], unpacker);
+	  exit(1);
+	}
+      } else {
+	close(fd);
+	fd = -1;
+      }
+    }
+  }
+  return fd;
+}
+
+static int
+call_package_callback(SV *urpm, SV *sv_pkg, SV *callback) {
+  if (sv_pkg != NULL && callback != NULL) {
+    int count;
+
+    /* now, a callback will be called for sure */
+    dSP;
+    PUSHMARK(SP);
+    XPUSHs(urpm);
+    XPUSHs(sv_pkg);
+    PUTBACK;
+    count = call_sv(callback, G_SCALAR);
+    SPAGAIN;
+    if (count == 1 && !POPi) {
+      /* package should not be added in depslist, so we free it */
+      SvREFCNT_dec(sv_pkg);
+      sv_pkg = NULL;
+    }
+    PUTBACK;
+  }
+
+  return sv_pkg != NULL;
+}
+
+static int
+parse_line(AV *depslist, HV *provides, HV *obsoletes, URPM__Package pkg, char *buff, SV *urpm, SV *callback) {
+  SV *sv_pkg;
+  URPM__Package _pkg;
+  char *tag, *data;
+  int data_len;
+
+  if (buff[0] == 0) {
+    return 1;
+  } else if ((tag = buff)[0] == '@' && (data = strchr(tag+1, '@')) != NULL) {
+    *tag++ = *data++ = 0;
+    data_len = 1+strlen(data);
+    if (!strcmp(tag, "info")) {
+      pkg->info = memcpy(malloc(data_len), data, data_len);
+      pkg->flag &= ~FLAG_ID;
+      pkg->flag |= 1 + av_len(depslist);
+      sv_pkg = sv_setref_pv(newSVpv("", 0), "URPM::Package",
+			    _pkg = memcpy(malloc(sizeof(struct s_Package)), pkg, sizeof(struct s_Package)));
+      if (call_package_callback(urpm, sv_pkg, callback)) {
+	if (provides) update_provides(_pkg, provides);
+	if (obsoletes) update_obsoletes(_pkg, obsoletes);
+	av_push(depslist, sv_pkg);
+      }
+      memset(pkg, 0, sizeof(struct s_Package));
+    } else if (!strcmp(tag, "filesize")) {
+      pkg->filesize = atoi(data);
+    } else if (!strcmp(tag, "requires")) {
+      free(pkg->requires); pkg->requires = memcpy(malloc(data_len), data, data_len);
+    } else if (!strcmp(tag, "suggests")) {
+      free(pkg->suggests); pkg->suggests = memcpy(malloc(data_len), data, data_len);
+    } else if (!strcmp(tag, "obsoletes")) {
+      free(pkg->obsoletes); pkg->obsoletes = memcpy(malloc(data_len), data, data_len);
+    } else if (!strcmp(tag, "conflicts")) {
+      free(pkg->conflicts); pkg->conflicts = memcpy(malloc(data_len), data, data_len);
+    } else if (!strcmp(tag, "provides")) {
+      free(pkg->provides); pkg->provides = memcpy(malloc(data_len), data, data_len);
+    } else if (!strcmp(tag, "summary")) {
+      free(pkg->summary); pkg->summary = memcpy(malloc(data_len), data, data_len);
+    }
+    return 1;
+  } else {
+    fprintf(stderr, "bad line <%s>\n", buff);
+    return 0;
+  }
+}
+
+#if 0
+static void pack_rpm_header(Header *h) {
+  Header packed = headerNew();
+
+  HeaderIterator hi = headerInitIterator(*h);
+  struct rpmtd_s td;
+  while (headerNext(hi, &td)) {
+      // fprintf(stderr, "adding %s %d\n", tagname(tag), c);
+      headerPut(packed, &td, HEADERPUT_DEFAULT);
+      rpmtdFreeData(&td);
+  }
+
+  headerFreeIterator(hi);
+  *h = headerFree(*h);
+
+  *h = packed;
+}
+
+static void drop_tags(Header *h) {
+  headerDel(*h, RPMTAG_FILEUSERNAME); /* user ownership is correct */
+  headerDel(*h, RPMTAG_FILEGROUPNAME); /* group ownership is correct */
+  headerDel(*h, RPMTAG_FILEMTIMES); /* correct time without it */
+  headerDel(*h, RPMTAG_FILEINODES); /* hardlinks work without it */
+  headerDel(*h, RPMTAG_FILEDEVICES); /* it is the same number for every file */
+  headerDel(*h, RPMTAG_FILESIZES); /* ? */
+  headerDel(*h, RPMTAG_FILERDEVS); /* it seems unused. always empty */
+  headerDel(*h, RPMTAG_FILEVERIFYFLAGS); /* only used for -V */
+#ifndef RPM_ORG
+  headerDel(*h, RPMTAG_FILEDIGESTALGOS); /* only used for -V */
+  headerDel(*h, RPMTAG_FILEDIGESTS); /* only used for -V */ /* alias: RPMTAG_FILEMD5S */ 
+#endif
+  /* keep RPMTAG_FILEFLAGS for %config (rpmnew) to work */
+  /* keep RPMTAG_FILELANGS for %lang (_install_langs) to work */
+  /* keep RPMTAG_FILELINKTOS for checking conflicts between symlinks */
+  /* keep RPMTAG_FILEMODES otherwise it segfaults with excludepath */
+
+  /* keep RPMTAG_POSTIN RPMTAG_POSTUN RPMTAG_PREIN RPMTAG_PREUN */
+  /* keep RPMTAG_TRIGGERSCRIPTS RPMTAG_TRIGGERVERSION RPMTAG_TRIGGERFLAGS RPMTAG_TRIGGERNAME */
+  /* small enough, and only in some packages. not needed per se */
+
+  headerDel(*h, RPMTAG_ICON);
+  headerDel(*h, RPMTAG_GIF);
+  headerDel(*h, RPMTAG_EXCLUDE);
+  headerDel(*h, RPMTAG_EXCLUSIVE);
+  headerDel(*h, RPMTAG_COOKIE);
+  headerDel(*h, RPMTAG_VERIFYSCRIPT);
+
+  /* always the same for our packages */
+  headerDel(*h, RPMTAG_VENDOR);
+  headerDel(*h, RPMTAG_DISTRIBUTION);
+
+  /* keep RPMTAG_SIGSIZE, useful to tell the size of the rpm file (+440) */
+
+  headerDel(*h, RPMTAG_DSAHEADER);
+  headerDel(*h, RPMTAG_SHA1HEADER);
+  headerDel(*h, RPMTAG_SIGMD5);
+  headerDel(*h, RPMTAG_SIGGPG);
+
+  pack_rpm_header(h);
+}
+#endif
+
+static int
+update_header(char *filename, URPM__Package pkg, __attribute__((unused)) int keep_all_tags, int vsflags) {
+  int d = open(filename, O_RDONLY);
+
+  if (d >= 0) {
+    unsigned char sig[4];
+
+    if (read(d, &sig, sizeof(sig)) == sizeof(sig)) {
+      lseek(d, 0, SEEK_SET);
+      if (sig[0] == 0xed && sig[1] == 0xab && sig[2] == 0xee && sig[3] == 0xdb) {
+	FD_t fd = fdDup(d);
+	Header header;
+	rpmts ts;
+
+	close(d);
+	ts = rpmtsCreate();
+	rpmtsSetVSFlags(ts, _RPMVSF_NOSIGNATURES | vsflags);
+	if (fd != NULL && rpmReadPackageFile(ts, fd, filename, &header) == 0 && header) {
+	  char *basename;
+#ifndef RPM_ORG
+	  struct stat sb;
+#else
+	  int32_t size;
+#endif
+
+	  basename = strrchr(filename, '/');
+#ifndef RPM_ORG
+	  Fstat(fd, &sb);
+#else
+	  size = fdSize(fd);
+#endif
+	  Fclose(fd);
+
+	  /* this is only kept for compatibility with older distros
+	     (where ->filename on "unpacked" URPM::Package rely on FILENAME_TAG) */
+	  headerPutString(header, FILENAME_TAG, basename != NULL ? basename + 1 : filename);
+
+	  if (pkg->h && !(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h = headerFree(pkg->h);
+	  pkg->h = header;
+	  pkg->flag &= ~FLAG_NO_HEADER_FREE;
+
+	  /*if (!keep_all_tags) drop_tags(&pkg->h);*/
+	  (void)rpmtsFree(ts);
+	  return 1;
+	}
+	(void)rpmtsFree(ts);
+      } else if (sig[0] == 0x8e && sig[1] == 0xad && sig[2] == 0xe8 && sig[3] == 0x01) {
+	FD_t fd = fdDup(d);
+
+	close(d);
+	if (fd != NULL) {
+	  if (pkg->h && !(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h = headerFree(pkg->h);
+	  pkg->h = headerRead(fd, HEADER_MAGIC_YES);
+	  pkg->flag &= ~FLAG_NO_HEADER_FREE;
+	  Fclose(fd);
+	  return 1;
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+static int
+read_config_files(int force) {
+  static int already = 0;
+  int rc = 0;
+
+  if (!already || force) {
+    rc = rpmReadConfigFiles(NULL, NULL);
+    already = (rc == 0); /* set config as load only if it succeed */
+  }
+  return rc;
+}
+
+static void
+ts_nosignature(rpmts ts) {
+  rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES);
+}
+
+static void *rpmRunTransactions_callback(__attribute__((unused)) const void *h,
+					 const rpmCallbackType what, 
+					 const rpm_loff_t amount, 
+					 const rpm_loff_t total,
+					 fnpyKey pkgKey,
+					 rpmCallbackData data) {
+  static struct timeval tprev;
+  static struct timeval tcurr;
+  static FD_t fd = NULL;
+  long delta;
+  int i;
+  struct s_TransactionData *td = data;
+  SV *callback = NULL;
+  char *callback_type = NULL;
+  char *callback_subtype = NULL;
+
+  if (!td)
+    return NULL;
+
+  switch (what) {
+    case RPMCALLBACK_INST_OPEN_FILE:
+      callback = td->callback_open;
+      callback_type = "open";
+      break;
+    case RPMCALLBACK_INST_CLOSE_FILE:
+      callback = td->callback_close;
+      callback_type = "close";
+      break;
+    case RPMCALLBACK_TRANS_START:
+    case RPMCALLBACK_TRANS_PROGRESS:
+    case RPMCALLBACK_TRANS_STOP:
+      callback = td->callback_trans;
+      callback_type = "trans";
+      break;
+    case RPMCALLBACK_UNINST_START:
+    case RPMCALLBACK_UNINST_PROGRESS:
+    case RPMCALLBACK_UNINST_STOP:
+      callback = td->callback_uninst;
+      callback_type = "uninst";
+      break;
+    case RPMCALLBACK_INST_START:
+    case RPMCALLBACK_INST_PROGRESS:
+      callback = td->callback_inst;
+      callback_type = "inst";
+      break;
+    default:
+      break;
+  }
+
+  if (callback != NULL) {
+    switch (what) {
+      case RPMCALLBACK_TRANS_START:
+      case RPMCALLBACK_UNINST_START:
+      case RPMCALLBACK_INST_START:
+	callback_subtype = "start";
+	gettimeofday(&tprev, NULL);
+	break;
+      case RPMCALLBACK_TRANS_PROGRESS:
+      case RPMCALLBACK_UNINST_PROGRESS:
+      case RPMCALLBACK_INST_PROGRESS:
+	callback_subtype = "progress";
+	gettimeofday(&tcurr, NULL);
+	delta = 1000000 * (tcurr.tv_sec - tprev.tv_sec) + (tcurr.tv_usec - tprev.tv_usec);
+	if (delta < td->min_delta && amount < total - 1)
+	  callback = NULL; /* avoid calling too often a given callback */
+	else
+	  tprev = tcurr;
+	break;
+      case RPMCALLBACK_TRANS_STOP:
+      case RPMCALLBACK_UNINST_STOP:
+	callback_subtype = "stop";
+	break;
+      default:
+	break;
+    }
+
+    if (callback != NULL) {
+      /* now, a callback will be called for sure */
+      dSP;
+      ENTER;
+      SAVETMPS;
+      PUSHMARK(SP);
+      XPUSHs(td->data);
+      XPUSHs(sv_2mortal(newSVpv(callback_type, 0)));
+      XPUSHs(pkgKey != NULL ? sv_2mortal(newSViv((long)pkgKey - 1)) : &PL_sv_undef);
+      if (callback_subtype != NULL) {
+	XPUSHs(sv_2mortal(newSVpv(callback_subtype, 0)));
+	XPUSHs(sv_2mortal(newSViv(amount)));
+	XPUSHs(sv_2mortal(newSViv(total)));
+      }
+      PUTBACK;
+      i = call_sv(callback, callback == td->callback_open ? G_SCALAR : G_DISCARD);
+      SPAGAIN;
+      if (callback == td->callback_open) {
+	if (i != 1) croak("callback_open should return a file handle");
+	i = POPi;
+	fd = fdDup(i);
+	if (fd) {
+	  fd = fdLink(fd, "persist perl-URPM");
+	  Fcntl(fd, F_SETFD, (void *)1); /* necessary to avoid forked/execed process to lock removable */
+	}
+	PUTBACK;
+      } else if (callback == td->callback_close) {
+	fd = fdFree(fd, "persist perl-URPM");
+	if (fd) {
+	  Fclose(fd);
+	  fd = NULL;
+	}
+      }
+      FREETMPS;
+      LEAVE;
+    }
+  }
+  return callback == td->callback_open ? fd : NULL;
+}
+
+int rpmtag_from_string(char *tag)
+{
+    if (!strcmp(tag, "name"))
+      return RPMTAG_NAME;
+    else if (!strcmp(tag, "whatprovides"))
+      return RPMTAG_PROVIDENAME;
+    else if (!strcmp(tag, "whatrequires"))
+      return RPMTAG_REQUIRENAME;
+    else if (!strcmp(tag, "whatconflicts"))
+      return RPMTAG_CONFLICTNAME;
+    else if (!strcmp(tag, "group"))
+      return RPMTAG_GROUP;
+    else if (!strcmp(tag, "triggeredby"))
+      return RPMTAG_TRIGGERNAME;
+    else if (!strcmp(tag, "path"))
+      return RPMTAG_BASENAMES;
+    else croak("unknown tag [%s]", tag);
+}
+
+MODULE = URPM            PACKAGE = URPM::Package       PREFIX = Pkg_
+
+void
+Pkg_DESTROY(pkg)
+  URPM::Package pkg
+  CODE:
+  free(pkg->info);
+  free(pkg->requires);
+  free(pkg->suggests);
+  free(pkg->obsoletes);
+  free(pkg->conflicts);
+  free(pkg->provides);
+  free(pkg->rflags);
+  free(pkg->summary);
+  if (pkg->h && !(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h = headerFree(pkg->h);
+  free(pkg);
+
+void
+Pkg_name(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *name;
+    char *version;
+
+    get_fullname_parts(pkg, &name, &version, NULL, NULL, NULL);
+    if (version - name < 1) croak("invalid fullname");
+    XPUSHs(sv_2mortal(newSVpv(name, version-name-1)));
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_NAME), 0)));
+  }
+
+void
+Pkg_version(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *version;
+    char *release;
+
+    get_fullname_parts(pkg, NULL, &version, &release, NULL, NULL);
+    if (release - version < 1) croak("invalid fullname");
+    XPUSHs(sv_2mortal(newSVpv(version, release-version-1)));
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_VERSION), 0)));
+  }
+
+void
+Pkg_release(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *release;
+    char *arch;
+
+    get_fullname_parts(pkg, NULL, NULL, &release, &arch, NULL);
+    if (arch - release < 1) croak("invalid fullname");
+    XPUSHs(sv_2mortal(newSVpv(release, arch-release-1)));
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_RELEASE), 0)));
+  }
+
+void
+Pkg_arch(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *arch;
+    char *eos;
+
+    get_fullname_parts(pkg, NULL, NULL, NULL, &arch, &eos);
+    XPUSHs(sv_2mortal(newSVpv(arch, eos-arch)));
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src", 0)));
+  }
+
+int
+Pkg_is_arch_compat__XS(pkg)
+  URPM::Package pkg
+  INIT:
+#ifndef RPM_ORG
+  char * platform;
+#endif
+  CODE:
+  read_config_files(0);
+  if (pkg->info) {
+    char *arch;
+    char *eos;
+
+    get_fullname_parts(pkg, NULL, NULL, NULL, &arch, &eos);
+    *eos = 0;
+#ifndef RPM_ORG
+    platform = rpmExpand(arch, "-%{_target_vendor}-%{_target_os}%{?_gnu}", NULL);
+    RETVAL = rpmPlatformScore(platform, NULL, 0);
+    _free(platform);
+#else
+    RETVAL = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+#endif
+    *eos = '@';
+  } else if (pkg->h && headerIsEntry(pkg->h, RPMTAG_SOURCERPM)) {
+    char *arch = get_name(pkg->h, RPMTAG_ARCH);
+#ifndef RPM_ORG
+    platform = rpmExpand(arch, "-%{_target_vendor}-%{_target_os}%{?_gnu}", NULL);
+    RETVAL = rpmPlatformScore(platform, NULL, 0);
+    _free(platform);
+#else
+    RETVAL = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+#endif
+  } else {
+    RETVAL = 0;
+  }
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_is_platform_compat(pkg)
+  URPM::Package pkg
+  INIT:
+#ifndef RPM_ORG
+  char * platform = NULL;
+  struct rpmtd_s val;
+#endif
+  CODE:
+#ifndef RPM_ORG
+  read_config_files(0);
+  if (pkg->h && headerIsEntry(pkg->h, RPMTAG_PLATFORM)) {
+    (void) headerGet(pkg->h, RPMTAG_PLATFORM, &val, HEADERGET_DEFAULT);
+    platform = (char *) rpmtdGetString(&val);
+    RETVAL = rpmPlatformScore(platform, NULL, 0);
+    platform = headerFreeData(platform, val.type);
+  } else if (pkg->info) {
+    char *arch;
+    char *eos;
+
+    get_fullname_parts(pkg, NULL, NULL, NULL, &arch, &eos);
+    *eos = 0;
+    platform = rpmExpand(arch, "-%{_target_vendor}-", eos, "%{?_gnu}", NULL);
+    RETVAL = rpmPlatformScore(platform, NULL, 0);
+    *eos = '@';
+    _free(platform);
+  } else { 
+#else
+    croak("is_platform_compat() is available only since rpm 4.4.8");
+    { /* to match last } and avoid another #ifdef for it */
+#endif
+    RETVAL = 0;
+    }
+  
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_summary(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->summary) {
+    XPUSHs(sv_2mortal(newSVpv_utf8(pkg->summary, 0)));
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv_utf8(get_name(pkg->h, RPMTAG_SUMMARY), 0)));
+  }
+
+void
+Pkg_description(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv_utf8(get_name(pkg->h, RPMTAG_DESCRIPTION), 0)));
+  }
+
+void
+Pkg_sourcerpm(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_SOURCERPM), 0)));
+  }
+
+void
+Pkg_packager(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv_utf8(get_name(pkg->h, RPMTAG_PACKAGER), 0)));
+  }
+
+void
+Pkg_buildhost(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_BUILDHOST), 0)));
+  }
+
+int
+Pkg_buildtime(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->h) {
+    RETVAL = get_int(pkg->h, RPMTAG_BUILDTIME);
+  } else {
+    RETVAL = 0;
+  }
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_installtid(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->h) {
+    RETVAL = get_int(pkg->h, RPMTAG_INSTALLTID);
+  } else {
+    RETVAL = 0;
+  }
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_url(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_URL), 0)));
+  }
+
+void
+Pkg_license(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_LICENSE), 0)));
+  }
+
+void
+Pkg_distribution(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_DISTRIBUTION), 0)));
+  }
+
+void
+Pkg_vendor(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_VENDOR), 0)));
+  }
+
+void
+Pkg_os(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_OS), 0)));
+  }
+
+void
+Pkg_payload_format(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_PAYLOADFORMAT), 0)));
+  }
+
+void
+Pkg_fullname(pkg)
+  URPM::Package pkg
+  PREINIT:
+  I32 gimme = GIMME_V;
+  PPCODE:
+  if (pkg->info) {
+    if (gimme == G_SCALAR) {
+      char *eos;
+      if ((eos = strchr(pkg->info, '@')) != NULL) {
+	XPUSHs(sv_2mortal(newSVpv(pkg->info, eos-pkg->info)));
+      }
+    } else if (gimme == G_ARRAY) {
+      char *name, *version, *release, *arch, *eos;
+      get_fullname_parts(pkg, &name, &version, &release, &arch, &eos);
+      if (version - name < 1 || release - version < 1 || arch - release < 1)
+	  croak("invalid fullname");
+      EXTEND(SP, 4);
+      PUSHs(sv_2mortal(newSVpv(name, version-name-1)));
+      PUSHs(sv_2mortal(newSVpv(version, release-version-1)));
+      PUSHs(sv_2mortal(newSVpv(release, arch-release-1)));
+      PUSHs(sv_2mortal(newSVpv(arch, eos-arch)));
+    }
+  } else if (pkg->h) {
+    char *name = get_name(pkg->h, RPMTAG_NAME);
+    char *version = get_name(pkg->h, RPMTAG_VERSION);
+    char *release = get_name(pkg->h, RPMTAG_RELEASE);
+    char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src";
+
+    if (gimme == G_SCALAR) {
+      XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s", name, version, release, arch)));
+    } else if (gimme == G_ARRAY) {
+      EXTEND(SP, 4);
+      PUSHs(sv_2mortal(newSVpv(name, 0)));
+      PUSHs(sv_2mortal(newSVpv(version, 0)));
+      PUSHs(sv_2mortal(newSVpv(release, 0)));
+      PUSHs(sv_2mortal(newSVpv(arch, 0)));
+    }
+  }
+
+int
+Pkg_epoch(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->info) {
+    char *s, *eos;
+
+    if ((s = strchr(pkg->info, '@')) != NULL) {
+      if ((eos = strchr(s+1, '@')) != NULL) *eos = 0; /* mark end of string to enable searching backwards */
+      RETVAL = atoi(s+1);
+      if (eos != NULL) *eos = '@';
+    } else {
+      RETVAL = 0;
+    }
+  } else if (pkg->h) {
+    RETVAL = get_int(pkg->h, RPMTAG_EPOCH);
+  } else RETVAL = 0;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_compare_pkg(lpkg, rpkg)
+  URPM::Package lpkg
+  URPM::Package rpkg
+  PREINIT:
+  int compare = 0;
+  int lepoch;
+  char *lversion;
+  char *lrelease;
+  char *larch;
+  char *leos;
+  int repoch;
+  char *rversion;
+  char *rrelease;
+  char *rarch;
+  char *reos;
+  CODE:
+  if (lpkg == rpkg) RETVAL = 0;
+  else {
+    if (lpkg->info) {
+      char *s;
+
+      if ((s = strchr(lpkg->info, '@')) != NULL) {
+	if ((leos = strchr(s+1, '@')) != NULL) *leos = 0; /* mark end of string to enable searching backwards */
+	lepoch = atoi(s+1);
+	if (leos != NULL) *leos = '@';
+      } else {
+	lepoch = 0;
+      }
+      get_fullname_parts(lpkg, NULL, &lversion, &lrelease, &larch, &leos);
+      /* temporarily mark end of each substring */
+      lrelease[-1] = 0;
+      larch[-1] = 0;
+    } else if (lpkg->h) {
+      lepoch = get_int(lpkg->h, RPMTAG_EPOCH);
+      lversion = get_name(lpkg->h, RPMTAG_VERSION);
+      lrelease = get_name(lpkg->h, RPMTAG_RELEASE);
+      larch = headerIsEntry(lpkg->h, RPMTAG_SOURCERPM) ? get_name(lpkg->h, RPMTAG_ARCH) : "src";
+    } else croak("undefined package");
+    if (rpkg->info) {
+      char *s;
+
+      if ((s = strchr(rpkg->info, '@')) != NULL) {
+	if ((reos = strchr(s+1, '@')) != NULL) *reos = 0; /* mark end of string to enable searching backwards */
+	repoch = atoi(s+1);
+	if (reos != NULL) *reos = '@';
+      } else {
+	repoch = 0;
+      }
+      get_fullname_parts(rpkg, NULL, &rversion, &rrelease, &rarch, &reos);
+      /* temporarily mark end of each substring */
+      rrelease[-1] = 0;
+      rarch[-1] = 0;
+    } else if (rpkg->h) {
+      repoch = get_int(rpkg->h, RPMTAG_EPOCH);
+      rversion = get_name(rpkg->h, RPMTAG_VERSION);
+      rrelease = get_name(rpkg->h, RPMTAG_RELEASE);
+      rarch = headerIsEntry(rpkg->h, RPMTAG_SOURCERPM) ? get_name(rpkg->h, RPMTAG_ARCH) : "src";
+    } else {
+      /* restore info string modified */
+      if (lpkg->info) {
+	lrelease[-1] = '-';
+	larch[-1] = '.';
+      }
+      croak("undefined package");
+    }
+    compare = lepoch - repoch;
+    if (!compare) {
+      compare = rpmvercmp(lversion, rversion);
+      if (!compare) {
+	compare = rpmvercmp(lrelease, rrelease);
+	if (!compare) {
+	  int lscore, rscore;
+	  char *eolarch = strchr(larch, '@');
+	  char *eorarch = strchr(rarch, '@');
+
+	  read_config_files(0);
+	  if (eolarch) *eolarch = 0; lscore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, larch);
+	  if (eorarch) *eorarch = 0; rscore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, rarch);
+	  if (lscore == 0) {
+	    if (rscore == 0)
+#if 0
+              /* Nanar: TODO check this 
+               * hu ?? what is the goal of strcmp, some of arch are equivalent */
+              compare = 0
+#endif
+	      compare = strcmp(larch, rarch);
+	    else
+	      compare = -1;
+	  } else {
+	    if (rscore == 0)
+	      compare = 1;
+	    else
+	      compare = rscore - lscore; /* score are lower for better */
+	  }
+	  if (eolarch) *eolarch = '@';
+	  if (eorarch) *eorarch = '@';
+	}
+      }
+    }
+    /* restore info string modified */
+    if (lpkg->info) {
+      lrelease[-1] = '-';
+      larch[-1] = '.';
+    }
+    if (rpkg->info) {
+      rrelease[-1] = '-';
+      rarch[-1] = '.';
+    }
+    RETVAL = compare;
+  }
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_compare(pkg, evr)
+  URPM::Package pkg
+  char *evr
+  PREINIT:
+  int compare = 0;
+  int _epoch;
+  char *_version;
+  char *_release;
+  char *_eos;
+  CODE:
+  if (pkg->info) {
+    char *s;
+
+    if ((s = strchr(pkg->info, '@')) != NULL) {
+      if ((_eos = strchr(s+1, '@')) != NULL) *_eos = 0; /* mark end of string to enable searching backwards */
+      _epoch = atoi(s+1);
+      if (_eos != NULL) *_eos = '@';
+    } else {
+      _epoch = 0;
+    }
+    get_fullname_parts(pkg, NULL, &_version, &_release, &_eos, NULL);
+    /* temporarily mark end of each substring */
+    _release[-1] = 0;
+    _eos[-1] = 0;
+  } else if (pkg->h) {
+    _epoch = get_int(pkg->h, RPMTAG_EPOCH);
+  } else croak("undefined package");
+  if (!compare) {
+    char *epoch, *version, *release;
+
+    /* extract epoch and version from evr */
+    version = evr;
+    while (*version && isdigit(*version)) version++;
+    if (*version == ':') {
+      epoch = evr;
+      *version++ = 0;
+      if (!*epoch) epoch = "0";
+      compare = _epoch - (*epoch ? atoi(epoch) : 0);
+      version[-1] = ':'; /* restore in memory modification */
+    } else {
+      /* there is no epoch defined, so assume epoch = 0 */
+      version = evr;
+      compare = _epoch;
+    }
+    if (!compare) {
+      if (!pkg->info)
+	_version = get_name(pkg->h, RPMTAG_VERSION);
+      /* continue extracting release if any */
+      if ((release = strrchr(version, '-')) != NULL) {
+	*release++ = 0;
+	compare = rpmvercmp(_version, version);
+	if (!compare) {
+	  /* need to compare with release here */
+	  if (!pkg->info)
+	    _release = get_name(pkg->h, RPMTAG_RELEASE);
+	  compare = rpmvercmp(_release, release);
+	}
+	release[-1] = '-'; /* restore in memory modification */
+      } else {
+	compare = rpmvercmp(_version, version);
+      }
+    }
+  }
+  /* restore info string modified */
+  if (pkg->info) {
+    _release[-1] = '-';
+    _eos[-1] = '.';
+  }
+  RETVAL = compare;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_size(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->info) {
+    char *s, *eos;
+
+    if ((s = strchr(pkg->info, '@')) != NULL && (s = strchr(s+1, '@')) != NULL) {
+      if ((eos = strchr(s+1, '@')) != NULL) *eos = 0; /* mark end of string to enable searching backwards */
+      RETVAL = atoi(s+1);
+      if (eos != NULL) *eos = '@';
+    } else {
+      RETVAL = 0;
+    }
+  } else if (pkg->h) {
+    RETVAL = get_int(pkg->h, RPMTAG_SIZE);
+  } else RETVAL = 0;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_filesize(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->filesize) {
+    RETVAL = pkg->filesize;
+  } else if (pkg->h) {
+    RETVAL = sigsize_to_filesize(get_int(pkg->h, RPMTAG_SIGSIZE));
+  } else RETVAL = 0;
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_group(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *s;
+
+    if ((s = strchr(pkg->info, '@')) != NULL && (s = strchr(s+1, '@')) != NULL && (s = strchr(s+1, '@')) != NULL) {
+      char *eos = strchr(s+1, '@');
+      XPUSHs(sv_2mortal(newSVpv_utf8(s+1, eos != NULL ? eos-s-1 : 0)));
+    }
+  } else if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv_utf8(get_name(pkg->h, RPMTAG_GROUP), 0)));
+  }
+
+void
+Pkg_filename(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *eon;
+
+    if ((eon = strchr(pkg->info, '@')) != NULL) {
+	char savbuf[4];
+	memcpy(savbuf, eon, 4); /* there should be at least epoch and size described so (@0 at 0 minimum) */
+	memcpy(eon, ".rpm", 4);
+	XPUSHs(sv_2mortal(newSVpv(pkg->info, eon-pkg->info+4)));
+	memcpy(eon, savbuf, 4);
+    }
+  } else if (pkg->h) {
+    char *name = get_name(pkg->h, RPMTAG_NAME);
+    char *version = get_name(pkg->h, RPMTAG_VERSION);
+    char *release = get_name(pkg->h, RPMTAG_RELEASE);
+    char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src";
+
+    XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s.rpm", name, version, release, arch)));
+  }
+
+# deprecated
+void
+Pkg_header_filename(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->info) {
+    char *eon;
+
+    if ((eon = strchr(pkg->info, '@')) != NULL) {
+      XPUSHs(sv_2mortal(newSVpv(pkg->info, eon-pkg->info)));
+    }
+  } else if (pkg->h) {
+    char buff[1024];
+    char *p = buff;
+    char *name = get_name(pkg->h, RPMTAG_NAME);
+    char *version = get_name(pkg->h, RPMTAG_VERSION);
+    char *release = get_name(pkg->h, RPMTAG_RELEASE);
+    char *arch = headerIsEntry(pkg->h, RPMTAG_SOURCERPM) ? get_name(pkg->h, RPMTAG_ARCH) : "src";
+
+    p += snprintf(buff, sizeof(buff), "%s-%s-%s.%s", name, version, release, arch);
+    XPUSHs(sv_2mortal(newSVpv(buff, p-buff)));
+  }
+
+void
+Pkg_id(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if ((pkg->flag & FLAG_ID) <= FLAG_ID_MAX) {
+    XPUSHs(sv_2mortal(newSViv(pkg->flag & FLAG_ID)));
+  }
+
+void
+Pkg_set_id(pkg, id=-1)
+  URPM::Package pkg
+  int id
+  PPCODE:
+  if ((pkg->flag & FLAG_ID) <= FLAG_ID_MAX) {
+    XPUSHs(sv_2mortal(newSViv(pkg->flag & FLAG_ID)));
+  }
+  pkg->flag &= ~FLAG_ID;
+  pkg->flag |= id >= 0 && id <= FLAG_ID_MAX ? id : FLAG_ID_INVALID;
+
+void
+Pkg_requires(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->requires, pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, RPMTAG_REQUIREVERSION,
+		  callback_list_str_xpush_requires, NULL);
+  SPAGAIN;
+
+void
+Pkg_requires_nosense(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->requires, pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, 0, 
+		  callback_list_str_xpush_requires, NULL);
+  SPAGAIN;
+
+void
+Pkg_suggests(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  int count = return_list_str(pkg->suggests, pkg->h, RPMTAG_SUGGESTSNAME, 0, 0, callback_list_str_xpush, NULL);
+  if (count == 0)
+    return_list_str(pkg->suggests, pkg->h, RPMTAG_REQUIRENAME, RPMTAG_REQUIREFLAGS, 0,
+		    callback_list_str_xpush_old_suggests, NULL);
+  SPAGAIN;
+
+void
+Pkg_obsoletes(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->obsoletes, pkg->h, RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEFLAGS, RPMTAG_OBSOLETEVERSION,
+		  callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+void
+Pkg_obsoletes_nosense(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->obsoletes, pkg->h, RPMTAG_OBSOLETENAME, 0, 0, callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+int
+Pkg_obsoletes_overlap(pkg, s, b_nopromote=1, direction=-1)
+  URPM::Package pkg
+  char *s
+  int b_nopromote
+  int direction
+  PREINIT:
+  struct cb_overlap_s os;
+  char *eon = NULL;
+  char eonc = '\0';
+  CODE:
+  os.name = s;
+  os.flags = 0;
+  while (*s && *s != ' ' && *s != '[' && *s != '<' && *s != '>' && *s != '=') ++s;
+  if (*s) {
+    eon = s;
+    while (*s) {
+      if (*s == ' ' || *s == '[' || *s == '*' || *s == ']');
+      else if (*s == '<') os.flags |= RPMSENSE_LESS;
+      else if (*s == '>') os.flags |= RPMSENSE_GREATER;
+      else if (*s == '=') os.flags |= RPMSENSE_EQUAL;
+      else break;
+      ++s;
+    }
+    os.evr = s;
+  } else
+    os.evr = "";
+  os.direction = direction;
+  os.b_nopromote = b_nopromote;
+  /* mark end of name */
+  if (eon) { eonc = *eon; *eon = 0; }
+  /* return_list_str returns a negative value is the callback has returned non-zero */
+  RETVAL = return_list_str(pkg->obsoletes, pkg->h, RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEFLAGS, RPMTAG_OBSOLETEVERSION,
+			   callback_list_str_overlap, &os) < 0;
+  /* restore end of name */
+  if (eon) *eon = eonc;
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_conflicts(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->conflicts, pkg->h, RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTFLAGS, RPMTAG_CONFLICTVERSION,
+		  callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+void
+Pkg_conflicts_nosense(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->conflicts, pkg->h, RPMTAG_CONFLICTNAME, 0, 0, callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+void
+Pkg_provides(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->provides, pkg->h, RPMTAG_PROVIDENAME, RPMTAG_PROVIDEFLAGS, RPMTAG_PROVIDEVERSION,
+		  callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+void
+Pkg_provides_nosense(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_str(pkg->provides, pkg->h, RPMTAG_PROVIDENAME, 0, 0, callback_list_str_xpush, NULL);
+  SPAGAIN;
+
+int
+Pkg_provides_overlap(pkg, s, b_nopromote=1, direction=1)
+  URPM::Package pkg
+  char *s
+  int b_nopromote
+  int direction
+  PREINIT:
+  struct cb_overlap_s os;
+  char *eon = NULL;
+  char eonc = '\0';
+  CODE:
+  os.name = s;
+  os.flags = 0;
+  while (*s && *s != ' ' && *s != '[' && *s != '<' && *s != '>' && *s != '=') ++s;
+  if (*s) {
+    eon = s;
+    while (*s) {
+      if (*s == ' ' || *s == '[' || *s == '*' || *s == ']');
+      else if (*s == '<') os.flags |= RPMSENSE_LESS;
+      else if (*s == '>') os.flags |= RPMSENSE_GREATER;
+      else if (*s == '=') os.flags |= RPMSENSE_EQUAL;
+      else break;
+      ++s;
+    }
+    os.evr = s;
+  } else
+    os.evr = "";
+  os.direction = direction;
+  os.b_nopromote = b_nopromote;
+  /* mark end of name */
+  if (eon) { eonc = *eon; *eon = 0; }
+  /* return_list_str returns a negative value is the callback has returned non-zero */
+  RETVAL = return_list_str(pkg->provides, pkg->h, RPMTAG_PROVIDENAME, RPMTAG_PROVIDEFLAGS, RPMTAG_PROVIDEVERSION,
+			   callback_list_str_overlap, &os) < 0;
+  /* restore end of name */
+  if (eon) *eon = eonc;
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_buildarchs(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_BUILDARCHS);
+  SPAGAIN;
+  
+void
+Pkg_excludearchs(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_EXCLUDEARCH);
+  SPAGAIN;
+  
+void
+Pkg_exclusivearchs(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_EXCLUSIVEARCH);
+  SPAGAIN;
+  
+void
+Pkg_dirnames(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_DIRNAMES);
+  SPAGAIN;
+
+void Pkg_distepoch(pkg)
+  URPM::Package pkg
+  PPCODE:
+#ifdef RPMTAG_DISTEPOCH
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_DISTEPOCH), 0)));
+  }
+#else
+  croak("distepoch isn't available with this rpm version");
+#endif
+
+void Pkg_disttag(pkg)
+  URPM::Package pkg
+  PPCODE:
+  if (pkg->h) {
+    XPUSHs(sv_2mortal(newSVpv(get_name(pkg->h, RPMTAG_DISTTAG), 0)));
+  }
+
+void
+Pkg_filelinktos(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_FILELINKTOS);
+  SPAGAIN;
+
+void
+Pkg_files(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_files(pkg->h, 0);
+  SPAGAIN;
+
+void
+Pkg_files_md5sum(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_FILEMD5S);
+  SPAGAIN;
+
+void
+Pkg_files_owner(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_FILEUSERNAME);
+  SPAGAIN;
+
+void
+Pkg_files_group(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_FILEGROUPNAME);
+  SPAGAIN;
+
+void
+Pkg_files_mtime(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_FILEMTIMES);
+  SPAGAIN;
+
+void
+Pkg_files_size(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_FILESIZES);
+  SPAGAIN;
+
+void
+Pkg_files_uid(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_FILEUIDS);
+  SPAGAIN;
+
+void
+Pkg_files_gid(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_FILEGIDS);
+  SPAGAIN;
+
+void
+Pkg_files_mode(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_uint_16(pkg->h, RPMTAG_FILEMODES);
+  SPAGAIN;
+
+void
+Pkg_files_flags(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_FILEFLAGS);
+  SPAGAIN;
+  
+void
+Pkg_conf_files(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_files(pkg->h, FILTER_MODE_CONF_FILES);
+  SPAGAIN;
+
+void
+Pkg_changelog_time(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  return_list_int32_t(pkg->h, RPMTAG_CHANGELOGTIME);
+  SPAGAIN;
+
+void
+Pkg_changelog_name(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_CHANGELOGNAME);
+  SPAGAIN;
+
+void
+Pkg_changelog_text(pkg)
+  URPM::Package pkg
+  PPCODE:
+  PUTBACK;
+  xpush_simple_list_str(pkg->h, RPMTAG_CHANGELOGTEXT);
+  SPAGAIN;
+
+void
+Pkg_queryformat(pkg, fmt)
+  URPM::Package pkg
+  char *fmt
+  PREINIT:
+  char *s;
+  PPCODE:
+  if (pkg->h) {
+    s = headerFormat(pkg->h, fmt, NULL);
+      if (s) {
+        XPUSHs(sv_2mortal(newSVpv_utf8(s,0)));
+      }
+  }
+  
+void
+Pkg_get_tag(pkg, tagname)
+  URPM::Package pkg
+  int tagname;
+  PPCODE:
+  PUTBACK;
+  return_list_tag(pkg, tagname);
+  SPAGAIN;
+
+void
+Pkg_get_tag_modifiers(pkg, tagname)
+  URPM::Package pkg
+  int tagname;
+  PPCODE:
+  PUTBACK;
+  return_list_tag_modifier(pkg->h, tagname);
+  SPAGAIN;
+  
+void
+Pkg_pack_header(pkg)
+  URPM::Package pkg
+  CODE:
+  pack_header(pkg);
+
+int
+Pkg_update_header(pkg, filename, ...)
+  URPM::Package pkg
+  char *filename
+  PREINIT:
+  int packing = 0;
+  int keep_all_tags = 0;
+  CODE:
+  /* compability mode with older interface of parse_hdlist */
+  if (items == 3) {
+    packing = SvIV(ST(2));
+  } else if (items > 3) {
+    int i;
+    for (i = 2; i < items-1; i+=2) {
+      STRLEN len;
+      char *s = SvPV(ST(i), len);
+
+      if (len == 7 && !memcmp(s, "packing", 7)) {
+	packing = SvTRUE(ST(i + 1));
+      } else if (len == 13 && !memcmp(s, "keep_all_tags", 13)) {
+	keep_all_tags = SvTRUE(ST(i+1));
+      }
+    }
+  }
+  RETVAL = update_header(filename, pkg, !packing && keep_all_tags, RPMVSF_DEFAULT);
+  if (RETVAL && packing) pack_header(pkg);
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_free_header(pkg)
+  URPM::Package pkg
+  CODE:
+  if (pkg->h && !(pkg->flag & FLAG_NO_HEADER_FREE)) pkg->h = headerFree(pkg->h);
+  pkg->h = NULL;
+
+void
+Pkg_build_info(pkg, fileno, provides_files=NULL)
+  URPM::Package pkg
+  int fileno
+  char *provides_files
+  CODE:
+  if (pkg->info) {
+    char buff[65536];
+    size_t size;
+
+    /* info line should be the last to be written */
+    if (pkg->provides && *pkg->provides) {
+      size = snprintf(buff, sizeof(buff), "@provides@%s\n", pkg->provides);
+      if (size < sizeof(buff)) {
+	if (provides_files && *provides_files) {
+	  --size;
+	  size += snprintf(buff+size, sizeof(buff)-size, "@%s\n", provides_files);
+	}
+	write_nocheck(fileno, buff, size);
+      }
+    }
+    if (pkg->conflicts && *pkg->conflicts) {
+      size = snprintf(buff, sizeof(buff), "@conflicts@%s\n", pkg->conflicts);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    if (pkg->obsoletes && *pkg->obsoletes) {
+      size = snprintf(buff, sizeof(buff), "@obsoletes@%s\n", pkg->obsoletes);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    if (pkg->requires && *pkg->requires) {
+      size = snprintf(buff, sizeof(buff), "@requires@%s\n", pkg->requires);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    if (pkg->suggests && *pkg->suggests) {
+      size = snprintf(buff, sizeof(buff), "@suggests@%s\n", pkg->suggests);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    if (pkg->summary && *pkg->summary) {
+      size = snprintf(buff, sizeof(buff), "@summary@%s\n", pkg->summary);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    if (pkg->filesize) {
+      size = snprintf(buff, sizeof(buff), "@filesize@%d\n", pkg->filesize);
+      if (size < sizeof(buff)) write_nocheck(fileno, buff, size);
+    }
+    size = snprintf(buff, sizeof(buff), "@info@%s\n", pkg->info);
+    write_nocheck(fileno, buff, size);
+  } else croak("no info available for package %s",
+	  pkg->h ? get_name(pkg->h, RPMTAG_NAME) : "-");
+
+void
+Pkg_build_header(pkg, fileno)
+  URPM::Package pkg
+  int fileno
+  CODE:
+  if (pkg->h) {
+    FD_t fd;
+
+    if ((fd = fdDup(fileno)) != NULL) {
+      headerWrite(fd, pkg->h, HEADER_MAGIC_YES);
+      Fclose(fd);
+    } else croak("unable to get rpmio handle on fileno %d", fileno);
+  } else croak("no header available for package");
+
+int
+Pkg_flag(pkg, name)
+  URPM::Package pkg
+  char *name
+  PREINIT:
+  unsigned mask;
+  CODE:
+  if (!strcmp(name, "skip")) mask = FLAG_SKIP;
+  else if (!strcmp(name, "disable_obsolete")) mask = FLAG_DISABLE_OBSOLETE;
+  else if (!strcmp(name, "installed")) mask = FLAG_INSTALLED;
+  else if (!strcmp(name, "requested")) mask = FLAG_REQUESTED;
+  else if (!strcmp(name, "required")) mask = FLAG_REQUIRED;
+  else if (!strcmp(name, "upgrade")) mask = FLAG_UPGRADE;
+  else croak("unknown flag: %s", name);
+  RETVAL = pkg->flag & mask;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag(pkg, name, value=1)
+  URPM::Package pkg
+  char *name
+  int value
+  PREINIT:
+  unsigned mask;
+  CODE:
+  if (!strcmp(name, "skip")) mask = FLAG_SKIP;
+  else if (!strcmp(name, "disable_obsolete")) mask = FLAG_DISABLE_OBSOLETE;
+  else if (!strcmp(name, "installed")) mask = FLAG_INSTALLED;
+  else if (!strcmp(name, "requested")) mask = FLAG_REQUESTED;
+  else if (!strcmp(name, "required")) mask = FLAG_REQUIRED;
+  else if (!strcmp(name, "upgrade")) mask = FLAG_UPGRADE;
+  else croak("unknown flag: %s", name);
+  RETVAL = pkg->flag & mask;
+  if (value) pkg->flag |= mask;
+  else       pkg->flag &= ~mask;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_skip(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_SKIP;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_skip(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_SKIP;
+  if (value) pkg->flag |= FLAG_SKIP;
+  else       pkg->flag &= ~FLAG_SKIP;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_base(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_BASE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_base(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_BASE;
+  if (value) pkg->flag |= FLAG_BASE;
+  else       pkg->flag &= ~FLAG_BASE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_disable_obsolete(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_DISABLE_OBSOLETE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_disable_obsolete(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_DISABLE_OBSOLETE;
+  if (value) pkg->flag |= FLAG_DISABLE_OBSOLETE;
+  else       pkg->flag &= ~FLAG_DISABLE_OBSOLETE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_installed(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_INSTALLED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_installed(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_INSTALLED;
+  if (value) pkg->flag |= FLAG_INSTALLED;
+  else       pkg->flag &= ~FLAG_INSTALLED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_requested(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_REQUESTED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_requested(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_REQUESTED;
+  if (value) pkg->flag |= FLAG_REQUESTED;
+  else       pkg->flag &= ~FLAG_REQUESTED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_required(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_REQUIRED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_required(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_REQUIRED;
+  if (value) pkg->flag |= FLAG_REQUIRED;
+  else       pkg->flag &= ~FLAG_REQUIRED;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_upgrade(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_UPGRADE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_flag_upgrade(pkg, value=1)
+  URPM::Package pkg
+  int value
+  CODE:
+  RETVAL = pkg->flag & FLAG_UPGRADE;
+  if (value) pkg->flag |= FLAG_UPGRADE;
+  else       pkg->flag &= ~FLAG_UPGRADE;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_selected(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = pkg->flag & FLAG_UPGRADE ? pkg->flag & (FLAG_BASE | FLAG_REQUIRED) : 0;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_flag_available(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = (pkg->flag & FLAG_INSTALLED && !(pkg->flag & FLAG_UPGRADE)) ||
+           (pkg->flag & FLAG_UPGRADE ? pkg->flag & (FLAG_BASE | FLAG_REQUIRED) : 0);
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_rate(pkg)
+  URPM::Package pkg
+  CODE:
+  RETVAL = (pkg->flag & FLAG_RATE) >> FLAG_RATE_POS;
+  OUTPUT:
+  RETVAL
+
+int
+Pkg_set_rate(pkg, rate)
+  URPM::Package pkg
+  int rate
+  CODE:
+  RETVAL = (pkg->flag & FLAG_RATE) >> FLAG_RATE_POS;
+  pkg->flag &= ~FLAG_RATE;
+  pkg->flag |= (rate >= 0 && rate <= FLAG_RATE_MAX ? rate : FLAG_RATE_INVALID) << FLAG_RATE_POS;
+  OUTPUT:
+  RETVAL
+
+void
+Pkg_rflags(pkg)
+  URPM::Package pkg
+  PREINIT:
+  I32 gimme = GIMME_V;
+  PPCODE:
+  if (gimme == G_ARRAY && pkg->rflags != NULL) {
+    char *s = pkg->rflags;
+    char *eos;
+    while ((eos = strchr(s, '\t')) != NULL) {
+      XPUSHs(sv_2mortal(newSVpv(s, eos-s)));
+      s = eos + 1;
+    }
+    XPUSHs(sv_2mortal(newSVpv(s, 0)));
+  }
+
+void
+Pkg_set_rflags(pkg, ...)
+  URPM::Package pkg
+  PREINIT:
+  I32 gimme = GIMME_V;
+  char *new_rflags;
+  STRLEN total_len;
+  int i;
+  PPCODE:
+  total_len = 0;
+  for (i = 1; i < items; ++i)
+    total_len += SvCUR(ST(i)) + 1;
+
+  new_rflags = malloc(total_len);
+  total_len = 0;
+  for (i = 1; i < items; ++i) {
+    STRLEN len;
+    char *s = SvPV(ST(i), len);
+    memcpy(new_rflags + total_len, s, len);
+    new_rflags[total_len + len] = '\t';
+    total_len += len + 1;
+  }
+  new_rflags[total_len - 1] = 0; /* but mark end-of-string correctly */
+
+  if (gimme == G_ARRAY && pkg->rflags != NULL) {
+    char *s = pkg->rflags;
+    char *eos;
+    while ((eos = strchr(s, '\t')) != NULL) {
+      XPUSHs(sv_2mortal(newSVpv(s, eos-s)));
+      s = eos + 1;
+    }
+    XPUSHs(sv_2mortal(newSVpv(s, 0)));
+  }
+
+  free(pkg->rflags);
+  pkg->rflags = new_rflags;
+
+
+MODULE = URPM            PACKAGE = URPM::DB            PREFIX = Db_
+
+URPM::DB
+Db_open(prefix=NULL, write_perm=0)
+  char *prefix
+  int write_perm
+  PREINIT:
+  URPM__DB db;
+  CODE:
+  read_config_files(0);
+  db = malloc(sizeof(struct s_Transaction));
+  db->count = 1;
+  db->ts = rpmtsCreate();
+  rpmtsSetRootDir(db->ts, prefix && prefix[0] ? prefix : NULL);
+  if (rpmtsOpenDB(db->ts, write_perm ? O_RDWR | O_CREAT : O_RDONLY) == 0) {
+    RETVAL = db;
+  } else {
+    RETVAL = NULL;
+    (void)rpmtsFree(db->ts);
+    free(db);
+  }
+  OUTPUT:
+  RETVAL
+
+int
+Db_rebuild(prefix="")
+  char *prefix
+  PREINIT:
+  rpmts ts;
+  CODE:
+  read_config_files(0);
+  ts = rpmtsCreate();
+  rpmtsSetRootDir(ts, prefix);
+  RETVAL = rpmtsRebuildDB(ts) == 0;
+  (void)rpmtsFree(ts);
+  OUTPUT:
+  RETVAL
+
+int
+Db_verify(prefix="")
+  char *prefix
+  PREINIT:
+  rpmts ts;
+  CODE:
+  ts = rpmtsCreate();
+  rpmtsSetRootDir(ts, prefix);
+  RETVAL = rpmtsVerifyDB(ts) == 0;
+  ts = rpmtsFree(ts);
+  OUTPUT:
+  RETVAL
+
+void
+Db_DESTROY(db)
+  URPM::DB db
+  CODE:
+  (void)rpmtsFree(db->ts);
+  if (!--db->count) free(db);
+
+int
+Db_traverse(db,callback)
+  URPM::DB db
+  SV *callback
+  PREINIT:
+  Header header;
+  rpmdbMatchIterator mi;
+  int count = 0;
+  CODE:
+  db->ts = rpmtsLink(db->ts, "URPM::DB::traverse");
+  ts_nosignature(db->ts);
+  mi = rpmtsInitIterator(db->ts, RPMDBI_PACKAGES, NULL, 0);
+  while ((header = rpmdbNextIterator(mi))) {
+    if (SvROK(callback)) {
+      dSP;
+      URPM__Package pkg = calloc(1, sizeof(struct s_Package));
+
+      pkg->flag = FLAG_ID_INVALID | FLAG_NO_HEADER_FREE;
+      pkg->h = header;
+
+      PUSHMARK(SP);
+      XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), "URPM::Package", pkg)));
+      PUTBACK;
+
+      call_sv(callback, G_DISCARD | G_SCALAR);
+
+      SPAGAIN;
+      pkg->h = 0; /* avoid using it anymore, in case it has been copied inside callback */
+    }
+    ++count;
+  }
+  rpmdbFreeIterator(mi);
+  (void)rpmtsFree(db->ts);
+  RETVAL = count;
+  OUTPUT:
+  RETVAL
+
+int
+Db_traverse_tag(db,tag,names,callback)
+  URPM::DB db
+  char *tag
+  SV *names
+  SV *callback
+  PREINIT:
+  Header header;
+  rpmdbMatchIterator mi;
+  int count = 0;
+  CODE:
+  if (SvROK(names) && SvTYPE(SvRV(names)) == SVt_PVAV) {
+    AV* names_av = (AV*)SvRV(names);
+    int len = av_len(names_av);
+    int i, rpmtag;
+
+    rpmtag = rpmtag_from_string(tag);
+
+    for (i = 0; i <= len; ++i) {
+      STRLEN str_len;
+      SV **isv = av_fetch(names_av, i, 0);
+      char *name = SvPV(*isv, str_len);
+      db->ts = rpmtsLink(db->ts, "URPM::DB::traverse_tag");
+      ts_nosignature(db->ts);
+      mi = rpmtsInitIterator(db->ts, rpmtag, name, str_len);
+      while ((header = rpmdbNextIterator(mi))) {
+	if (SvROK(callback)) {
+	  dSP;
+	  URPM__Package pkg = calloc(1, sizeof(struct s_Package));
+
+	  pkg->flag = FLAG_ID_INVALID | FLAG_NO_HEADER_FREE;
+	  pkg->h = header;
+
+	  PUSHMARK(SP);
+	  XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), "URPM::Package", pkg)));
+	  PUTBACK;
+
+	  call_sv(callback, G_DISCARD | G_SCALAR);
+
+	  SPAGAIN;
+	  pkg->h = 0; /* avoid using it anymore, in case it has been copied inside callback */
+	}
+	++count;
+      }
+      (void)rpmdbFreeIterator(mi);
+      (void)rpmtsFree(db->ts);
+    } 
+  } else croak("bad arguments list");
+  RETVAL = count;
+  OUTPUT:
+  RETVAL
+
+int
+Db_traverse_tag_find(db,tag,name,callback)
+  URPM::DB db
+  char *tag
+  char *name
+  SV *callback
+  PREINIT:
+  Header header;
+  rpmdbMatchIterator mi;
+  CODE:
+  int rpmtag = rpmtag_from_string(tag);
+  int found = 0;
+
+  db->ts = rpmtsLink(db->ts, "URPM::DB::traverse_tag");
+  ts_nosignature(db->ts);
+  mi = rpmtsInitIterator(db->ts, rpmtag, name, 0);
+  while ((header = rpmdbNextIterator(mi))) {
+      dSP;
+      URPM__Package pkg = calloc(1, sizeof(struct s_Package));
+
+      pkg->flag = FLAG_ID_INVALID | FLAG_NO_HEADER_FREE;
+      pkg->h = header;
+
+      PUSHMARK(SP);
+      XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), "URPM::Package", pkg)));
+      PUTBACK;
+
+      int count = call_sv(callback, G_SCALAR);
+
+      SPAGAIN;
+      pkg->h = 0; /* avoid using it anymore, in case it has been copied inside callback */
+
+      if (count == 1 && POPi) {
+	found = 1;
+	break;
+      }
+  }
+  (void)rpmdbFreeIterator(mi);
+  (void)rpmtsFree(db->ts);
+  RETVAL = found;
+  OUTPUT:
+  RETVAL
+
+URPM::Transaction
+Db_create_transaction(db, prefix="/")
+  URPM::DB db
+  char *prefix
+  CODE:
+  /* this is *REALLY* dangerous to create a new transaction while another is open,
+     so use the db transaction instead. */
+  db->ts = rpmtsLink(db->ts, "URPM::DB::create_transaction");
+  ++db->count;
+  RETVAL = db;
+  OUTPUT:
+  RETVAL
+
+
+MODULE = URPM            PACKAGE = URPM::Transaction   PREFIX = Trans_
+
+void
+Trans_DESTROY(trans)
+  URPM::Transaction trans
+  CODE:
+  (void)rpmtsFree(trans->ts);
+  if (!--trans->count) free(trans);
+
+void
+Trans_set_script_fd(trans, fdno)
+  URPM::Transaction trans
+  int fdno
+  CODE:
+  rpmtsSetScriptFd(trans->ts, fdDup(fdno));
+
+int
+Trans_add(trans, pkg, ...)
+  URPM::Transaction trans
+  URPM::Package pkg
+  CODE:
+  if ((pkg->flag & FLAG_ID) <= FLAG_ID_MAX && pkg->h != NULL) {
+    int update = 0;
+#ifndef RPM_ORG
+    rpmRelocation  relocations = NULL;
+#else
+    rpmRelocation *relocations = NULL;
+#endif
+    /* compability mode with older interface of add */
+    if (items == 3) {
+      update = SvIV(ST(2));
+    } else if (items > 3) {
+      int i;
+      for (i = 2; i < items-1; i+=2) {
+	STRLEN len;
+	char *s = SvPV(ST(i), len);
+
+	if (len == 6 && !memcmp(s, "update", 6)) {
+	  update = SvIV(ST(i+1));
+	} else if (len == 11 && !memcmp(s, "excludepath", 11)) {
+	  if (SvROK(ST(i+1)) && SvTYPE(SvRV(ST(i+1))) == SVt_PVAV) {
+	    AV *excludepath = (AV*)SvRV(ST(i+1));
+	    I32 j = 1 + av_len(excludepath);
+#ifndef RPM_ORG
+	    int relno = 0;
+	    relocations = malloc(sizeof(rpmRelocation));
+#else
+	    relocations = calloc(j + 1, sizeof(rpmRelocation));
+#endif
+	    while (--j >= 0) {
+	      SV **e = av_fetch(excludepath, j, 0);
+	      if (e != NULL && *e != NULL) {
+#ifndef RPM_ORG
+		rpmfiAddRelocation(&relocations, &relno, SvPV_nolen(*e), NULL);
+#else
+		relocations[j].oldPath = SvPV_nolen(*e);
+#endif
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    RETVAL = rpmtsAddInstallElement(trans->ts, pkg->h, (fnpyKey)(1+(long)(pkg->flag & FLAG_ID)), update, relocations) == 0;
+    /* free allocated memory, check rpm is copying it just above, at least in 4.0.4 */
+#ifndef RPM_ORG
+    rpmfiFreeRelocations(relocations);
+#else
+    free(relocations);
+#endif
+  } else RETVAL = 0;
+  OUTPUT:
+  RETVAL
+
+int
+Trans_remove(trans, name)
+  URPM::Transaction trans
+  char *name
+  PREINIT:
+  Header h;
+  rpmdbMatchIterator mi;
+  int count = 0;
+  char *boa = NULL, *bor = NULL;
+  CODE:
+  /* hide arch in name if present */
+  if ((boa = strrchr(name, '.'))) {
+    *boa = 0;
+    if ((bor = strrchr(name, '-'))) {
+      *bor = 0;
+      if (!strrchr(name, '-')) {
+	*boa = '.'; boa = NULL;
+      }
+      *bor = '-'; bor = NULL;
+    } else {
+      *boa = '.'; boa = NULL;
+    }
+  }
+  mi = rpmtsInitIterator(trans->ts, RPMDBI_LABEL, name, 0);
+  while ((h = rpmdbNextIterator(mi))) {
+    unsigned int recOffset = rpmdbGetIteratorOffset(mi);
+    if (recOffset != 0) {
+      rpmtsAddEraseElement(trans->ts, h, recOffset);
+      ++count;
+    }
+  }
+  rpmdbFreeIterator(mi);
+  if (boa) *boa = '.';
+  RETVAL=count;
+  OUTPUT:
+  RETVAL
+
+int
+Trans_traverse(trans, callback)
+  URPM::Transaction trans
+  SV *callback
+  PREINIT:
+  rpmdbMatchIterator mi;
+  Header h;
+  int c = 0;
+  CODE:
+  mi = rpmtsInitIterator(trans->ts, RPMDBI_PACKAGES, NULL, 0);
+  while ((h = rpmdbNextIterator(mi))) {
+    if (SvROK(callback)) {
+      dSP;
+      URPM__Package pkg = calloc(1, sizeof(struct s_Package));
+      pkg->flag = FLAG_ID_INVALID | FLAG_NO_HEADER_FREE;
+      pkg->h = h;
+      PUSHMARK(SP);
+      XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), "URPM::Package", pkg)));
+      PUTBACK;
+      call_sv(callback, G_DISCARD | G_SCALAR);
+      SPAGAIN;
+      pkg->h = 0; /* avoid using it anymore, in case it has been copied inside callback */
+    }
+    ++c;
+  }
+  rpmdbFreeIterator(mi);
+  RETVAL = c;
+  OUTPUT:
+  RETVAL
+
+void
+Trans_check(trans, ...)
+  URPM::Transaction trans
+  PREINIT:
+  I32 gimme = GIMME_V;
+  int translate_message = 0;
+  int i;
+  PPCODE:
+  for (i = 1; i < items-1; i+=2) {
+    STRLEN len;
+    char *s = SvPV(ST(i), len);
+
+    if (len == 17 && !memcmp(s, "translate_message", 17)) {
+      translate_message = SvIV(ST(i+1));
+    }
+  }
+  if (rpmtsCheck(trans->ts)) {
+    if (gimme == G_SCALAR) {
+      XPUSHs(sv_2mortal(newSViv(0)));
+    } else if (gimme == G_ARRAY) {
+      XPUSHs(sv_2mortal(newSVpv("error while checking dependencies", 0)));
+    }
+  } else {
+    rpmps ps = rpmtsProblems(trans->ts);
+    if (rpmpsNumProblems(ps) > 0) {
+      if (gimme == G_SCALAR) {
+	XPUSHs(sv_2mortal(newSViv(0)));
+      } else if (gimme == G_ARRAY) {
+	/* now translation is handled by rpmlib, but only for version 4.2 and above */
+	PUTBACK;
+	return_problems(ps, 1, 0);
+	SPAGAIN;
+      }
+    } else if (gimme == G_SCALAR) {
+      XPUSHs(sv_2mortal(newSViv(1)));
+    }
+    ps = rpmpsFree(ps);
+  }
+
+void
+Trans_order(trans)
+  URPM::Transaction trans
+  PREINIT:
+  I32 gimme = GIMME_V;
+  PPCODE:
+  if (rpmtsOrder(trans->ts) == 0) {
+    if (gimme == G_SCALAR) {
+      XPUSHs(sv_2mortal(newSViv(1)));
+    }
+  } else {
+    if (gimme == G_SCALAR) {
+      XPUSHs(sv_2mortal(newSViv(0)));
+    } else if (gimme == G_ARRAY) {
+      XPUSHs(sv_2mortal(newSVpv("error while ordering dependencies", 0)));
+    }
+  }
+
+int
+Trans_NElements(trans)
+  URPM::Transaction trans
+  CODE:
+  RETVAL = rpmtsNElements(trans->ts);
+  OUTPUT:
+  RETVAL
+
+char *
+Trans_Element_name(trans, index)
+  URPM::Transaction trans
+  int index
+  CODE:
+  rpmte te = rpmtsElement(trans->ts, index);
+  RETVAL = te ? (char *) rpmteN(te) : NULL;
+  OUTPUT:
+  RETVAL
+
+char *
+Trans_Element_version(trans, index)
+  URPM::Transaction trans
+  int index
+  CODE:
+  rpmte te = rpmtsElement(trans->ts, index);
+  RETVAL = te ? (char *) rpmteV(te) : NULL;
+  OUTPUT:
+  RETVAL
+
+char *
+Trans_Element_release(trans, index)
+  URPM::Transaction trans
+  int index
+  CODE:
+  rpmte te = rpmtsElement(trans->ts, index);
+  RETVAL = te ? (char *) rpmteR(te) : NULL;
+  OUTPUT:
+  RETVAL
+
+char *
+Trans_Element_fullname(trans, index)
+  URPM::Transaction trans
+  int index
+  CODE:
+  rpmte te = rpmtsElement(trans->ts, index);
+  RETVAL = te ? (char *) rpmteNEVRA(te) : NULL;
+  OUTPUT:
+  RETVAL
+
+void
+Trans_run(trans, data, ...)
+  URPM::Transaction trans
+  SV *data
+  PREINIT:
+  struct s_TransactionData td = { NULL, NULL, NULL, NULL, NULL, 100000, data };
+  rpmtransFlags transFlags = RPMTRANS_FLAG_NONE;
+  int probFilter = 0;
+  int translate_message = 0, raw_message = 0;
+  int i;
+  PPCODE:
+  for (i = 2 ; i < items - 1 ; i += 2) {
+    STRLEN len;
+    char *s = SvPV(ST(i), len);
+
+    if (len == 4 && !memcmp(s, "test", 4)) {
+      if (SvIV(ST(i+1))) transFlags |= RPMTRANS_FLAG_TEST;
+    } else if (len == 11 && !memcmp(s, "excludedocs", 11)) {
+      if (SvIV(ST(i+1))) transFlags |= RPMTRANS_FLAG_NODOCS;
+    } else if (len == 5) {
+      if (!memcmp(s, "force", 5)) {
+	if (SvIV(ST(i+1))) probFilter |= (RPMPROB_FILTER_REPLACEPKG |
+					  RPMPROB_FILTER_REPLACEOLDFILES |
+					  RPMPROB_FILTER_REPLACENEWFILES |
+					  RPMPROB_FILTER_OLDPACKAGE);
+      } else if (!memcmp(s, "delta", 5))
+	td.min_delta = SvIV(ST(i+1));
+    } else if (len == 6 && !memcmp(s, "nosize", 6)) {
+      if (SvIV(ST(i+1))) probFilter |= (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES);
+    } else if (len == 9 && !memcmp(s, "noscripts", 9)) {
+      if (SvIV(ST(i+1))) transFlags |= (RPMTRANS_FLAG_NOSCRIPTS |
+				        RPMTRANS_FLAG_NOPRE |
+				        RPMTRANS_FLAG_NOPREUN |
+				        RPMTRANS_FLAG_NOPOST |
+				        RPMTRANS_FLAG_NOPOSTUN );
+    } else if (len == 10 && !memcmp(s, "oldpackage", 10)) {
+      if (SvIV(ST(i+1))) probFilter |= RPMPROB_FILTER_OLDPACKAGE;
+    } else if (len == 11 && !memcmp(s, "replacepkgs", 11)) {
+      if (SvIV(ST(i+1))) probFilter |= RPMPROB_FILTER_REPLACEPKG;
+    } else if (len == 11 && !memcmp(s, "raw_message", 11)) {
+      raw_message = 1;
+    } else if (len == 12 && !memcmp(s, "replacefiles", 12)) {
+      if (SvIV(ST(i+1))) probFilter |= RPMPROB_FILTER_REPLACEOLDFILES | RPMPROB_FILTER_REPLACENEWFILES;
+    } else if (len == 9 && !memcmp(s, "repackage", 9)) {
+      if (SvIV(ST(i+1))) transFlags |= RPMTRANS_FLAG_REPACKAGE;
+    } else if (len == 6 && !memcmp(s, "justdb", 6)) {
+      if (SvIV(ST(i+1))) transFlags |= RPMTRANS_FLAG_JUSTDB;
+    } else if (len == 10 && !memcmp(s, "ignorearch", 10)) {
+      if (SvIV(ST(i+1))) probFilter |= RPMPROB_FILTER_IGNOREARCH;
+    } else if (len == 17 && !memcmp(s, "translate_message", 17))
+      translate_message = 1;
+    else if (len >= 9 && !memcmp(s, "callback_", 9)) {
+      if (len == 9+4 && !memcmp(s+9, "open", 4)) {
+	if (SvROK(ST(i+1))) td.callback_open = ST(i+1);
+      } else if (len == 9+5 && !memcmp(s+9, "close", 5)) {
+	if (SvROK(ST(i+1))) td.callback_close = ST(i+1);
+      } else if (len == 9+5 && !memcmp(s+9, "trans", 5)) {
+	if (SvROK(ST(i+1))) td.callback_trans = ST(i+1);
+      } else if (len == 9+6 && !memcmp(s+9, "uninst", 6)) {
+	if (SvROK(ST(i+1))) td.callback_uninst = ST(i+1);
+      } else if (len == 9+4 && !memcmp(s+9, "inst", 4)) {
+	if (SvROK(ST(i+1))) td.callback_inst = ST(i+1);
+      }
+    }
+  }
+  /* check macros */
+  {
+    char *repa = rpmExpand("%_repackage_all_erasures", NULL);
+    if (repa && *repa && *repa != '0')
+      transFlags |= RPMTRANS_FLAG_REPACKAGE;
+    if (repa) free(repa);
+  }
+  rpmtsSetFlags(trans->ts, transFlags);
+  trans->ts = rpmtsLink(trans->ts, "URPM::Transaction::run");
+  rpmtsSetNotifyCallback(trans->ts, rpmRunTransactions_callback, &td);
+  if (rpmtsRun(trans->ts, NULL, probFilter) > 0) {
+    rpmps ps = rpmtsProblems(trans->ts);
+    PUTBACK;
+    return_problems(ps, translate_message, raw_message || !translate_message);
+    SPAGAIN;
+    ps = rpmpsFree(ps);
+  }
+  rpmtsEmpty(trans->ts);
+  (void)rpmtsFree(trans->ts);
+
+MODULE = URPM            PACKAGE = URPM                PREFIX = Urpm_
+
+BOOT:
+(void) read_config_files(0);
+
+void
+Urpm_bind_rpm_textdomain_codeset()
+  CODE:
+  rpm_codeset_is_utf8 = 1;
+  bind_textdomain_codeset("rpm", "UTF-8");
+
+int
+Urpm_read_config_files()
+  CODE:
+  RETVAL = (read_config_files(1) == 0); /* force re-read of configuration files */
+  OUTPUT:
+  RETVAL
+
+void
+Urpm_list_rpm_tag(urpm=Nullsv)
+   SV *urpm
+   CODE:
+   croak("list_rpm_tag() has been removed from perl-URPM. please report if you need it back");
+
+int
+rpmvercmp(one, two)
+    char *one
+    char *two        
+       
+int
+Urpm_ranges_overlap(a, b, b_nopromote=1)
+  char *a
+  char *b
+  int b_nopromote
+  PREINIT:
+  char *sa = a, *sb = b;
+  int aflags = 0, bflags = 0;
+  CODE:
+  while (*sa && *sa != ' ' && *sa != '[' && *sa != '<' && *sa != '>' && *sa != '=' && *sa == *sb) {
+    ++sa;
+    ++sb;
+  }
+  if ((*sa && *sa != ' ' && *sa != '[' && *sa != '<' && *sa != '>' && *sa != '=') ||
+      (*sb && *sb != ' ' && *sb != '[' && *sb != '<' && *sb != '>' && *sb != '=')) {
+    /* the strings are sure to be different */
+    RETVAL = 0;
+  } else {
+    while (*sa) {
+      if (*sa == ' ' || *sa == '[' || *sa == '*' || *sa == ']');
+      else if (*sa == '<') aflags |= RPMSENSE_LESS;
+      else if (*sa == '>') aflags |= RPMSENSE_GREATER;
+      else if (*sa == '=') aflags |= RPMSENSE_EQUAL;
+      else break;
+      ++sa;
+    }
+    while (*sb) {
+      if (*sb == ' ' || *sb == '[' || *sb == '*' || *sb == ']');
+      else if (*sb == '<') bflags |= RPMSENSE_LESS;
+      else if (*sb == '>') bflags |= RPMSENSE_GREATER;
+      else if (*sb == '=') bflags |= RPMSENSE_EQUAL;
+      else break;
+      ++sb;
+    }
+    RETVAL = ranges_overlap(aflags, sa, bflags, sb, b_nopromote);
+  }
+  OUTPUT:
+  RETVAL
+
+void
+Urpm_parse_synthesis__XS(urpm, filename, ...)
+  SV *urpm
+  char *filename
+  PPCODE:
+  if (SvROK(urpm) && SvTYPE(SvRV(urpm)) == SVt_PVHV) {
+    SV **fdepslist = hv_fetch((HV*)SvRV(urpm), "depslist", 8, 0);
+    AV *depslist = fdepslist && SvROK(*fdepslist) && SvTYPE(SvRV(*fdepslist)) == SVt_PVAV ? (AV*)SvRV(*fdepslist) : NULL;
+    SV **fprovides = hv_fetch((HV*)SvRV(urpm), "provides", 8, 0);
+    HV *provides = fprovides && SvROK(*fprovides) && SvTYPE(SvRV(*fprovides)) == SVt_PVHV ? (HV*)SvRV(*fprovides) : NULL;
+    SV **fobsoletes = hv_fetch((HV*)SvRV(urpm), "obsoletes", 9, 0);
+    HV *obsoletes = fobsoletes && SvROK(*fobsoletes) && SvTYPE(SvRV(*fobsoletes)) == SVt_PVHV ? (HV*)SvRV(*fobsoletes) : NULL;
+
+    if (depslist != NULL) {
+      char buff[65536];
+      char *p, *eol;
+      int buff_len;
+      struct s_Package pkg;
+      gzFile f;
+      int start_id = 1 + av_len(depslist);
+      SV *callback = NULL;
+
+      if (items > 2) {
+	int i;
+	for (i = 2; i < items-1; i+=2) {
+	  STRLEN len;
+	  char *s = SvPV(ST(i), len);
+
+	  if (len == 8 && !memcmp(s, "callback", 8)) {
+	    if (SvROK(ST(i+1))) callback = ST(i+1);
+	  }
+	}
+      }
+
+      PUTBACK;
+      if ((f = gzopen(filename, "rb")) != NULL) {
+	memset(&pkg, 0, sizeof(struct s_Package));
+	buff[sizeof(buff)-1] = 0;
+	p = buff;
+	int ok = 1;
+	while ((buff_len = gzread(f, p, sizeof(buff)-1-(p-buff))) >= 0 &&
+	       (buff_len += p-buff)) {
+	  buff[buff_len] = 0;
+	  p = buff;
+	  if ((eol = strchr(p, '\n')) != NULL) {
+	    do {
+	      *eol++ = 0;
+	      if (!parse_line(depslist, provides, obsoletes, &pkg, p, urpm, callback)) { ok = 0; break; }
+	      p = eol;
+	    } while ((eol = strchr(p, '\n')) != NULL);
+	  } else {
+	    /* a line larger than sizeof(buff) has been encountered, bad file problably */
+	    fprintf(stderr, "invalid line <%s>\n", p);
+	    ok = 0;
+	    break;
+	  }
+	  if (gzeof(f)) {
+	    if (!parse_line(depslist, provides, obsoletes, &pkg, p, urpm, callback)) ok = 0;
+	    break;
+	  } else {
+	    /* move the remaining non-complete-line at beginning */
+	    memmove(buff, p, buff_len-(p-buff));
+	    /* point to the end of the non-complete-line */
+	    p = &buff[buff_len-(p-buff)];
+	  }
+	}
+	if (gzclose(f) != 0) ok = 0;
+	SPAGAIN;
+	if (ok) {
+	  XPUSHs(sv_2mortal(newSViv(start_id)));
+	  XPUSHs(sv_2mortal(newSViv(av_len(depslist))));
+	}
+      } else {
+	  SV **nofatal = hv_fetch((HV*)SvRV(urpm), "nofatal", 7, 0);
+	  if (!errno) errno = EINVAL; /* zlib error */
+	  if (!nofatal || !SvIV(*nofatal))
+	      croak(errno == ENOENT
+		      ? "unable to read synthesis file %s"
+		      : "unable to uncompress synthesis file %s", filename);
+      }
+    } else croak("first argument should contain a depslist ARRAY reference");
+  } else croak("first argument should be a reference to a HASH");
+
+void
+Urpm_parse_hdlist__XS(urpm, filename, ...)
+  SV *urpm
+  char *filename
+  PPCODE:
+  if (SvROK(urpm) && SvTYPE(SvRV(urpm)) == SVt_PVHV) {
+    SV **fdepslist = hv_fetch((HV*)SvRV(urpm), "depslist", 8, 0);
+    AV *depslist = fdepslist && SvROK(*fdepslist) && SvTYPE(SvRV(*fdepslist)) == SVt_PVAV ? (AV*)SvRV(*fdepslist) : NULL;
+    SV **fprovides = hv_fetch((HV*)SvRV(urpm), "provides", 8, 0);
+    HV *provides = fprovides && SvROK(*fprovides) && SvTYPE(SvRV(*fprovides)) == SVt_PVHV ? (HV*)SvRV(*fprovides) : NULL;
+    SV **fobsoletes = hv_fetch((HV*)SvRV(urpm), "obsoletes", 9, 0);
+    HV *obsoletes = fobsoletes && SvROK(*fobsoletes) && SvTYPE(SvRV(*fobsoletes)) == SVt_PVHV ? (HV*)SvRV(*fobsoletes) : NULL;
+
+    if (depslist != NULL) {
+      pid_t pid = 0;
+      int d;
+      int empty_archive = 0;
+      FD_t fd;
+
+      d = open_archive(filename, &pid, &empty_archive);
+      fd = fdDup(d);
+      close(d);
+
+      if (empty_archive) {
+	  XPUSHs(sv_2mortal(newSViv(1 + av_len(depslist))));
+	  XPUSHs(sv_2mortal(newSViv(av_len(depslist))));
+      } else if (d >= 0 && fd) {
+	Header header;
+	int start_id = 1 + av_len(depslist);
+	int packing = 0;
+	SV *callback = NULL;
+
+	/* compability mode with older interface of parse_hdlist */
+	if (items == 3) {
+	  packing = SvTRUE(ST(2));
+	} else if (items > 3) {
+	  int i;
+	  for (i = 2; i < items-1; i+=2) {
+	    STRLEN len;
+	    char *s = SvPV(ST(i), len);
+
+	    if (len == 7 && !memcmp(s, "packing", 7)) {
+	      packing = SvTRUE(ST(i+1));
+	    } else if (len == 8 && !memcmp(s, "callback", 8)) {
+	      if (SvROK(ST(i+1))) callback = ST(i+1);
+	    }
+	  }
+	}
+
+	PUTBACK;
+	do {
+	  header=headerRead(fd, HEADER_MAGIC_YES);
+	  if (header != NULL) {
+	    struct s_Package pkg, *_pkg;
+	    SV *sv_pkg;
+
+	    memset(&pkg, 0, sizeof(struct s_Package));
+	    pkg.flag = 1 + av_len(depslist);
+	    pkg.h = header;
+	    sv_pkg = sv_setref_pv(newSVpv("", 0), "URPM::Package",
+				  _pkg = memcpy(malloc(sizeof(struct s_Package)), &pkg, sizeof(struct s_Package)));
+	    if (call_package_callback(urpm, sv_pkg, callback)) {
+	      if (provides) {
+		update_provides(_pkg, provides);
+		update_provides_files(_pkg, provides);
+	      }
+	      if (obsoletes) update_obsoletes(_pkg, obsoletes);
+	      if (packing) pack_header(_pkg);
+	      av_push(depslist, sv_pkg);
+	    }
+	  }
+	} while (header != NULL);
+
+	int ok = Fclose(fd) == 0;
+
+	if (pid) {
+	  kill(pid, SIGTERM);
+	  int status;
+	  int rc = waitpid(pid, &status, 0);
+	  ok = rc != -1 && WEXITSTATUS(status) != 1; /* in our standard case, gzip will exit with status code 2, meaning "decompression OK, trailing garbage ignored" */
+	  pid = 0;
+	} else if (!empty_archive) {
+	  ok = av_len(depslist) >= start_id;
+	}
+	SPAGAIN;
+	if (ok) {
+	  XPUSHs(sv_2mortal(newSViv(start_id)));
+	  XPUSHs(sv_2mortal(newSViv(av_len(depslist))));
+	}
+      } else {
+	  SV **nofatal = hv_fetch((HV*)SvRV(urpm), "nofatal", 7, 0);
+	  if (!nofatal || !SvIV(*nofatal))
+	      croak("cannot open hdlist file %s", filename);
+      }
+    } else croak("first argument should contain a depslist ARRAY reference");
+  } else croak("first argument should be a reference to a HASH");
+
+void
+Urpm_parse_rpm(urpm, filename, ...)
+  SV *urpm
+  char *filename
+  PPCODE:
+  if (SvROK(urpm) && SvTYPE(SvRV(urpm)) == SVt_PVHV) {
+    SV **fdepslist = hv_fetch((HV*)SvRV(urpm), "depslist", 8, 0);
+    AV *depslist = fdepslist && SvROK(*fdepslist) && SvTYPE(SvRV(*fdepslist)) == SVt_PVAV ? (AV*)SvRV(*fdepslist) : NULL;
+    SV **fprovides = hv_fetch((HV*)SvRV(urpm), "provides", 8, 0);
+    HV *provides = fprovides && SvROK(*fprovides) && SvTYPE(SvRV(*fprovides)) == SVt_PVHV ? (HV*)SvRV(*fprovides) : NULL;
+    SV **fobsoletes = hv_fetch((HV*)SvRV(urpm), "obsoletes", 8, 0);
+    HV *obsoletes = fobsoletes && SvROK(*fobsoletes) && SvTYPE(SvRV(*fobsoletes)) == SVt_PVHV ? (HV*)SvRV(*fobsoletes) : NULL;
+
+    if (depslist != NULL) {
+      struct s_Package pkg, *_pkg;
+      SV *sv_pkg;
+      int packing = 0;
+      int keep_all_tags = 0;
+      SV *callback = NULL;
+      rpmVSFlags vsflags = RPMVSF_DEFAULT;
+
+      /* compability mode with older interface of parse_hdlist */
+      if (items == 3) {
+	packing = SvTRUE(ST(2));
+      } else if (items > 3) {
+	int i;
+	for (i = 2; i < items-1; i+=2) {
+	  STRLEN len;
+	  char *s = SvPV(ST(i), len);
+
+	  if (len == 7 && !memcmp(s, "packing", 7)) {
+	    packing = SvTRUE(ST(i + 1));
+	  } else if (len == 13 && !memcmp(s, "keep_all_tags", 13)) {
+	    keep_all_tags = SvTRUE(ST(i+1));
+	  } else if (len == 8 && !memcmp(s, "callback", 8)) {
+	    if (SvROK(ST(i+1))) callback = ST(i+1);
+	  } else if (len == 5) {
+            if (!memcmp(s, "nopgp", 5)) {
+              if (SvIV(ST(i+1))) vsflags |= (RPMVSF_NOSHA1 | RPMVSF_NOSHA1HEADER);
+            }
+            else if (!memcmp(s, "nogpg", 5)) {
+              if (SvIV(ST(i+1))) vsflags |= (RPMVSF_NOSHA1 | RPMVSF_NOSHA1HEADER);
+            }
+            else if (!memcmp(s, "nomd5", 5)) {
+              if (SvIV(ST(i+1))) vsflags |= (RPMVSF_NOMD5 |  RPMVSF_NOMD5HEADER);
+            }
+            else if (!memcmp(s, "norsa", 5)) {
+              if (SvIV(ST(i+1))) vsflags |= (RPMVSF_NORSA | RPMVSF_NORSAHEADER);
+            }
+            else if (!memcmp(s, "nodsa", 5)) {
+              if (SvIV(ST(i+1))) vsflags |= (RPMVSF_NODSA | RPMVSF_NODSAHEADER);
+            }
+          } else if (len == 9) {
+            if (!memcmp(s, "nodigests", 9)) {
+              if (SvIV(ST(i+1))) vsflags |= _RPMVSF_NODIGESTS;
+            } else
+            if (!memcmp(s, "nopayload", 9)) {
+              if (SvIV(ST(i+1))) vsflags |= _RPMVSF_NOPAYLOAD;
+            }
+          } 
+	}
+      }
+      PUTBACK;
+      memset(&pkg, 0, sizeof(struct s_Package));
+      pkg.flag = 1 + av_len(depslist);
+      _pkg = memcpy(malloc(sizeof(struct s_Package)), &pkg, sizeof(struct s_Package));
+
+      if (update_header(filename, _pkg, keep_all_tags, vsflags)) {
+	sv_pkg = sv_setref_pv(newSVpv("", 0), "URPM::Package", _pkg);
+	if (call_package_callback(urpm, sv_pkg, callback)) {
+	  if (provides) {
+	    update_provides(_pkg, provides);
+	    update_provides_files(_pkg, provides);
+	  }
+	  if (obsoletes) update_obsoletes(_pkg, obsoletes);
+	  if (packing) pack_header(_pkg);
+	  av_push(depslist, sv_pkg);
+	}
+	SPAGAIN;
+	/* only one element read */
+	XPUSHs(sv_2mortal(newSViv(av_len(depslist))));
+	XPUSHs(sv_2mortal(newSViv(av_len(depslist))));
+      } else free(_pkg);
+    } else croak("first argument should contain a depslist ARRAY reference");
+  } else croak("first argument should be a reference to a HASH");
+
+int
+Urpm_verify_rpm(filename, ...)
+  char *filename
+  PREINIT:
+  FD_t fd;
+  int i, oldlogmask;
+  rpmts ts = NULL;
+  struct rpmQVKArguments_s qva;
+  CODE:
+  /* Don't display error messages */
+  oldlogmask = rpmlogSetMask(RPMLOG_UPTO(RPMLOG_PRI(4)));
+  memset(&qva, 0, sizeof(struct rpmQVKArguments_s));
+  qva.qva_source = RPMQV_RPM;
+  qva.qva_flags = VERIFY_ALL;
+  for (i = 1 ; i < items - 1 ; i += 2) {
+    STRLEN len;
+    char *s = SvPV(ST(i), len);
+    if (len == 9 && !strncmp(s, "nodigests", 9)) {
+      if (SvIV(ST(i+1))) qva.qva_flags &= ~VERIFY_DIGEST;
+    } else if (len == 12 && !strncmp(s, "nosignatures", 12)) {
+      if (SvIV(ST(i+1))) qva.qva_flags &= ~VERIFY_SIGNATURE;
+    }
+  }
+  fd = Fopen(filename, "r");
+  if (fd == NULL) {
+    RETVAL = 0;
+  } else {
+    read_config_files(0);
+    ts = rpmtsCreate();
+    rpmtsSetRootDir(ts, "/");
+    rpmtsOpenDB(ts, O_RDONLY);
+    if (rpmVerifySignatures(&qva, ts, fd, filename)) {
+      RETVAL = 0;
+    } else {
+      RETVAL = 1;
+    }
+    Fclose(fd);
+    (void)rpmtsFree(ts);
+  }
+  rpmlogSetMask(oldlogmask);
+
+  OUTPUT:
+  RETVAL
+
+
+char *
+Urpm_get_gpg_fingerprint(filename)
+    char * filename
+    PREINIT:
+    uint8_t fingerprint[sizeof(pgpKeyID_t)];
+    char fingerprint_str[sizeof(pgpKeyID_t) * 2 + 1];
+    const uint8_t *pkt = NULL;
+    size_t pktlen = 0;
+    int rc;
+
+    CODE:
+    memset (fingerprint, 0, sizeof (fingerprint));
+    if ((rc = pgpReadPkts(filename, (uint8_t ** ) &pkt, &pktlen)) <= 0) {
+	pktlen = 0;
+    } else if (rc != PGPARMOR_PUBKEY) {
+	pktlen = 0;
+    } else {
+	unsigned int i;
+        pgpPubkeyFingerprint (pkt, pktlen, fingerprint);
+   	for (i = 0; i < sizeof (pgpKeyID_t); i++) {
+	    sprintf(&fingerprint_str[i*2], "%02x", fingerprint[i]);
+	}
+    }
+    _free(pkt);
+    RETVAL = fingerprint_str;
+    OUTPUT:
+    RETVAL
+
+
+char *
+Urpm_verify_signature(filename, prefix="/")
+  char *filename
+  char *prefix
+  PREINIT:
+  rpmts ts = NULL;
+  char result[1024];
+  rpmRC rc;
+  FD_t fd;
+  Header h;
+  CODE:
+  fd = Fopen(filename, "r");
+  if (fd == NULL) {
+    RETVAL = "NOT OK (could not read file)";
+  } else {
+    read_config_files(0);
+    ts = rpmtsCreate();
+    rpmtsSetRootDir(ts, prefix);
+    rpmtsOpenDB(ts, O_RDONLY);
+    rpmtsSetVSFlags(ts, RPMVSF_DEFAULT);
+    rc = rpmReadPackageFile(ts, fd, filename, &h);
+    Fclose(fd);
+    *result = '\0';
+    switch(rc) {
+      case RPMRC_OK:
+	if (h) {
+	  char *fmtsig = headerFormat(
+	      h,
+	      "%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:"
+	      "{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|",
+	      NULL);
+	  snprintf(result, sizeof(result), "OK (%s)", fmtsig);
+	  free(fmtsig);
+	} else snprintf(result, sizeof(result), "NOT OK (bad rpm): %s", rpmlogMessage());
+	break;
+      case RPMRC_NOTFOUND:
+	snprintf(result, sizeof(result), "NOT OK (signature not found): %s", rpmlogMessage());
+	break;
+      case RPMRC_FAIL:
+	snprintf(result, sizeof(result), "NOT OK (fail): %s", rpmlogMessage());
+	break;
+      case RPMRC_NOTTRUSTED:
+	snprintf(result, sizeof(result), "NOT OK (key not trusted): %s", rpmlogMessage());
+	break;
+      case RPMRC_NOKEY:
+	snprintf(result, sizeof(result), "NOT OK (no key): %s", rpmlogMessage());
+	break;
+    }
+    RETVAL = result;
+    if (h) h = headerFree(h);
+    (void)rpmtsFree(ts);
+  }
+
+  OUTPUT:
+  RETVAL
+
+    
+int
+Urpm_import_pubkey_file(db, filename)
+    URPM::DB db
+    char * filename
+    PREINIT:
+    const uint8_t *pkt = NULL;
+    size_t pktlen = 0;
+    int rc;
+    CODE:
+
+    rpmts ts = rpmtsLink(db->ts, "URPM::import_pubkey_file");
+    rpmtsClean(ts);
+    
+    if ((rc = pgpReadPkts(filename, (uint8_t ** ) &pkt, &pktlen)) <= 0) {
+        RETVAL = 0;
+    } else if (rc != PGPARMOR_PUBKEY) {
+        RETVAL = 0;
+    } else if (rpmtsImportPubkey(ts, pkt, pktlen) != RPMRC_OK) {
+        RETVAL = 0;
+    } else {
+        RETVAL = 1;
+    }
+    pkt = _free(pkt);
+    (void)rpmtsFree(ts);
+    OUTPUT:
+    RETVAL
+
+int
+Urpm_import_pubkey(...)
+  CODE:
+  unused_variable(&items);
+  croak("import_pubkey() is dead. use import_pubkey_file() instead");
+  RETVAL = 1;
+  OUTPUT:
+  RETVAL
+
+int
+Urpm_archscore(arch)
+  const char * arch
+  PREINIT:
+#ifndef RPM_ORG
+  char * platform = NULL;
+#endif
+  CODE:
+  read_config_files(0);
+#ifndef RPM_ORG
+  platform = rpmExpand(arch, "-%{_target_vendor}-%{_target_os}%{?_gnu}", NULL);
+  RETVAL=rpmPlatformScore(platform, NULL, 0);
+  _free(platform);
+#else
+  RETVAL=rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+#endif
+  OUTPUT:
+  RETVAL
+
+int
+Urpm_osscore(os)
+  const char * os
+  PREINIT:
+#ifndef RPM_ORG
+  char * platform = NULL;
+#endif
+  CODE:
+  read_config_files(0);
+#ifndef RPM_ORG
+  platform = rpmExpand("%{_target_cpu}-%{_target_vendor}-", os, "%{?_gnu}", NULL);
+  RETVAL=rpmPlatformScore(platform, NULL, 0);
+  _free(platform);
+#else
+  RETVAL=rpmMachineScore(RPM_MACHTABLE_INSTOS, os);
+#endif
+  OUTPUT:
+  RETVAL
+
+int
+Urpm_platformscore(platform)
+  const char * platform
+  CODE:
+  read_config_files(0);
+#ifndef RPM_ORG
+  RETVAL=rpmPlatformScore(platform, NULL, 0);
+#else
+  unused_variable(platform);
+  croak("platformscore() is available only since rpm 4.4.8");
+  RETVAL=0;
+#endif
+  OUTPUT:
+  RETVAL
+
+void
+Urpm_stream2header(fp)
+    FILE *fp
+  PREINIT:
+    FD_t fd;
+    URPM__Package pkg;
+  PPCODE:
+    if ((fd = fdDup(fileno(fp)))) {
+	pkg = (URPM__Package)malloc(sizeof(struct s_Package));
+	memset(pkg, 0, sizeof(struct s_Package));
+        pkg->h = headerRead(fd, HEADER_MAGIC_YES);
+        if (pkg->h) {
+            SV *sv_pkg;
+            EXTEND(SP, 1);
+            sv_pkg = sv_newmortal();
+            sv_setref_pv(sv_pkg, "URPM::Package", (void*)pkg);
+            PUSHs(sv_pkg);
+        }
+        Fclose(fd);
+    }
+
+void
+Urpm_spec2srcheader(specfile)
+  char *specfile
+  PREINIT:
+    rpmts ts = rpmtsCreate();
+    URPM__Package pkg;
+    Spec spec = NULL;
+  PPCODE:
+/* ensure the config is in memory with all macro */
+  read_config_files(0);
+/* Do not verify architecture */
+#define SPEC_ANYARCH 1
+/* Do not verify whether sources exist */
+#define SPEC_FORCE 1
+  if (!parseSpec(ts, specfile, "/", NULL, 0, NULL, NULL, SPEC_ANYARCH, SPEC_FORCE)) {
+    SV *sv_pkg;
+    spec = rpmtsSetSpec(ts, NULL);
+#ifdef RPM_ORG
+    if (! spec->sourceHeader)
+#endif
+      initSourceHeader(spec);
+    pkg = (URPM__Package)malloc(sizeof(struct s_Package));
+    memset(pkg, 0, sizeof(struct s_Package));
+    headerPutString(spec->sourceHeader, RPMTAG_SOURCERPM, "");
+
+    {
+      struct rpmtd_s td = {
+	.tag = RPMTAG_ARCH,
+	.type = RPM_STRING_TYPE,
+	.data = (void *) "src",
+	.count = 1,
+      };
+      /* parseSpec() sets RPMTAG_ARCH to %{_target_cpu} whereas we really a header similar to .src.rpm header */
+      headerMod(spec->sourceHeader, &td);
+    }
+
+    pkg->h = headerLink(spec->sourceHeader);
+    sv_pkg = sv_newmortal();
+    sv_setref_pv(sv_pkg, "URPM::Package", (void*)pkg);
+    XPUSHs(sv_pkg);
+    spec = freeSpec(spec);
+  } else {
+    XPUSHs(&PL_sv_undef);
+    /* apparently rpmlib sets errno this when given a bad spec. */
+    if (errno == EBADF)
+      errno = 0;
+  }
+  ts = rpmtsFree(ts);
+
+void
+expand(name)
+    char * name
+    PPCODE:
+    const char * value = rpmExpand(name, NULL);
+    XPUSHs(sv_2mortal(newSVpv(value, 0)));
+
+void
+add_macro_noexpand(macro)
+    char * macro
+    CODE:
+    rpmDefineMacro(NULL, macro, RMIL_DEFAULT);
+
+void
+del_macro(name)
+    char * name
+    CODE:
+    delMacro(NULL, name);
+
+void
+loadmacrosfile(filename)
+    char * filename
+    PPCODE:
+    rpmInitMacros(NULL, filename);
+
+void
+resetmacros()
+    PPCODE:
+    rpmFreeMacros(NULL);
+
+void
+setVerbosity(level)
+    int level
+    PPCODE:
+    rpmSetVerbosity(level);
+
+const char *
+rpmErrorString()
+  CODE:
+  RETVAL = rpmlogMessage();
+  OUTPUT:
+  RETVAL 
+
+void
+rpmErrorWriteTo(fd)
+  int fd
+  CODE:
+  rpmError_callback_data = fd;
+  rpmlogSetCallback(rpmError_callback, NULL);
+
+  /* vim:set ts=8 sts=2 sw=2: */

Added: rpm/perl-URPM/trunk/t/00prepare.t
===================================================================
--- rpm/perl-URPM/trunk/t/00prepare.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/00prepare.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More tests => 1;
+use Cwd;
+
+chdir 't' if -d 't';
+mkdir "tmp";
+for (qw(BUILD SOURCES RPMS RPMS/noarch)) {
+    mkdir "tmp/".$_;
+}
+# locally build a test rpm
+system(rpmbuild => '--define', '_topdir '. Cwd::cwd() . "/tmp/", '-bb', 'test-rpm.spec');
+ok( -f 'tmp/RPMS/noarch/test-rpm-1.0-1mdk.noarch.rpm', 'rpm created' );
+

Added: rpm/perl-URPM/trunk/t/buggy_synthesis.cz
===================================================================
(Binary files differ)


Property changes on: rpm/perl-URPM/trunk/t/buggy_synthesis.cz
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: rpm/perl-URPM/trunk/t/empty_synthesis.cz
===================================================================
(Binary files differ)


Property changes on: rpm/perl-URPM/trunk/t/empty_synthesis.cz
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: rpm/perl-URPM/trunk/t/fatal.t
===================================================================
--- rpm/perl-URPM/trunk/t/fatal.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/fatal.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 8;
+use URPM;
+
+my $u = new URPM;
+
+eval { $u->parse_hdlist('non-existent'); };
+like( $@, qr/^cannot open hdlist file non-existent/, 'fatal error on hdlist not found' );
+is( $! + 0, $!{EBADF}, '$! is EBADF' );
+eval { $u->parse_synthesis('non-existent'); };
+like( $@, qr/^unable to read synthesis file non-existent/, 'fatal error on synthesis not found' );
+is( $! + 0, $!{ENOENT}, '$! is ENOENT' );
+
+my $v = new URPM( nofatal => 1 );
+
+eval { $v->parse_hdlist('non-existent'); };
+is( $@, '', 'no error on hdlist not found' );
+is( $! + 0, $!{EBADF}, '$! is EBADF' );
+eval { $v->parse_synthesis('non-existent'); };
+is( $@, '', 'no error on synthesis not found' );
+is( $! + 0, $!{ENOENT}, '$! is ENOENT' );

Added: rpm/perl-URPM/trunk/t/parse.t
===================================================================
--- rpm/perl-URPM/trunk/t/parse.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/parse.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+
+# $Id: parse.t 258553 2009-07-22 18:21:30Z peroyvind $
+
+use strict;
+use warnings;
+use Test::More tests => 39;
+use MDV::Packdrakeng;
+use URPM;
+use URPM::Build;
+use URPM::Query;
+
+chdir 't' if -d 't';
+
+# shut up
+URPM::setVerbosity(2);
+
+my $a = new URPM;
+ok($a);
+
+END { system('rm -rf hdlist.cz empty_hdlist.cz headers tmp') }
+
+my ($start, $end) = $a->parse_rpms_build_headers(rpms => [ "tmp/RPMS/noarch/test-rpm-1.0-1mdk.noarch.rpm" ], keep_all_tags => 1);
+ok(@{$a->{depslist}} == 1);
+my $pkg = $a->{depslist}[0];
+ok($pkg);
+is($pkg->get_tag(1000), 'test-rpm', 'name');
+is($pkg->get_tag(1001), '1.0', 'version');
+is($pkg->get_tag(1002), '1mdk', 'release');
+
+mkdir 'headers';
+system('touch headers/empty');
+is(URPM->new->parse_hdlist('headers/empty'), undef, 'empty header');
+system('echo FOO > headers/bad');
+is(URPM->new->parse_hdlist('headers/bad'), undef, 'bad rpm header');
+
+$a->build_hdlist(
+    start  => 0,
+    end    => -1,
+    hdlist => 'empty_hdlist.cz',
+);
+ok(-f 'empty_hdlist.cz');
+
+($start, $end) = URPM->new->parse_hdlist('empty_hdlist.cz');
+is("$start $end", "0 -1", 'empty hdlist');
+
+
+$a->build_hdlist(
+    start  => 0,
+    end    => $#{$a->{depslist}},
+    hdlist => 'hdlist.cz',
+    ratio  => 9,
+);
+
+ok(-f 'hdlist.cz');
+
+my $b = new URPM;
+($start, $end) = $b->parse_hdlist('hdlist.cz', keep_all_tags => 1);
+is("$start $end", "0 0", 'parse_hdlist');
+ok(@{$b->{depslist}} == 1);
+$pkg = $b->{depslist}[0];
+ok($pkg);
+is($pkg->get_tag(1000), 'test-rpm', 'name');
+is($pkg->get_tag(1001), '1.0', 'version');
+is($pkg->get_tag(1002), '1mdk', 'release');
+is($pkg->queryformat("%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}"), "test-rpm-1.0-1mdk.noarch",
+    q/get headers from hdlist/);
+rpm_is_jbj_version() ?
+  ok($pkg->is_platform_compat() > 0, "can evaluate platform score") :
+  pass('no platform compat');
+
+my $headers = eval { [ $b->parse_rpms_build_headers(rpms => [ "tmp/RPMS/noarch/test-rpm-1.0-1mdk.noarch.rpm" ], 
+						    dir => 'headers') ] };
+is($@, '', 'parse_rpms_build_headers');
+is(int @$headers, 1, 'parse_rpms_build_headers');
+ok(@{$b->{depslist}} == 2);
+($start, $end) = eval { $b->parse_headers(dir => "headers", headers => $headers) };
+is($@, '', 'parse_headers');
+is("$start $end", "2 2", 'parse_headers');
+
+
+
+# Version comparison
+ok(URPM::rpmvercmp("1-1mdk",     "1-1mdk") ==  0, "Same value = 0");
+ok(URPM::rpmvercmp("0:1-1mdk",   "1-1mdk") ==  -1, "Same value, epoch 0 on left = 1");
+ok(URPM::rpmvercmp("1-1mdk",     "1-2mdk") == -1, "Right value win = -1");
+ok(URPM::rpmvercmp("1-2mdk",     "1-1mdk") ==  1, "Left value win = 1");
+ok(URPM::rpmvercmp("1:1-1mdk", "2:1-1mdk") == -1, "epoch 1 vs 2 = -1");
+
+{
+    open(my $hdfh, "zcat hdlist.cz 2>/dev/null |") or die $!;
+    my $pkg = URPM::stream2header($hdfh);
+    ok(defined $pkg, "Reading a header works");
+    is($pkg->get_tag(1000), 'test-rpm');
+    is($pkg->get_tag(1001), '1.0');
+    is($pkg->get_tag(1002), '1mdk');
+    is($pkg->queryformat("%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}"), "test-rpm-1.0-1mdk.noarch");
+    ok($pkg->is_arch_compat(), "Arch compat works");
+    close $hdfh;
+}
+
+{
+    my $pkg = URPM::spec2srcheader("test-rpm.spec");
+    ok(defined $pkg, "Parsing a spec works");
+    is($pkg->get_tag(1000), 'test-rpm', 'parsed correctly');
+    $pkg = URPM::spec2srcheader("doesnotexist.spec");
+    ok(!defined $pkg, "non-existent spec");
+    open my $f, '>', 'bad.spec' or die "Can't write bad.spec: $!\n";
+    print $f "Name: foo\nVerssion: 2\n";
+    close $f;
+    $pkg = URPM::spec2srcheader("bad.spec");
+    ok(!defined $pkg, "bad spec");
+    END { unlink "bad.spec" }
+}
+
+sub rpm_is_jbj_version {
+    # checking for --yaml support
+    `rpm --help` =~ /yaml/;
+}

Added: rpm/perl-URPM/trunk/t/pod.t
===================================================================
--- rpm/perl-URPM/trunk/t/pod.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/pod.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,5 @@
+#!perl
+use Test::More;
+eval "use Test::Pod 1.14";
+plan skip_all => "Test::Pod 1.14 required for testing POD" if $@;
+all_pod_files_ok();

Added: rpm/perl-URPM/trunk/t/rpmdb.t
===================================================================
--- rpm/perl-URPM/trunk/t/rpmdb.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/rpmdb.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+use strict ;
+use warnings ;
+use Test::More tests => 7;
+use URPM;
+
+my ($count, @all_pkgs_extern, @all_pkgs);
+my ($pkg_perl, $count_perl, $pkg_perl_extern);
+{
+    my $db;
+    ok($db = URPM::DB::open, 'DB opened');
+
+    @all_pkgs_extern = sort { $a cmp $b } split /\n/ => qx(rpm -qa --nosignature --qf '%{name}-%{version}-%{release}\n');
+    ok(@all_pkgs_extern > 0, 'There are RPMs');
+
+    $count = $db->traverse(sub {
+	    my ($pkg) = @_;
+	    my ($name, $version, $release, $arch) = $pkg->fullname;
+	    #- arch is void for -pubkey- package.
+	    my $fullname = "$name-$version-$release";
+	    push @all_pkgs, $fullname;
+	    if ($name eq 'perl') { $pkg_perl_extern = $fullname }
+	});
+
+    $count_perl = $db->traverse_tag('name', ['perl'], sub {
+	    my ($pkg) = @_;
+	    my ($name, $version, $release) = $pkg->fullname;
+	    $pkg_perl = "$name-$version-$release";
+	});
+}
+is($count, @all_pkgs_extern,
+    'traversed same num of packages than given by rpm -qa');
+is($count, @all_pkgs,
+    'traversed each package once');
+is($count_perl, 1, q(there's exactly 1 "perl" package));
+is($pkg_perl, $pkg_perl_extern, '... with the correct fullname');
+
+my @all_pkgs_sorted = sort { $a cmp $b } @all_pkgs;
+my $bad_pkgs = 0;
+foreach (0..$#all_pkgs_sorted) {
+    $all_pkgs_sorted[$_] eq $all_pkgs_extern[$_] and next;
+    diag($all_pkgs_extern[$_] . " vs " . $all_pkgs_sorted[$_]);
+    ++$bad_pkgs;
+}
+is($bad_pkgs, 0, 'no mismatch between package lists');

Added: rpm/perl-URPM/trunk/t/sort_graph.t
===================================================================
--- rpm/perl-URPM/trunk/t/sort_graph.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/sort_graph.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More 'no_plan';
+use URPM;
+
+
+my ($list_unsorted, $requires);
+
+$list_unsorted = [ 0, 1, 2 ];
+$requires = { 2 => [ 1 ], 1 => [ 0 ], 0 => [ 1, 2 ] }; 
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0, 1, 2, 3, 4 ];
+$requires = { '0' => [], '1' => [ 2, 3 ], '2' => [ 4 ], '3' => [ 4 ], '4' => [ 1, 0 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0, 3, 4, 5, 6, 10 ];
+$requires = { '0' => [ 4 ], '3' => [ 5 ], '4' => [ 6, 5 ], '5' => [ 10 ], '6' => [ 10, 3 ], '10' => [ 6 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0, 1, 2, 3, 4 ];
+$requires = { '0' => [ 0 ], '1' => [ 4 ], '2' => [], '3' => [ 3 ], '4' => [ 0, 2 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0, 1, 2, 3, 4 ];
+$requires = { '0' => [], '1' => [ 3, 1 ], '2' => [ 2 ], '3' => [ 3 ], '4' => [ 1, 2 ] }; 
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0, 1, 2, 3, 4 ];
+$requires = { '0' => [ 3, 4 ], '1' => [ 0, 3 ], '2' => [], '3' => [ 4 ], '4' => [ 0, 3 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 92, 94, 133, 137, 5826, 5828, 5830, 5831, 5836, 5839, 5842, 5844, 5845, 5848, 5849, 5851, 5856, 5859, 5864, 5873, 5882, 5883, 5890, 5892, 5894, 5895, 5897, 5900, 5913, 5915, 5916, 5917, 5924, 5925, 5926, 5928, 5929, 5932, 5936, 5937, 5938, 5943, 5948, 5953, 5955, 5956, 5959, 5960, 5961, 5962, 5964, 5968, 5969, 5970, 5974, 6008, 6009, 6010, 6012, 6110, 6115, 6119, 6120, 6127, 6129, 6132, 6135, 6164, 6165, 6166, 16841, 16842, 16844, 16845, 16890, 17009, 17011, 17013, 17156, 17157, 17169 ];
+$requires = { '17011' => [], '5883' => [], '5956' => [ 5955, 5839, 5959, 5964 ], '5897' => [], '5953' => [ 5936, 5943 ], '5894' => [ 5839 ], '17013' => [ 6135 ], '5936' => [ 5943 ], '5826' => [], '6135' => [ 5839 ], '16845' => [ 5839 ], '5974' => [ 5974, 5839, 5964 ], '5851' => [ 5856, 5849 ], '6115' => [], '92' => [ 5839, 5925, 94 ], '6010' => [ 6008, 6009, 6010 ], '5882' => [], '5970' => [ 5955, 5839, 5969 ], '16841' => [], '5926' => [ 5953, 5936, 5926, 6009, 5943, 5928 ], '17156' => [ 17157, 17156 ], '5848' => [ 5856 ], '6008' => [ 6009, 5839, 6008, 6010 ], '5842' => [ 5839, 5844 ], '16844' => [ 16845, 16841, 16842, 5839 ], '16842' => [], '5955' => [ 5970 ], '6119' => [ 6119 ], '133' => [ 5839 ], '6009' => [ 6008, 6009, 6010 ], '5831' => [], '5839' => [ 5839 ], '6165' => [ 5839 ], '5830' => [], '5960' => [ 5839, 5962 ], '5932' => [ 5953, 5936, 6009, 5932, 5938, 5943, 5928 ], '5924' => [ 5839 ], '5828' => [], '5959' => [ 5969 ], '5890' => [ 5897 ], '17169' => [ 17157 ], '5
 937' => [ 5936, 5943 ], '137' => [ 133, 5839, 5925 ], '5895' => [], '5892' => [], '6110' => [ 5839 ], '6127' => [], '5900' => [], '5948' => [ 5953, 5936, 6009, 5932, 5937, 5948, 5929, 5938, 5943, 5928 ], '6120' => [], '5929' => [ 5936, 5943 ], '5961' => [ 5839 ], '5964' => [ 5956, 5970, 5839 ], '6164' => [ 6119, 6120, 6164 ], '5925' => [ 5924 ], '5844' => [ 5842, 5844 ], '5864' => [], '17157' => [ 5839, 17156, 17157 ], '5969' => [], '5962' => [ 6009, 5839, 5962 ], '5913' => [ 6115, 5839, 5917 ], '5968' => [ 5970, 5839, 5959 ], '5915' => [], '6166' => [ 5839, 6165 ], '6132' => [ 5839, 6129 ], '6129' => [ 5839, 6127, 6132 ], '5938' => [ 5936, 5943 ], '5836' => [], '5943' => [ 5953, 5936, 6009, 5937, 5948, 5929, 5928 ], '5856' => [ 5897 ], '5873' => [], '5917' => [ 5839, 5856, 5917, 5849 ], '17009' => [], '94' => [ 5839 ], '5859' => [ 5856 ], '16890' => [], '5845' => [ 5851, 5848, 5856, 5849 ], '5928' => [ 5953, 5936, 5926, 6009, 5943, 5928 ], '5916' => [ 5915 ], '5849' => [ 58
 56 ], '6012' => [ 6012 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 53, 56, 118, 189, 223, 284, 286, 304, 396, 397, 403, 442, 480, 544, 556, 596, 607, 692, 729, 758, 764, 772, 778, 798, 829, 838, 840, 865, 917, 1019, 1112, 1149, 1191, 1192, 1232, 1275, 1292, 1316, 1319, 1364, 1411, 1415, 1422, 1487, 1508, 1583, 1719, 1769, 1787, 1827, 1855, 1884, 1894, 2001, 2136, 2139, 2243, 2244, 2355, 2387, 2516, 2597, 2603, 2669, 2694, 2727, 2746, 2818, 2820, 2826, 2845, 2861, 2869, 2932, 2992, 3002, 3016, 3037, 3069, 3079, 3151, 3173, 3272, 3273, 3275, 3280, 3289, 3293, 3314, 3327, 3568, 3569, 3602, 3659, 3662, 3665, 3667, 3669, 3672, 3675, 3682, 3934, 3935, 3936, 3971, 3973, 3980, 4053, 4060, 4150, 4161, 4350, 4400, 4402, 4426, 4428, 4430, 4438, 4439, 4444, 4446, 4635, 4636, 4637, 4638, 4639, 4640, 4656, 4657, 4673, 4681, 4685, 4686, 4687, 4691, 4715, 4793, 5060, 5070, 5079, 5198, 5199, 5250, 5327, 5329, 5330, 5331, 5333, 5334, 5342, 5401, 5404, 5407, 5409, 5423, 5442, 5486, 5487, 5494, 5499, 5501, 5616, 5618, 5664, 5685, 5688, 5775,
  5777, 5778, 6166, 6178, 6305, 8295, 9859, 10199, 10649, 10651, 10659, 11879, 22012 ];
+$requires = { '5423' => [ 5442 ], '118' => [ 5060 ], '3934' => [ 764 ], '5250' => [], '2818' => [], '2746' => [ 1019, 764 ], '2992' => [ 5327, 1884, 4636, 917, 2603, 56, 5334 ], '3002' => [ 3069 ], '5327' => [ 3934, 2746, 5327, 1884, 4636, 1019, 397, 764, 758, 829, 2603, 4681, 5331, 1232, 5777, 5334, 1719 ], '798' => [ 3273, 2861 ], '3037' => [ 3037, 2820, 838 ], '5688' => [ 5327, 1884, 4636, 2603, 5334 ], '1884' => [ 3934, 764, 4402, 5777, 2861 ], '2516' => [ 917, 596, 2826, 56, 607, 1112, 4444 ], '2001' => [ 4060, 442, 284, 5333, 1894, 396, 5329, 4640 ], '5664' => [], '1364' => [ 5250, 1364, 4060, 917, 5401, 2243, 5407, 1411 ], '5494' => [ 480, 5501 ], '4715' => [ 3151 ], '5499' => [ 764, 865, 2387, 1232, 3973 ], '3273' => [], '4636' => [ 3934, 1884, 4636, 764, 5198, 4638, 4639, 5777, 2861, 5775 ], '1019' => [ 764 ], '4060' => [ 4060, 4053 ], '4439' => [ 1364, 4060, 3682, 2932, 729, 3665, 403, 2845, 3672, 3327, 3569, 4444 ], '397' => [ 764, 1232 ], '764' => [ 5501, 5486 ],
  '865' => [ 764, 2387, 3973 ], '5342' => [ 4715, 11879, 4635, 4673, 53 ], '5060' => [], '3936' => [], '3314' => [], '8295' => [], '3682' => [ 3665, 3662, 3569 ], '5198' => [ 3934, 764, 5777, 2861 ], '10649' => [ 5331, 6166 ], '4685' => [ 4687, 4686 ], '3272' => [], '11879' => [], '442' => [ 798, 1884, 3273, 442, 5778, 3935, 396, 4400 ], '4638' => [], '5778' => [ 798, 3273, 5777, 3327, 5775 ], '2932' => [ 2932 ], '1855' => [ 607, 1112 ], '2387' => [ 3973 ], '1191' => [ 5494, 1019, 5487, 480, 396 ], '3016' => [ 2746, 1191, 480, 396 ], '5404' => [ 5409 ], '284' => [ 4060, 2603 ], '5442' => [], '2136' => [ 5327, 1884, 2516, 4636, 764, 2387, 917, 596, 2603, 5409, 3293, 3973, 56, 5334, 1415, 4444 ], '2869' => [ 5494, 1232, 5487, 480, 396 ], '5070' => [ 5060 ], '4402' => [], '729' => [ 1364, 4060, 56 ], '917' => [ 917, 5401, 1411 ], '3568' => [ 764, 2387, 3973, 5501, 5486 ], '3980' => [ 5327, 1884, 4636, 4635, 2603, 5334 ], '4635' => [], '3675' => [], '758' => [ 3934, 764, 1232 ], 
 '829' => [ 764, 1232 ], '4687' => [ 1192, 6305 ], '596' => [ 917, 596, 544 ], '5330' => [ 5423, 3934, 2746, 5327, 1884, 4636, 1019, 397, 764, 5442, 4402, 758, 829, 2603, 4681, 1232, 1319, 5777, 5334, 5501, 5486, 4161, 2861, 1719 ], '223' => [ 1855, 223, 2727, 1112 ], '772' => [], '5401' => [], '4657' => [ 4657 ], '3289' => [ 2001, 4060, 442, 5404, 284, 3293, 5333, 5329, 4640 ], '4350' => [], '5685' => [ 5688, 10649 ], '3151' => [ 5499, 764 ], '3069' => [], '3667' => [ 3675, 3659, 3662 ], '1149' => [ 2869, 829, 480, 396 ], '3935' => [ 3934, 480, 396 ], '4673' => [ 10659, 4150, 10651 ], '2603' => [ 772 ], '2243' => [], '4053' => [], '1487' => [ 5327, 1884, 2516, 4636, 764, 5060, 2387, 2136, 917, 596, 2603, 2355, 5409, 3293, 3973, 56, 4426, 5334, 4444 ], '3659' => [ 3675 ], '2694' => [ 764, 2387, 3973 ], '4681' => [ 3934, 1019, 764 ], '1769' => [ 118, 764, 865, 5060, 2387, 4402, 1769, 1232, 3602, 5777, 3973, 3173, 5079, 2861 ], '2826' => [ 2516, 5342, 917, 596, 56, 607, 1112, 4
 444 ], '778' => [ 397, 2869, 480, 396 ], '4639' => [ 3934, 5664, 4636, 764, 5198, 5777, 4656, 5501, 5486, 2861 ], '4430' => [ 5423, 5327, 1884, 4636, 5442, 2603, 5334, 5618 ], '5407' => [ 4060, 5401 ], '2355' => [ 5327, 1884, 2516, 4636, 10649, 2136, 917, 596, 2603, 1487, 5409, 3293, 56, 4426, 5334, 3280, 4444 ], '5409' => [], '5331' => [ 5330, 5334 ], '10199' => [], '3293' => [ 5327, 1884, 4636, 3314, 5330, 2603, 5409, 3293, 1894, 5334, 3280 ], '4446' => [], '1232' => [ 764, 5501 ], '2820' => [ 2820 ], '4637' => [], '3602' => [ 5060 ], '1192' => [ 5775 ], '1275' => [ 2820 ], '4438' => [ 2992, 5342, 917, 3568, 3675, 4446, 3669, 56, 1827, 3662, 4444 ], '556' => [ 5060, 3173 ], '22012' => [ 8295, 442, 5407, 1275, 1787, 189, 1292, 5333, 1422, 1508, 4400, 1316, 4640, 840, 4793 ], '1787' => [ 3037, 1275, 1292 ], '1319' => [ 5423, 5442, 1319, 286, 3275 ], '189' => [ 5494, 865, 5487, 480, 692, 396, 3971 ], '2597' => [ 5250, 1364, 4060, 4439, 442, 5404, 284, 2136, 729, 3289, 5333, 6
 92, 396, 3971, 1415, 2845, 5329, 1316, 3327, 4640 ], '1292' => [ 3037, 1275 ], '5487' => [ 480, 5486 ], '5333' => [ 3934, 2746, 5327, 1884, 4636, 4060, 1019, 397, 764, 442, 5778, 1191, 3016, 284, 2869, 4402, 758, 829, 5330, 1149, 3935, 2603, 4681, 778, 1232, 5333, 5777, 4691, 3079, 396, 5334, 5501, 5486, 5329, 2861, 4640, 1719, 2669 ], '5777' => [ 2861, 5775 ], '480' => [ 5494, 189 ], '1894' => [ 5327, 1884, 4636, 764, 2603, 1894, 1583, 5334 ], '4691' => [ 1191, 3935, 4681, 480, 396 ], '3079' => [ 2869, 758, 3935, 480, 396 ], '692' => [ 2387, 480, 3971 ], '3973' => [], '5199' => [ 798, 3273, 5198, 5778, 3935, 480, 396 ], '3669' => [ 3675 ], '304' => [ 4636, 2603, 304, 5334, 2861 ], '1583' => [], '396' => [ 5494, 764, 5487, 480 ], '3173' => [], '1422' => [ 2694, 692, 396, 3971 ], '3665' => [ 3675 ], '56' => [ 2992, 917 ], '2139' => [ 2139 ], '9859' => [ 9859 ], '5616' => [ 2818, 3936, 3272, 10199, 2139, 5618 ], '4426' => [ 4430 ], '5334' => [ 764, 5060, 4402, 5334, 5079 ], '6
 178' => [], '10659' => [], '4656' => [ 5664, 4657 ], '1508' => [ 5250, 1364, 4060, 4439, 442, 5404, 284, 5070, 729, 3289, 1487, 2355, 2597, 5333, 692, 396, 3971, 2845, 4428, 5329, 1316, 3327, 4640 ], '4400' => [ 3273, 4402 ], '1827' => [], '6305' => [ 5775 ], '5501' => [], '838' => [ 3037, 2820 ], '5486' => [], '403' => [ 4060, 3569 ], '3971' => [ 480, 3973 ], '3662' => [ 3675, 3667 ], '286' => [ 5423, 5442 ], '2845' => [ 1364, 4060, 596, 2845, 544, 3327 ], '1415' => [ 5327, 1884, 2516, 4636, 2136, 917, 596, 2603, 5409, 5331, 3293, 56, 5334, 3280, 4444 ], '5618' => [ 5616, 5618 ], '2727' => [ 607 ], '3672' => [ 4060, 3669, 3665 ], '544' => [ 917, 596 ], '4150' => [ 4350, 556, 304, 9859, 2861, 2244 ], '4161' => [ 5423, 5060, 5442, 4402, 1319, 4161, 5079 ], '10651' => [], '5079' => [ 5060, 5079 ], '3280' => [ 5327, 1884, 4636, 2603, 5334 ], '53' => [], '6166' => [], '4428' => [ 4060, 4426, 3569 ], '607' => [], '5329' => [ 4060, 396, 5334, 5329 ], '1112' => [ 1855, 607, 1112 ],
  '3275' => [], '1316' => [ 5250, 2516, 1364, 4060, 4439, 729, 223, 2826, 2845, 2727 ], '2861' => [], '3327' => [ 3273 ], '4640' => [ 3934, 798, 1884, 3273, 4636, 4060, 764, 5198, 442, 4638, 5778, 4402, 3935, 4637, 5777, 5199, 396, 5501, 5486, 2861, 3327, 4640 ], '4686' => [ 5423, 5060, 5442, 4402, 1319, 5777, 4161, 5079 ], '840' => [ 118, 764, 865, 5060, 4685, 2387, 4402, 1769, 1232, 3602, 5777, 3973, 3173, 5501, 5486, 5079, 2861 ], '3569' => [], '4444' => [ 3002, 917, 3675, 4446, 4438, 3669, 56, 6178, 3662, 5618, 4444 ], '1719' => [ 1019, 764, 1232 ], '1411' => [ 917, 5401 ], '5775' => [ 5777, 2861 ], '2244' => [ 4402 ], '4793' => [], '2669' => [ 1191, 2869, 480, 396, 1719 ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 5625, 6155, 6156, 6157, 6158, 6172, 6180, 6186, 6190, 6192, 6199, 6201, 6202, 6204, 6206, 6210, 6215, 6221, 6222, 6223, 6224, 6226, 6229, 6233, 6234, 6236, 6238, 6239, 6243, 6244, 6250, 6254, 6255, 6256, 6257, 6258, 6259, 6261, 6263, 6265, 6266, 6267, 6269, 6270, 6271, 6272, 6273, 6274, 6275, 6278, 6279, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6296, 6298, 6299, 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6309, 6310, 6311, 6312, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6324, 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6341, 6342, 6343, 6344, 6346, 6347, 6348, 6349, 6350, 6376, 6377, 6379, 6380, 6385, 6387, 6388, 6390, 6394, 6400, 6402, 6403, 6404, 6405, 6412, 6414, 6416, 6417, 6418, 6419, 6420, 6426, 6427, 6429, 6430, 6436, 6439, 6444, 6451, 6454, 6459, 6462, 6464, 6466, 6469, 6472, 6477, 6478, 6479, 6480, 6481, 6483, 6484, 6485, 6489, 6491, 6493, 6495, 6497, 6500, 6501
 , 6502, 6518, 6519, 6521, 6522, 6523, 6524, 6527, 6528, 6530, 6531, 6533, 6534, 6535, 6536, 6537, 6538, 6540, 6541, 6542, 6546, 6547, 6548, 16770, 16772, 16774, 16775, 16779, 16780, 16783, 16786, 16788, 16789, 16790, 16793, 16794, 16795, 16799, 16802, 16803, 16804, 16805, 16864, 16869, 16871, 16873, 16874, 16875, 16878, 16879, 16913, 16927, 16928, 16957, 16958, 16959, 16960, 16961, 16962, 16963, 16964, 16965, 16966, 16967, 16968, 16969, 16970, 16971, 16972, 16974, 16975, 16976, 16977, 16978, 16979, 16980, 16981, 16982, 16983, 16984, 16985, 16986, 16987, 16988, 16989, 16990, 16992 ];
+$requires = { '16977' => [ '16972', '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6261' => [ '6500', '6481' ], '16775' => [ '16774', '16979', '16970', '16969', '16976', '16803', '6500', '16981', '16986', '6481' ], '6347' => [ '6342', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6256' => [ '6287', '6284', '6274', '6273', '6257', '6278', '6271', '6269', '6288', '6286', '6275', '6289', '6272', '6254' ], '16873' => [ '16873' ], '16965' => [ '16969' ], '6535' => [ '6377', '6500', '6524', '6481' ], '6270' => [ '6279', '6548', '6519' ], '6497' => [ '6481' ], '16967' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '16774' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '16799' => [ '16783', '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6501' => [ '6484' ], '16793' => [ '16969', '16981', '16790' ], '16783' => [ '16969' ], '6518' => [ '6489', '6481' ], '6293' =
 > [ '6293', '6300' ], '6333' => [ '6342', '6346', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 6349, 6347, 6344, 6334, 6328, 6332 ], '16794' => [ '16979', '16989', '16970', '16969', '6500', '16981', '16986', '6481' ], '6222' => [ '6292', '6223', '6377', '6300' ], '16984' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '16927' => [ '16928', '6377', '6500', '6481' ], '6531' => [ '6535', '6306', '6480', '6527', '6158', '6377', '6500', '6521', '6524', '6481' ], '6405' => [ '6416' ], '16786' => [ '16979', '16795', '16970', '16969', '16976', '6500', '16981', '16986', '6481' ], '6541' => [ '6541', '6390', '6426' ], '6263' => [ '6292', '6267', '6342', '6266', '6300' ], '6341' => [ '6347', '6333', '6341', '6334', '6332', '6342', '6329', '6344', '6337', '6348', '6328', '6339', '6346', '6343', '6330', '6335', '6349' ], '16802' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6334' => [ '6334', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 63
 46, 6349, 6347, 6344, 6342, 6328, 6332 ], '6290' => [ '6292', '6390', '6426', '6500', '6300', '6481' ], '6522' => [ '6531', '6527', '6537', '6536', '6523', '6534' ], '6527' => [ '6377', '6500', '6524', '6481' ], '16789' => [ '16969' ], '16982' => [ '16979', '16989', '16970', '16969', '6500', '16981', '16986', '6481' ], '6495' => [ '6489' ], '16804' => [ '16969', '6500', '6481' ], '16980' => [ '16979', '16989', '16970', '16969', '16976', '6500', '16981', '16986', '6481', '16961' ], '16928' => [ '16927' ], '16989' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6332' => [ '6342', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6190' => [ '6192' ], '6292' => [ '6292', '6298', '6300' ], '6298' => [ '6290', '6300' ], '6239' => [ '6484', '6501', '6483', '6480', '6489', '6158', '6416', '6462', '6500', '6155', '6481', '6417' ], '6267' => [ '6292', '6267', '6342', '6266', '6300' ], '6186' => [ '6376', '6292', '6298', '
 6186', '6300' ], '16958' => [ '16979', '16969', '6500', '16986', '6481' ], '6419' => [ '6342', '6339' ], '6394' => [ '6306', '6292', '6298', '6394', '6300', '6387' ], '6412' => [ '6430', '6390' ], '6204' => [ '6306', '6292', '6377', '6500', '6300', '6202', '6481' ], '6229' => [ '6233' ], '6342' => [ '6261', '6334', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 6346, 6349, 6347, 6344, 6342, 6328, 6332 ], '6430' => [ '6426' ], '16795' => [ '16979', '16970', '16969', '16976', '6500', '16981', '16986', '6481' ], '6390' => [ '6426' ], '16779' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6533' => [ '6377', '6500', '6481' ], '6478' => [ '6500' ], '16970' => [ '16979', '16969', '6500', '16981', '16986', '6481' ], '16987' => [ '16969' ], '6329' => [ '6342', '6346', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6349, 6347, 6344, 6334, 6328, 6332 ], '6530' => [ '6377', '6500', '6481' ], '16869' => [ '16869' ], '16974' => [ '16979', '16989', '16970', '16969
 ', '16976', '6500', '16981', '16986', '6481' ], '6226' => [ '5625' ], '6528' => [ '6377', '6500', '6481' ], '6344' => [ '6333', '6342', 6335, 6348, 6330, 6337, 6343, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6444' => [ '6292', '6300' ], '6156' => [ '6155' ], '6491' => [ '6484' ], '6337' => [ '6342', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6477' => [ '6485' ], '16957' => [ '16969' ], '6519' => [ '6489' ], '6348' => [ '6342', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6328' => [ '6342', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6266' => [ '6342' ], '16976' => [ '16979', '16989', '16970', '16969', '6500', '16981', '16986', '6481' ], '16990' => [ '16969' ], '6547' => [ '6489', '6481' ], '6537' => [ '6535', '6531', '6528', '6377', '6500', '6481' ], '6404' => [ '6403' ], '6388' => [ '6377' ], '6310' => [ '6320'
  ], '6466' => [ '6462' ], '16803' => [ '16774', '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '16983' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '6454' => [ '6439', '6292', '6377', '6300' ], '16874' => [ '6206' ], '6540' => [ '6541' ], '6244' => [ '6270', '6311', '5625', '6310', '6259', '6255' ], '16879' => [ '16869', '16879', '16864' ], '6299' => [ '6293', '6290', '6292', '6299', '6500', '6300', '6481' ], '16805' => [ '16965', '16972', '16979', '16989', '16970', '16969', '16976', '6500', '16981', '16986', '6481' ], '6339' => [ '6342', '6346', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6349, 6347, 6344, 6334, 6328, 6332 ], '6400' => [ '6394' ], '6221' => [ '6292', '6300', '6224' ], '16966' => [ '16979', '16969', '6500', '16986', '6481' ], '16964' => [ '16972' ], '16971' => [ '16979', '16969', '16990', '6500', '16986', '6481' ], '6300' => [ '6300' ], '6346' => [ '6342', '6339', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6346, 
 6349, 6347, 6344, 6334, 6328, 6332 ], '6202' => [ '6292', '6377', '6300', '6481' ], '6536' => [ '6535', '6531', '6377', '6500', '6521', '6481' ], '16975' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481' ], '16986' => [ '16979', '16969', '6500', '6481' ], '6385' => [ '6376' ], '16992' => [ '16972', '16979', '16982', '16989', '16970', '16969', '16976', '16985', '6500', '16981', '16986', '6481', '16961' ], '6538' => [ '6535', '6530', '6377', '6500', '6481' ], '6479' => [ '6483' ], '6343' => [ '6342', 6335, 6348, 6330, 6333, 6337, 6343, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6414' => [ '6417' ], '6523' => [ '6533', '6377', '6500', '6481' ], '6534' => [ '6535', '6531', '6377', '6500', '6481' ], '6234' => [ '6236' ], '6330' => [ '6342', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6493' => [ '6480' ], '6521' => [ '6377', '6500', '6521', '6481' ], '6335' => [ '6342', '6343', 6335, 6348, 6330, 6333, 
 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '6524' => [ '6480', '6530', '6377', '6500', '6521', '6524', '6199', '6481' ], '16772' => [ '16775', '16774', '16979', '16970', '16969', '16976', '16803', '16983', '6500', '16981', '16986', '6481' ], '6349' => [ '6342', '6343', 6335, 6348, 6330, 6333, 6337, 6329, 6339, 6346, 6349, 6347, 6344, 6334, 6328, 6332 ], '16864' => [ '16871' ], '6258' => [ '6258' ], '16968' => [ '16977', '16960', '16972', '16979', '16982', '16980', '16989', '16958', '16970', '16987', '16974', '16969', '16957', '16976', '16983', '16985', '6500', '16964', '16981', '16986', '16992', '16968', '6481', '16961', '16988', '16963', '16959' ], '16878' => [ '16878' ], '16978' => [ '16979', '16989', '16970', '16969', '6500', '16981', '16986', '6481' ], '6502' => [ '6501', '6491' ], '6157' => [ '6158' ], '16788' => [ '16979', '16969', '6500', '16986', '6481' ], '16790' => [ '16969' ], '16770' => [ '16965', '16979', '16989', '16970', '16974', '16969', '1
 6990', '16976', '16805', '6500', '16971', '16981', '16986', '6481' ], '6210' => [ '6306', '6210' ], '6379' => [ '6387' ], '6469' => [ '6427' ], '6259' => [ '6518', '6547' ], '6206' => [ '6206' ], '16961' => [ '16979', '16989', '16970', '16969', '6500', '16981', '16986', '6481' ], '16963' => [ '16979', '16969', '6500', '16986', '6481' ], '6250' => [ '6256', '6244' ], '16988' => [ '16969', '16985' ], '16959' => [ '16979', '16970', '16969', '6500', '16981', '16986', '6481', '16963' ] };
+check_it($list_unsorted, $requires, 0);
+
+$list_unsorted = [ 0 .. 10 ];
+check_it($list_unsorted, create_random($list_unsorted), 1) foreach 1 .. 10000;
+
+
+sub check_it {
+    my ($list_unsorted, $requires, $dump_it) = @_;
+
+    my @sorted = eval { URPM::sort_graph($list_unsorted, $requires) };
+    ok(@sorted > 0);
+
+    if (!@sorted && $dump_it) {
+	require Data::Dumper;
+	$Data::Dumper::Sortkeys = 1;
+	warn Data::Dumper::Dumper($list_unsorted, $requires);
+	warn "$@\n";
+	exit 1;
+    }
+}
+
+
+sub create_random {
+    my ($list_unsorted) = @_;
+    my %requires;
+
+    foreach my $i (@$list_unsorted) {
+	my $nb = int(rand(1) * 2.8);
+	push @{$requires{$i}}, grep { $_ != $i } uniq(map { int(rand @$list_unsorted) } 1 .. $nb);
+    }
+    \%requires;
+}
+sub uniq { my %l; $l{$_} = 1 foreach @_; grep { delete $l{$_} } @_ }

Added: rpm/perl-URPM/trunk/t/synthesis.t
===================================================================
--- rpm/perl-URPM/trunk/t/synthesis.t	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/synthesis.t	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,151 @@
+#!/usr/bin/perl
+
+use strict ;
+use warnings ;
+use Test::More tests => 94;
+use URPM;
+
+chdir 't' if -d 't';
+my $file1 = 'synthesis.sample.cz';
+
+open my $f, "| gzip -9 >$file1";
+print $f <<'EOF';
+ at provides@glibc-devel == 6:2.2.4-25mdk
+ at requires@/sbin/install-info at glibc == 2.2.4 at kernel-headers@kernel-headers >= 2.2.1@/bin/sh@/bin/sh@/bin/sh at rpmlib(PayloadFilesHavePrefix) <= 4.0-1 at rpmlib(CompressedFileNames) <= 3.0.4-1
+ at conflicts@texinfo < 3.11 at gcc < 2.96-0.50mdk
+ at obsoletes@libc-debug at libc-headers@libc-devel at linuxthreads-devel@glibc-debug
+ at info@glibc-devel-2.2.4-25mdk.i586 at 6@45692097 at Development/C
+EOF
+close $f;
+
+END { unlink $file1 }
+
+my $a = new URPM;
+ok($a);
+
+my ($first, $end);
+
+($first, $end) = URPM->new->parse_synthesis('empty_synthesis.cz');
+is("$first $end", "0 -1", 'parse empty synthesis');
+
+is(URPM->new->parse_synthesis('buggy_synthesis.cz'), undef, 'parse buggy synthesis');
+
+($first, $end) = $a->parse_synthesis($file1);
+ok($first == 0 && $end == 0);
+is(int @{$a->{depslist}}, 1);
+ok(keys(%{$a->{provides}}) == 3);
+ok(defined $a->{provides}{'glibc-devel'});
+ok(exists $a->{provides}{'/bin/sh'});
+ok(! defined $a->{provides}{'/bin/sh'});
+ok(exists $a->{provides}{'/sbin/install-info'});
+ok(! defined $a->{provides}{'/sbin/install-info'});
+
+my $pkg = $a->{depslist}[0];
+ok($pkg);
+ok($pkg->name eq 'glibc-devel');
+ok($pkg->version eq '2.2.4');
+ok($pkg->release eq '25mdk');
+ok($pkg->arch eq 'i586');
+ok($pkg->fullname eq 'glibc-devel-2.2.4-25mdk.i586');
+ok(!defined $pkg->buildarchs);
+ok(!defined $pkg->buildhost);
+is($pkg->buildtime,0);
+ok(!defined $pkg->changelog_name);
+ok(!defined $pkg->changelog_text);
+ok(!defined $pkg->changelog_time);
+
+my ($name, $version, $release, $arch, @l) = $pkg->fullname;
+ok(@l == 0);
+ok($name eq 'glibc-devel');
+ok($version eq '2.2.4');
+ok($release eq '25mdk');
+ok($arch eq 'i586');
+
+ok($pkg->epoch == 6);
+ok($pkg->size == 45692097);
+ok($pkg->group eq 'Development/C');
+ok($pkg->filename eq 'glibc-devel-2.2.4-25mdk.i586.rpm');
+ok(defined $pkg->id);
+ok($pkg->id == 0);
+ok($pkg->set_id(6) == 0);
+ok($pkg->id == 6);
+ok($pkg->set_id == 6);
+ok(! defined $pkg->id);
+ok(! defined $pkg->set_id(0));
+ok(defined $pkg->id);
+ok($pkg->id == 0);
+
+my @obsoletes = $pkg->obsoletes;
+ok(@obsoletes == 5);
+ok($obsoletes[0] eq 'libc-debug');
+ok($obsoletes[4] eq 'glibc-debug');
+
+my @conflicts = $pkg->conflicts;
+ok(@conflicts == 2);
+ok($conflicts[0] eq 'texinfo < 3.11');
+ok($conflicts[1] eq 'gcc < 2.96-0.50mdk');
+
+my @requires = $pkg->requires;
+ok(@requires == 9);
+ok($requires[0] eq '/sbin/install-info');
+ok($requires[8] eq 'rpmlib(CompressedFileNames) <= 3.0.4-1');
+
+my @provides = $pkg->provides;
+ok(@provides == 1);
+ok($provides[0] eq 'glibc-devel == 6:2.2.4-25mdk');
+
+my @files = $pkg->files;
+ok(@files == 0);
+
+ok($pkg->compare("6:2.2.4-25mdk") == 0);
+ok($pkg->compare("2.2.4-25mdk") > 0);
+ok($pkg->compare("6:2.2.4") == 0);
+ok($pkg->compare("2.2.3") > 0);
+ok($pkg->compare("2.2") > 0);
+ok($pkg->compare("2") > 0);
+ok($pkg->compare("2.2.4.0") > 0);
+ok($pkg->compare("2.2.5") > 0);
+ok($pkg->compare("2.1.7") > 0);
+ok($pkg->compare("2.3.1") > 0);
+ok($pkg->compare("2.2.31") > 0);
+ok($pkg->compare("2.2.4-25") > 0);
+ok($pkg->compare("2.2.4-25.1mdk") > 0);
+ok($pkg->compare("2.2.4-24mdk") > 0);
+ok($pkg->compare("2.2.4-26mdk") > 0);
+ok($pkg->compare("6:2.2.4-25.1mdk") < 0);
+ok($pkg->compare("6:2.2.4.0") < 0);
+ok($pkg->compare("6:2.2.5") < 0);
+ok($pkg->compare("6:2.2.31") < 0);
+ok($pkg->compare("6:2.3.1") < 0);
+ok($pkg->compare("6:2.2.4-24mdk") > 0);
+ok($pkg->compare("6:2.2.4-26mdk") < 0);
+ok($pkg->compare("7:2.2.4-26mdk") < 0);
+ok($pkg->compare("7:2.2.4-24mdk") < 0);
+
+ok($a->traverse() == 1);
+
+my $test = 0;
+ok($a->traverse(sub { my ($pkg) = @_; $test = $pkg->name eq 'glibc-devel' }) == 1);
+ok($test);
+ok($a->traverse_tag('name', [ 'glibc-devel' ]) == 1);
+ok($a->traverse_tag('name', [ 'glibc' ]) == 0);
+
+$test = 0;
+ok($a->traverse_tag('name', [ 'glibc-devel' ], sub { my ($pkg) = @_; $test = $pkg->name eq 'glibc-devel' }) == 1);
+ok($test);
+
+ at conflicts = $pkg->conflicts_nosense;
+ok(@conflicts == 2);
+ok($conflicts[0] eq 'texinfo');
+ok($conflicts[1] eq 'gcc');
+
+ at requires = $pkg->requires_nosense;
+ok(@requires == 9);
+ok($requires[0] eq '/sbin/install-info');
+ok($requires[1] eq 'glibc');
+ok($requires[3] eq 'kernel-headers');
+ok($requires[8] eq 'rpmlib(CompressedFileNames)');
+
+ at provides = $pkg->provides_nosense;
+ok(@provides == 1);
+ok($provides[0] eq 'glibc-devel');

Added: rpm/perl-URPM/trunk/t/test-rpm.spec
===================================================================
--- rpm/perl-URPM/trunk/t/test-rpm.spec	                        (rev 0)
+++ rpm/perl-URPM/trunk/t/test-rpm.spec	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,40 @@
+# $Id: test-rpm.spec 258552 2009-07-22 18:19:56Z peroyvind $
+
+# prevent distepoch & disttag to be added and appended to package filename
+%undefine distepoch
+%undefine disttag
+
+Summary: test rpm for perl-URPM test suite
+BuildArch: noarch
+Name: test-rpm
+Version: 1.0
+Release: 1mdk
+License: GPL
+Group: Application/Development
+BuildRoot: %{_tmppath}/%{name}-root
+
+%description
+test rpm
+
+%prep
+
+%build
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT%_sysconfdir
+
+date >> $RPM_BUILD_ROOT%_sysconfdir/%name
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%config(noreplace) %_sysconfdir/%name
+
+%changelog
+* Thu Apr 22 2004 Olivier Thauvin <thauvin at aerov.jussieu.fr> 1-1mdk
+- initial build 
+
+

Added: rpm/perl-URPM/trunk/typemap
===================================================================
--- rpm/perl-URPM/trunk/typemap	                        (rev 0)
+++ rpm/perl-URPM/trunk/typemap	2011-02-04 13:41:50 UTC (rev 419)
@@ -0,0 +1,3 @@
+URPM::DB		T_PTROBJ
+URPM::Transaction	T_PTROBJ
+URPM::Package		T_PTROBJ
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/mageia-sysadm/attachments/20110204/fb8a6b76/attachment-0001.html>


More information about the Mageia-sysadm mailing list