diff options
-rw-r--r-- | ChangeLog | 4159 | ||||
-rw-r--r-- | MANIFEST | 22 | ||||
-rw-r--r-- | META.yml | 11 | ||||
-rw-r--r-- | Makefile.PL | 74 | ||||
-rw-r--r-- | NEWS | 431 | ||||
-rw-r--r-- | README | 7 | ||||
-rw-r--r-- | URPM.pm | 879 | ||||
-rw-r--r-- | URPM.xs | 3944 | ||||
-rw-r--r-- | URPM/.perl_checker | 1 | ||||
-rw-r--r-- | URPM/Build.pm | 528 | ||||
-rw-r--r-- | URPM/Query.pm | 40 | ||||
-rw-r--r-- | URPM/Resolve.pm | 2003 | ||||
-rw-r--r-- | URPM/Signature.pm | 91 | ||||
-rw-r--r-- | t/00prepare.t | 16 | ||||
-rw-r--r-- | t/buggy_synthesis.cz | bin | 0 -> 40711 bytes | |||
-rw-r--r-- | t/empty_synthesis.cz | bin | 0 -> 20 bytes | |||
-rw-r--r-- | t/fatal.t | 23 | ||||
-rw-r--r-- | t/parse.t | 119 | ||||
-rw-r--r-- | t/pod.t | 5 | ||||
-rw-r--r-- | t/rpmdb.t | 46 | ||||
-rw-r--r-- | t/sort_graph.t | 76 | ||||
-rw-r--r-- | t/synthesis.t | 151 | ||||
-rw-r--r-- | t/test-rpm.spec | 40 | ||||
-rw-r--r-- | typemap | 3 |
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/*" }, +); @@ -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 @@ -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. @@ -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 @@ -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 Binary files differnew file mode 100644 index 0000000..fa1f68d --- /dev/null +++ b/t/buggy_synthesis.cz diff --git a/t/empty_synthesis.cz b/t/empty_synthesis.cz Binary files differnew file mode 100644 index 0000000..8aee682 --- /dev/null +++ b/t/empty_synthesis.cz 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/; +} @@ -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 + + @@ -0,0 +1,3 @@ +URPM::DB T_PTROBJ +URPM::Transaction T_PTROBJ +URPM::Package T_PTROBJ |