aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4159
-rw-r--r--MANIFEST22
-rw-r--r--META.yml11
-rw-r--r--Makefile.PL74
-rw-r--r--NEWS431
-rw-r--r--README7
-rw-r--r--URPM.pm879
-rw-r--r--URPM.xs3944
-rw-r--r--URPM/.perl_checker1
-rw-r--r--URPM/Build.pm528
-rw-r--r--URPM/Query.pm40
-rw-r--r--URPM/Resolve.pm2003
-rw-r--r--URPM/Signature.pm91
-rw-r--r--t/00prepare.t16
-rw-r--r--t/buggy_synthesis.czbin0 -> 40711 bytes
-rw-r--r--t/empty_synthesis.czbin0 -> 20 bytes
-rw-r--r--t/fatal.t23
-rw-r--r--t/parse.t119
-rw-r--r--t/pod.t5
-rw-r--r--t/rpmdb.t46
-rw-r--r--t/sort_graph.t76
-rw-r--r--t/synthesis.t151
-rw-r--r--t/test-rpm.spec40
-rw-r--r--typemap3
24 files changed, 12669 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..f244eff
--- /dev/null
+++ b/ChangeLog
@@ -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.
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..cf8bc4f
--- /dev/null
+++ b/MANIFEST
@@ -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)
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..5b9416f
--- /dev/null
+++ b/META.yml
@@ -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
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..eb0a823
--- /dev/null
+++ b/Makefile.PL
@@ -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` . ' -lrpmbuild';
+if ($hversion ge hexversion("4.9.0") && $hversion lt hexversion("5.0")) {
+ # rpm.org version 4.9.0
+ push @rpmflags, "-DRPM490";
+}
+
+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/*" },
+);
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..f8219f9
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,431 @@
+Version 3.38.1 - 16 November 2010
+
+- fix crashing while removing several packages (#248)
+- enable to compile with rpm-4.9.x
+
+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
diff --git a/README b/README
new file mode 100644
index 0000000..4903676
--- /dev/null
+++ b/README
@@ -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.
diff --git a/URPM.pm b/URPM.pm
new file mode 100644
index 0000000..9daf00f
--- /dev/null
+++ b/URPM.pm
@@ -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.1';
+
+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@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
diff --git a/URPM.xs b/URPM.xs
new file mode 100644
index 0000000..4ef9e76
--- /dev/null
+++ b/URPM.xs
@@ -0,0 +1,3944 @@
+/* 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
+
+static inline void *_free(const void * p) {
+ if (p != NULL) free((void *)p);
+ return NULL;
+}
+typedef struct rpmSpec_s * Spec;
+
+#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)) {
+ memset((void*)&flags, 0, sizeof(flags));
+ memset((void*)&list_evr, 0, sizeof(list_evr));
+ 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;
+ case RPM_CHAR_TYPE:
+ 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 */
+ /* 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;
+ int32_t size;
+
+ basename = strrchr(filename, '/');
+ size = fdSize(fd);
+ 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) {
+#ifdef RPM490
+ fd = fdLink(fd);
+#else
+ fd = fdLink(fd, "persist perl-URPM");
+#endif
+ Fcntl(fd, F_SETFD, (void *)1); /* necessary to avoid forked/execed process to lock removable */
+ }
+ PUTBACK;
+ } else if (callback == td->callback_close) {
+#ifdef RPM490
+ fd = fdFree(fd);
+#else
+ fd = fdFree(fd, "persist perl-URPM");
+#endif
+ 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:
+ CODE:
+ read_config_files(0);
+ if (pkg->info) {
+ char *arch;
+ char *eos;
+
+ get_fullname_parts(pkg, NULL, NULL, NULL, &arch, &eos);
+ *eos = 0;
+ RETVAL = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+ *eos = '@';
+ } else if (pkg->h && headerIsEntry(pkg->h, RPMTAG_SOURCERPM)) {
+ char *arch = get_name(pkg->h, RPMTAG_ARCH);
+ RETVAL = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+ } else {
+ RETVAL = 0;
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Pkg_is_platform_compat(pkg)
+ URPM::Package pkg
+ INIT:
+ CODE:
+ croak("is_platform_compat() is available only since rpm 4.4.8");
+ { /* to match last } and avoid another #ifdef for it */
+ 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@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:
+#ifdef RPM490
+ db->ts = rpmtsLink(db->ts);
+#else
+ db->ts = rpmtsLink(db->ts, "URPM::DB::traverse");
+#endif
+ 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);
+#ifdef RPM490
+ db->ts = rpmtsLink(db->ts);
+#else
+ db->ts = rpmtsLink(db->ts, "URPM::DB::traverse_tag");
+#endif
+ 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;
+#ifdef RPM490
+ db->ts = rpmtsLink(db->ts);
+#else
+ db->ts = rpmtsLink(db->ts, "URPM::DB::traverse_tag");
+#endif
+ 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. */
+#ifdef RPM490
+ db->ts = rpmtsLink(db->ts);
+#else
+ db->ts = rpmtsLink(db->ts, "URPM::DB::create_transaction");
+#endif
+ ++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;
+ rpmRelocation *relocations = NULL;
+ /* 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);
+ relocations = calloc(j + 1, sizeof(rpmRelocation));
+ while (--j >= 0) {
+ SV **e = av_fetch(excludepath, j, 0);
+ if (e != NULL && *e != NULL) {
+ relocations[j].oldPath = SvPV_nolen(*e);
+ }
+ }
+ }
+ }
+ }
+ }
+ 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 */
+ free(relocations);
+ } 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);
+#ifdef RPM490
+ trans->ts = rpmtsLink(trans->ts);
+#else
+ trans->ts = rpmtsLink(trans->ts, "URPM::Transaction::run");
+#endif
+ 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:
+#ifdef RPM490
+ rpmts ts = rpmtsLink(db->ts);
+#else
+ rpmts ts = rpmtsLink(db->ts, "URPM::import_pubkey_file");
+#endif
+ 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:
+ CODE:
+ read_config_files(0);
+ RETVAL=rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+ OUTPUT:
+ RETVAL
+
+int
+Urpm_osscore(os)
+ const char * os
+ PREINIT:
+ CODE:
+ read_config_files(0);
+ RETVAL=rpmMachineScore(RPM_MACHTABLE_INSTOS, os);
+ OUTPUT:
+ RETVAL
+
+int
+Urpm_platformscore(platform)
+ const char * platform
+ CODE:
+ read_config_files(0);
+ unused_variable(platform);
+ croak("platformscore() is available only since rpm 4.4.8");
+ RETVAL=0;
+ 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;
+ Header header = 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
+#ifdef RPM490
+ spec = rpmSpecParse(specfile, SPEC_ANYARCH|SPEC_FORCE, NULL);
+ header = rpmSpecSourceHeader(spec);
+ if (spec) {
+#else
+ if (!parseSpec(ts, specfile, "/", NULL, 0, NULL, NULL, SPEC_ANYARCH, SPEC_FORCE)) {
+#endif
+ SV *sv_pkg;
+#ifndef RPM490
+ // FIXME: has disappeared in rpm-4.9.0rpmSpecParse
+ // (See http://www.rpm.org/wiki/Releases/4.9.0)
+ spec = rpmtsSetSpec(ts, NULL);
+ header = spec->sourceHeader;
+ if (! header)
+ initSourceHeader(spec);
+#endif
+ pkg = (URPM__Package)calloc(1, sizeof(struct s_Package));
+ headerPutString(header, 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(header, &td);
+ }
+
+ pkg->h = headerLink(spec->sourceHeader);
+ sv_pkg = sv_newmortal();
+ sv_setref_pv(sv_pkg, "URPM::Package", (void*)pkg);
+ XPUSHs(sv_pkg);
+#ifdef RPM490
+ spec = rpmSpecFree(spec);
+#else
+ spec = freeSpec(spec);
+#endif
+ } 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: */
diff --git a/URPM/.perl_checker b/URPM/.perl_checker
new file mode 100644
index 0000000..202e053
--- /dev/null
+++ b/URPM/.perl_checker
@@ -0,0 +1 @@
+Basedir ..
diff --git a/URPM/Build.pm b/URPM/Build.pm
new file mode 100644
index 0000000..f298707
--- /dev/null
+++ b/URPM/Build.pm
@@ -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@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;
diff --git a/URPM/Query.pm b/URPM/Query.pm
new file mode 100644
index 0000000..14256a4
--- /dev/null
+++ b/URPM/Query.pm
@@ -0,0 +1,40 @@
+package URPM;
+
+use strict;
+use warnings;
+
+# Olivier Thauvin <thauvin@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;
diff --git a/URPM/Resolve.pm b/URPM/Resolve.pm
new file mode 100644
index 0000000..b82b45b
--- /dev/null
+++ b/URPM/Resolve.pm
@@ -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;
diff --git a/URPM/Signature.pm b/URPM/Signature.pm
new file mode 100644
index 0000000..003af07
--- /dev/null
+++ b/URPM/Signature.pm
@@ -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;
diff --git a/t/00prepare.t b/t/00prepare.t
new file mode 100644
index 0000000..7ea2704
--- /dev/null
+++ b/t/00prepare.t
@@ -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' );
+
diff --git a/t/buggy_synthesis.cz b/t/buggy_synthesis.cz
new file mode 100644
index 0000000..fa1f68d
--- /dev/null
+++ b/t/buggy_synthesis.cz
Binary files differ
diff --git a/t/empty_synthesis.cz b/t/empty_synthesis.cz
new file mode 100644
index 0000000..8aee682
--- /dev/null
+++ b/t/empty_synthesis.cz
Binary files differ
diff --git a/t/fatal.t b/t/fatal.t
new file mode 100644
index 0000000..0cfeafa
--- /dev/null
+++ b/t/fatal.t
@@ -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' );
diff --git a/t/parse.t b/t/parse.t
new file mode 100644
index 0000000..148e788
--- /dev/null
+++ b/t/parse.t
@@ -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/;
+}
diff --git a/t/pod.t b/t/pod.t
new file mode 100644
index 0000000..df36c2b
--- /dev/null
+++ b/t/pod.t
@@ -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();
diff --git a/t/rpmdb.t b/t/rpmdb.t
new file mode 100644
index 0000000..b263013
--- /dev/null
+++ b/t/rpmdb.t
@@ -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');
diff --git a/t/sort_graph.t b/t/sort_graph.t
new file mode 100644
index 0000000..73750c4
--- /dev/null
+++ b/t/sort_graph.t
@@ -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 ], '5937' => [ 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' => [ 5856 ], '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, 4444 ], '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, 692, 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 ], '6178' => [], '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, 6346, 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', '16990', '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{$_} } @_ }
diff --git a/t/synthesis.t b/t/synthesis.t
new file mode 100644
index 0000000..6729b3b
--- /dev/null
+++ b/t/synthesis.t
@@ -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';
+@provides@glibc-devel == 6:2.2.4-25mdk
+@requires@/sbin/install-info@glibc == 2.2.4@kernel-headers@kernel-headers >= 2.2.1@/bin/sh@/bin/sh@/bin/sh@rpmlib(PayloadFilesHavePrefix) <= 4.0-1@rpmlib(CompressedFileNames) <= 3.0.4-1
+@conflicts@texinfo < 3.11@gcc < 2.96-0.50mdk
+@obsoletes@libc-debug@libc-headers@libc-devel@linuxthreads-devel@glibc-debug
+@info@glibc-devel-2.2.4-25mdk.i586@6@45692097@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);
+
+@conflicts = $pkg->conflicts_nosense;
+ok(@conflicts == 2);
+ok($conflicts[0] eq 'texinfo');
+ok($conflicts[1] eq 'gcc');
+
+@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)');
+
+@provides = $pkg->provides_nosense;
+ok(@provides == 1);
+ok($provides[0] eq 'glibc-devel');
diff --git a/t/test-rpm.spec b/t/test-rpm.spec
new file mode 100644
index 0000000..c18f505
--- /dev/null
+++ b/t/test-rpm.spec
@@ -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@aerov.jussieu.fr> 1-1mdk
+- initial build
+
+
diff --git a/typemap b/typemap
new file mode 100644
index 0000000..031189e
--- /dev/null
+++ b/typemap
@@ -0,0 +1,3 @@
+URPM::DB T_PTROBJ
+URPM::Transaction T_PTROBJ
+URPM::Package T_PTROBJ