From 36512985f0735669740aeb8230e229001c871a01 Mon Sep 17 00:00:00 2001 From: "biao716.wang" Date: Fri, 8 Jul 2022 20:04:51 +0900 Subject: [PATCH] Imported Upstream version 0.37.0 Change-Id: I44d8429f225ee9f63fa9ad35365861ed11badd14 Signed-off-by: biao716.wang --- BSSolv.pm | 2 +- BSSolv.xs | 4311 +++++++++++++++----- Makefile.PL | 7 +- debian/control | 2 +- libsolv-0.6.15/BUGS | 7 - libsolv-0.6.15/NEWS | 52 - libsolv-0.6.15/ext/repo_comps.c | 396 -- libsolv-0.6.15/ext/repo_zyppdb.c | 370 -- libsolv-0.6.15/package/libsolv.spec.in | 268 -- libsolv-0.6.15/src/bitmap.c | 100 - libsolv-0.6.15/src/cplxdeps.c | 454 --- libsolv-0.6.15/src/problems.h | 58 - libsolv-0.6.15/src/repo_write.h | 37 - libsolv-0.6.15/src/selection.c | 1185 ------ libsolv-0.6.15/src/selection.h | 50 - libsolv-0.6.15/src/solver_private.h | 95 - libsolv-0.6.15/src/solvversion.h.in | 27 - libsolv-0.6.15/tools/common_write.c | 338 -- libsolv-0.6.15/tools/patchcheck.c | 642 --- libsolv-0.6.15/tools/rpmmd2solv.c | 163 - {libsolv-0.6.15 => libsolv-0.7.2}/.emacs-dirvars | 0 {libsolv-0.6.15 => libsolv-0.7.2}/.gitignore | 0 {libsolv-0.6.15 => libsolv-0.7.2}/.travis.yml | 0 {libsolv-0.6.15 => libsolv-0.7.2}/CMakeLists.txt | 145 +- {libsolv-0.6.15 => libsolv-0.7.2}/CREDITS | 0 {libsolv-0.6.15 => libsolv-0.7.2}/INSTALL | 0 {libsolv-0.6.15 => libsolv-0.7.2}/LICENSE.BSD | 0 libsolv-0.7.2/NEWS | 183 + {libsolv-0.6.15 => libsolv-0.7.2}/README | 28 +- libsolv-0.7.2/TODO_1.0 | 18 + {libsolv-0.6.15 => libsolv-0.7.2}/VERSION.cmake | 8 +- .../bindings/CMakeLists.txt | 3 + .../bindings/perl/CMakeLists.txt | 0 .../bindings/python/CMakeLists.txt | 19 +- libsolv-0.7.2/bindings/python3/CMakeLists.txt | 38 + .../bindings/ruby/CMakeLists.txt | 0 {libsolv-0.6.15 => libsolv-0.7.2}/bindings/solv.i | 579 ++- .../bindings/tcl/CMakeLists.txt | 0 .../bindings/tcl/solv.tm.in | 0 .../cmake/modules/FindCheck.cmake | 0 .../cmake/modules/FindEXPAT.cmake | 0 .../cmake/modules/FindLZMA.cmake | 0 .../cmake/modules/FindLibSolv.cmake | 0 .../modules/FindPackageHandleStandardArgs.cmake | 0 .../cmake/modules/FindRuby.cmake | 0 .../cmake/modules/_CMakeParseArguments.cmake | 0 .../doc/CMakeLists.txt | 6 +- {libsolv-0.6.15 => libsolv-0.7.2}/doc/Makefile.gen | 10 +- .../doc/appdata2solv.txt | 4 + .../doc/archpkgs2solv.txt | 4 + .../doc/archrepo2solv.txt | 4 + .../doc/comps2solv.txt | 4 + {libsolv-0.6.15 => libsolv-0.7.2}/doc/deb2solv.txt | 4 + .../doc/deltainfoxml2solv.txt | 4 + {libsolv-0.6.15 => libsolv-0.7.2}/doc/dumpsolv.txt | 4 + .../doc/filters/xcode.conf | 0 .../doc/filters/xcode.pl | 0 .../doc => libsolv-0.7.2/doc/gen}/appdata2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/archpkgs2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/archrepo2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/comps2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/deb2solv.1 | 6 +- .../doc/gen}/deltainfoxml2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/dumpsolv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/helix2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/installcheck.1 | 6 +- .../doc/gen}/libsolv-bindings.3 | 543 ++- .../doc/gen}/libsolv-constantids.3 | 6 +- .../doc/gen}/libsolv-history.3 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/libsolv-pool.3 | 75 +- .../doc => libsolv-0.7.2/doc/gen}/libsolv.3 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/mdk2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/mergesolv.1 | 6 +- libsolv-0.7.2/doc/gen/repo2solv.1 | 79 + .../doc => libsolv-0.7.2/doc/gen}/repomdxml2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/rpmdb2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/rpmmd2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/rpms2solv.1 | 6 +- libsolv-0.7.2/doc/gen/solv.1 | 102 + .../doc => libsolv-0.7.2/doc/gen}/susetags2solv.1 | 6 +- .../doc => libsolv-0.7.2/doc/gen}/testsolv.1 | 6 +- .../doc/gen}/updateinfoxml2solv.1 | 6 +- .../doc/helix2solv.txt | 4 + .../doc/installcheck.txt | 4 + .../doc/libsolv-bindings.txt | 391 +- .../doc/libsolv-constantids.txt | 3 + .../doc/libsolv-history.txt | 4 + .../doc/libsolv-pool.txt | 75 +- {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv.txt | 3 + {libsolv-0.6.15 => libsolv-0.7.2}/doc/mdk2solv.txt | 4 + .../doc/mergesolv.txt | 4 + libsolv-0.7.2/doc/repo2solv.txt | 60 + .../doc/repomdxml2solv.txt | 4 + .../doc/rpmdb2solv.txt | 4 + .../doc/rpmmd2solv.txt | 4 + .../doc/rpms2solv.txt | 4 + libsolv-0.7.2/doc/solv.txt | 73 + .../doc/susetags2solv.txt | 4 + {libsolv-0.6.15 => libsolv-0.7.2}/doc/testsolv.txt | 4 + .../doc/updateinfoxml2solv.txt | 4 + .../examples/CMakeLists.txt | 0 {libsolv-0.6.15 => libsolv-0.7.2}/examples/p5solv | 6 +- {libsolv-0.6.15 => libsolv-0.7.2}/examples/pysolv | 5 +- {libsolv-0.6.15 => libsolv-0.7.2}/examples/rbsolv | 1 + .../tools => libsolv-0.7.2/examples}/repo2solv.sh | 25 +- .../examples/solv/CMakeLists.txt | 0 .../examples/solv/checksig.c | 12 +- .../examples/solv/checksig.h | 0 .../examples/solv/deltarpm.c | 4 +- .../examples/solv/deltarpm.h | 0 .../examples/solv/fastestmirror.c | 0 .../examples/solv/fastestmirror.h | 0 .../examples/solv/fileconflicts.c | 7 +- .../examples/solv/fileconflicts.h | 0 .../examples/solv/fileprovides.c | 0 .../examples/solv/fileprovides.h | 0 .../examples/solv/mirror.c | 0 .../examples/solv/mirror.h | 0 .../examples/solv/patchjobs.c | 6 +- .../examples/solv/patchjobs.h | 0 .../examples/solv/repoinfo.c | 24 +- .../examples/solv/repoinfo.h | 0 .../examples/solv/repoinfo_cache.c | 0 .../examples/solv/repoinfo_cache.h | 0 .../examples/solv/repoinfo_config_debian.c | 0 .../examples/solv/repoinfo_config_debian.h | 0 .../examples/solv/repoinfo_config_urpmi.c | 0 .../examples/solv/repoinfo_config_urpmi.h | 0 .../examples/solv/repoinfo_config_yum.c | 10 +- .../examples/solv/repoinfo_config_yum.h | 0 .../examples/solv/repoinfo_download.c | 5 +- .../examples/solv/repoinfo_download.h | 0 .../examples/solv/repoinfo_system_debian.c | 0 .../examples/solv/repoinfo_system_debian.h | 0 .../examples/solv/repoinfo_system_rpm.c | 15 +- .../examples/solv/repoinfo_system_rpm.h | 0 .../examples/solv/repoinfo_type_debian.c | 0 .../examples/solv/repoinfo_type_debian.h | 0 .../examples/solv/repoinfo_type_mdk.c | 21 +- .../examples/solv/repoinfo_type_mdk.h | 0 .../examples/solv/repoinfo_type_rpmmd.c | 7 + .../examples/solv/repoinfo_type_rpmmd.h | 0 .../examples/solv/repoinfo_type_susetags.c | 9 +- .../examples/solv/repoinfo_type_susetags.h | 0 .../examples/solv/solv.c | 193 +- {libsolv-0.6.15 => libsolv-0.7.2}/examples/tclsolv | 6 +- .../ext/CMakeLists.txt | 27 +- .../ext/libsolvext.ver | 2 + .../ext/pool_fileconflicts.c | 371 +- .../ext/pool_fileconflicts.h | 0 .../ext/pool_parserpmrichdep.c | 13 +- .../ext/pool_parserpmrichdep.h | 0 .../ext/repo_appdata.c | 350 +- .../ext/repo_appdata.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_arch.c | 5 +- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_arch.h | 0 .../ext/repo_autopattern.c | 50 +- .../ext/repo_autopattern.h | 0 libsolv-0.7.2/ext/repo_comps.c | 232 ++ {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_comps.h | 0 .../ext/repo_content.c | 9 +- .../ext/repo_content.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_cudf.c | 16 +- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_cudf.h | 0 libsolv-0.7.2/ext/repo_deb.c | 891 ++++ .../ext/repo_deb.c.orig | 4 +- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_deb.h | 0 .../ext/repo_deltainfoxml.c | 216 +- .../ext/repo_deltainfoxml.h | 0 .../ext/repo_haiku.cpp | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_haiku.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_helix.c | 301 +- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_helix.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_mdk.c | 161 +- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_mdk.h | 0 .../ext/repo_products.c | 272 +- .../ext/repo_products.h | 0 .../ext/repo_pubkey.c | 2 - .../ext/repo_pubkey.h | 2 +- .../ext/repo_releasefile_products.c | 0 .../ext/repo_releasefile_products.h | 0 .../ext/repo_repomdxml.c | 221 +- .../ext/repo_repomdxml.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmdb.c | 1190 +++--- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmdb.h | 1 + libsolv-0.7.2/ext/repo_rpmdb_bdb.h | 487 +++ libsolv-0.7.2/ext/repo_rpmdb_librpm.h | 241 ++ {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmmd.c | 776 ++-- {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmmd.h | 0 .../ext/repo_susetags.c | 690 ++-- .../ext/repo_susetags.h | 0 .../ext/repo_updateinfoxml.c | 291 +- .../ext/repo_updateinfoxml.h | 0 libsolv-0.7.2/ext/repo_zyppdb.c | 200 + .../ext/repo_zyppdb.h | 0 libsolv-0.7.2/ext/repodata_diskusage.c | 78 + libsolv-0.7.2/ext/repodata_diskusage.h | 10 + libsolv-0.7.2/ext/solv_jsonparser.c | 294 ++ libsolv-0.7.2/ext/solv_jsonparser.h | 49 + .../ext/solv_pgpvrfy.c | 0 .../ext/solv_pgpvrfy.h | 0 .../ext/solv_xfopen.c | 373 +- .../ext/solv_xfopen.h | 0 libsolv-0.7.2/ext/solv_xmlparser.c | 334 ++ libsolv-0.7.2/ext/solv_xmlparser.h | 56 + libsolv-0.7.2/ext/solv_zchunk.c | 408 ++ libsolv-0.7.2/ext/solv_zchunk.h | 13 + {libsolv-0.6.15 => libsolv-0.7.2}/ext/testcase.c | 543 ++- {libsolv-0.6.15 => libsolv-0.7.2}/ext/testcase.h | 6 + {libsolv-0.6.15 => libsolv-0.7.2}/ext/tools_util.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/libsolv.pc.in | 4 +- libsolv-0.7.2/libsolvext.pc.in | 9 + .../package/libsolv.changes | 260 ++ libsolv-0.7.2/package/libsolv.spec.in | 342 ++ .../src/CMakeLists.txt | 6 +- libsolv-0.7.2/src/bitmap.c | 110 + {libsolv-0.6.15 => libsolv-0.7.2}/src/bitmap.h | 17 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/chksum.c | 2 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/chksum.h | 4 +- libsolv-0.7.2/src/cleandeps.c | 1393 +++++++ libsolv-0.7.2/src/cplxdeps.c | 424 ++ {libsolv-0.6.15 => libsolv-0.7.2}/src/cplxdeps.h | 7 - .../src/dataiterator.h | 32 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/dirpool.c | 7 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/dirpool.h | 2 +- libsolv-0.7.2/src/diskusage.c | 348 ++ {libsolv-0.6.15 => libsolv-0.7.2}/src/evr.c | 16 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/evr.h | 0 libsolv-0.7.2/src/filelistfilter.c | 196 + libsolv-0.7.2/src/fileprovides.c | 637 +++ {libsolv-0.6.15 => libsolv-0.7.2}/src/hash.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/knownid.h | 34 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/libsolv.ver | 42 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/linkedpkg.c | 50 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/linkedpkg.h | 3 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/md5.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/md5.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/order.c | 200 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/policy.c | 291 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/policy.h | 4 + {libsolv-0.6.15 => libsolv-0.7.2}/src/pool.c | 1185 ++---- {libsolv-0.6.15 => libsolv-0.7.2}/src/pool.h | 121 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolarch.c | 46 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolarch.h | 6 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolid.c | 92 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolid.h | 3 +- .../src/poolid_private.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/pooltypes.h | 8 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolvendor.c | 7 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/poolvendor.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/problems.c | 296 +- libsolv-0.7.2/src/problems.h | 61 + {libsolv-0.6.15 => libsolv-0.7.2}/src/qsort_r.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/queue.c | 86 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/queue.h | 6 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/repo.c | 632 +-- {libsolv-0.6.15 => libsolv-0.7.2}/src/repo.h | 36 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_solv.c | 117 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_solv.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_write.c | 1411 ++++--- libsolv-0.7.2/src/repo_write.h | 65 + {libsolv-0.6.15 => libsolv-0.7.2}/src/repodata.c | 793 ++-- {libsolv-0.6.15 => libsolv-0.7.2}/src/repodata.h | 81 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/repopack.h | 118 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/repopage.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/repopage.h | 4 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/rules.c | 1933 +++------ {libsolv-0.6.15 => libsolv-0.7.2}/src/rules.h | 72 +- libsolv-0.7.2/src/selection.c | 2081 ++++++++++ libsolv-0.7.2/src/selection.h | 81 + {libsolv-0.6.15 => libsolv-0.7.2}/src/sha1.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/sha1.h | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/sha2.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/src/sha2.h | 4 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/solvable.c | 372 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/solvable.h | 20 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/solver.c | 2793 ++++++------- {libsolv-0.6.15 => libsolv-0.7.2}/src/solver.h | 46 +- libsolv-0.7.2/src/solver_private.h | 113 + libsolv-0.7.2/src/solver_util.c | 461 +++ .../src/solverdebug.c | 33 - .../src/solverdebug.h | 4 +- .../src/solvversion.c | 0 libsolv-0.7.2/src/solvversion.h.in | 51 + {libsolv-0.6.15 => libsolv-0.7.2}/src/strpool.c | 56 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/strpool.h | 3 +- libsolv-0.7.2/src/suse.c | 747 ++++ .../src/transaction.c | 12 +- .../src/transaction.h | 20 +- libsolv-0.7.2/src/userinstalled.c | 367 ++ {libsolv-0.6.15 => libsolv-0.7.2}/src/util.c | 6 +- {libsolv-0.6.15 => libsolv-0.7.2}/src/util.h | 0 .../test/CMakeLists.txt | 0 .../test/runtestcases | 0 .../test/testcases/allowuninstall/conflict.t | 14 + .../test/testcases/allowuninstall/forcebest.t | 19 + .../test/testcases/choose/default.t | 0 .../test/testcases/choose/enhanced.t | 0 .../test/testcases/choose/oldversion.t | 0 .../test/testcases/choose/suggested.t | 0 .../test/testcases/choose/versioned.t | 0 .../test/testcases/choose/versioned2.t | 0 .../test/testcases/cleandeps/cleandeps_dup.t | 18 +- .../test/testcases/cleandeps/cleandeps_in.t | 3 +- .../test/testcases/cleandeps/cleandeps_up.t | 23 +- .../test/testcases/cleandeps/mistake.t | 0 libsolv-0.7.2/test/testcases/cplxdeps/and.t | 39 + libsolv-0.7.2/test/testcases/cplxdeps/andor.t | 73 + libsolv-0.7.2/test/testcases/cplxdeps/if.t | 36 + libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t | 70 + libsolv-0.7.2/test/testcases/cplxdeps/or.t | 34 + libsolv-0.7.2/test/testcases/cplxdeps/orand.t | 87 + .../testcases/distupgrade/dup_allowuninstall.t | 0 .../test/testcases/distupgrade/dup_multiversion1.t | 0 .../test/testcases/distupgrade/dup_multiversion2.t | 7 +- .../test/testcases/distupgrade/dup_multiversion3.t | 11 +- .../test/testcases/distupgrade/dup_noarchchange.t | 5 +- .../test/testcases/distupgrade/dup_orphan1.t | 78 + .../test/testcases/distupgrade/dup_orphan2.t | 98 + .../test/testcases/distupgrade/dup_orphan3.t | 98 + libsolv-0.7.2/test/testcases/evrcmp/caret.t | 74 + .../test/testcases/evrcmp/conflicts.repo | 0 .../test/testcases/evrcmp/system.repo | 0 .../test/testcases/evrcmp/testevr.t | 0 libsolv-0.7.2/test/testcases/favor/recommends.t | 50 + libsolv-0.7.2/test/testcases/favor/requires.t | 112 + libsolv-0.7.2/test/testcases/favor/supplements.t | 71 + libsolv-0.7.2/test/testcases/focus/best.t | 23 + libsolv-0.7.2/test/testcases/focus/installed.t | 23 + libsolv-0.7.2/test/testcases/focus/normal.t | 22 + .../test/testcases/forcebest/forcebest_dup.t | 0 .../test/testcases/forcebest/forcebest_in.t | 8 +- .../test/testcases/forcebest/forcebest_up.t | 0 .../test/testcases/lockstep/lockstep_install.t | 0 .../test/testcases/lockstep/lockstep_update.t | 0 .../test/testcases/multiversion/multiversion.t | 0 libsolv-0.7.2/test/testcases/multiversion/update.t | 65 + .../test/testcases/namespace/namespaceprovides.t | 24 + .../recommendations/recommended_conflicts.t | 16 + .../recommendations/recommended_multirepo.t | 19 + .../recommendations/recommended_oldversion.t | 15 + .../recommendations/recommended_targeted.t | 15 + .../recommendations/recommended_version.t | 15 + .../recommendations/suggested_conflicts.t | 16 + .../recommendations/suggested_multirepo.t | 19 + .../recommendations/suggested_oldversion.t | 15 + .../testcases/recommendations/suggested_targeted.t | 15 + .../testcases/recommendations/suggested_version.t | 15 + .../test/testcases/sat/assert.t | 0 .../test/testcases/sat/mm-test.t | 0 libsolv-0.7.2/test/testcases/sat/reuse.t | 20 + .../test/testcases/selection/selection_canon_rpm.t | 53 + .../test/testcases/selection/selection_filelist.t | 20 + .../test/testcases/selection/selection_matchdeps.t | 54 + .../testcases/selection/selection_matchsolvable.t | 27 + .../test/testcases/selection/selection_name.t | 85 + .../test/testcases/selection/selection_provides.t | 49 + .../test/testcases/strongrecommends/break.t | 28 + .../test/testcases/strongrecommends/strongr.t | 27 + .../test/testcases/targeted/targeted_dup.t | 0 .../test/testcases/targeted/targeted_up.t | 2 +- libsolv-0.7.2/test/testcases/testcase/nested.t | 56 + .../test/testcases/testcase/str2dep.t | 0 .../supplements_implicitobsoleteusescolors.t | 20 + .../test/testcases/yumobs/split.t | 0 .../tools/CMakeLists.txt | 22 +- .../tools/appdata2solv.c | 4 +- .../tools/archpkgs2solv.c | 8 +- .../tools/archrepo2solv.c | 6 +- libsolv-0.7.2/tools/common_write.c | 71 + .../tools/common_write.h | 2 +- .../tools/comps2solv.c | 4 +- {libsolv-0.6.15 => libsolv-0.7.2}/tools/cudftest.c | 0 {libsolv-0.6.15 => libsolv-0.7.2}/tools/deb2solv.c | 35 +- .../tools/deltainfoxml2solv.c | 13 +- .../tools/diskusagexml2solv.c | 11 +- {libsolv-0.6.15 => libsolv-0.7.2}/tools/dumpsolv.c | 2 - .../tools/findfileconflicts.c | 0 .../tools/helix2solv.c | 4 +- .../tools/installcheck.c | 10 +- {libsolv-0.6.15 => libsolv-0.7.2}/tools/mdk2solv.c | 8 +- .../tools/mergesolv.c | 10 +- libsolv-0.7.2/tools/repo2solv.c | 834 ++++ .../tools/repomdxml2solv.c | 4 +- .../tools/rpmdb2solv.c | 27 +- libsolv-0.7.2/tools/rpmmd2solv.c | 77 + .../tools/rpms2solv.c | 8 +- .../tools/susetags2solv.c | 37 +- {libsolv-0.6.15 => libsolv-0.7.2}/tools/testsolv.c | 70 +- .../tools/updateinfoxml2solv.c | 13 +- packaging/perl-BSSolv.spec | 152 +- 391 files changed, 27066 insertions(+), 15789 deletions(-) delete mode 100644 libsolv-0.6.15/BUGS delete mode 100644 libsolv-0.6.15/NEWS delete mode 100644 libsolv-0.6.15/ext/repo_comps.c delete mode 100644 libsolv-0.6.15/ext/repo_zyppdb.c delete mode 100644 libsolv-0.6.15/package/libsolv.spec.in delete mode 100644 libsolv-0.6.15/src/bitmap.c delete mode 100644 libsolv-0.6.15/src/cplxdeps.c delete mode 100644 libsolv-0.6.15/src/problems.h delete mode 100644 libsolv-0.6.15/src/repo_write.h delete mode 100644 libsolv-0.6.15/src/selection.c delete mode 100644 libsolv-0.6.15/src/selection.h delete mode 100644 libsolv-0.6.15/src/solver_private.h delete mode 100644 libsolv-0.6.15/src/solvversion.h.in delete mode 100644 libsolv-0.6.15/tools/common_write.c delete mode 100644 libsolv-0.6.15/tools/patchcheck.c delete mode 100644 libsolv-0.6.15/tools/rpmmd2solv.c rename {libsolv-0.6.15 => libsolv-0.7.2}/.emacs-dirvars (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/.gitignore (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/.travis.yml (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/CMakeLists.txt (72%) rename {libsolv-0.6.15 => libsolv-0.7.2}/CREDITS (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/INSTALL (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/LICENSE.BSD (100%) create mode 100644 libsolv-0.7.2/NEWS rename {libsolv-0.6.15 => libsolv-0.7.2}/README (71%) create mode 100644 libsolv-0.7.2/TODO_1.0 rename {libsolv-0.6.15 => libsolv-0.7.2}/VERSION.cmake (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/CMakeLists.txt (85%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/perl/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/python/CMakeLists.txt (63%) create mode 100644 libsolv-0.7.2/bindings/python3/CMakeLists.txt rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/ruby/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/solv.i (89%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/tcl/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/bindings/tcl/solv.tm.in (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindCheck.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindEXPAT.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindLZMA.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindLibSolv.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindPackageHandleStandardArgs.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/FindRuby.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/cmake/modules/_CMakeParseArguments.cmake (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/CMakeLists.txt (83%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/Makefile.gen (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/appdata2solv.txt (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/archpkgs2solv.txt (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/archrepo2solv.txt (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/comps2solv.txt (94%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/deb2solv.txt (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/deltainfoxml2solv.txt (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/dumpsolv.txt (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/filters/xcode.conf (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/filters/xcode.pl (100%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/appdata2solv.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/archpkgs2solv.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/archrepo2solv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/comps2solv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/deb2solv.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/deltainfoxml2solv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/dumpsolv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/helix2solv.1 (90%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/installcheck.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/libsolv-bindings.3 (89%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/libsolv-constantids.3 (99%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/libsolv-history.3 (97%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/libsolv-pool.3 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/libsolv.3 (95%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/mdk2solv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/mergesolv.1 (90%) create mode 100644 libsolv-0.7.2/doc/gen/repo2solv.1 rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/repomdxml2solv.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/rpmdb2solv.1 (94%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/rpmmd2solv.1 (91%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/rpms2solv.1 (93%) create mode 100644 libsolv-0.7.2/doc/gen/solv.1 rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/susetags2solv.1 (92%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/testsolv.1 (93%) rename {libsolv-0.6.15/doc => libsolv-0.7.2/doc/gen}/updateinfoxml2solv.1 (90%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/helix2solv.txt (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/installcheck.txt (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv-bindings.txt (90%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv-constantids.txt (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv-history.txt (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv-pool.txt (92%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/libsolv.txt (98%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/mdk2solv.txt (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/mergesolv.txt (93%) create mode 100644 libsolv-0.7.2/doc/repo2solv.txt rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/repomdxml2solv.txt (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/rpmdb2solv.txt (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/rpmmd2solv.txt (94%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/rpms2solv.txt (96%) create mode 100644 libsolv-0.7.2/doc/solv.txt rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/susetags2solv.txt (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/testsolv.txt (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/doc/updateinfoxml2solv.txt (94%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/p5solv (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/pysolv (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/rbsolv (99%) rename {libsolv-0.6.15/tools => libsolv-0.7.2/examples}/repo2solv.sh (92%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/checksig.c (86%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/checksig.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/deltarpm.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/deltarpm.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fastestmirror.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fastestmirror.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fileconflicts.c (77%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fileconflicts.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fileprovides.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/fileprovides.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/mirror.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/mirror.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/patchjobs.c (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/patchjobs.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo.c (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_cache.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_cache.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_debian.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_debian.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_urpmi.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_urpmi.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_yum.c (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_config_yum.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_download.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_download.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_system_debian.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_system_debian.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_system_rpm.c (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_system_rpm.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_debian.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_debian.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_mdk.c (86%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_mdk.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_rpmmd.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_rpmmd.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_susetags.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/repoinfo_type_susetags.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/solv/solv.c (83%) rename {libsolv-0.6.15 => libsolv-0.7.2}/examples/tclsolv (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/CMakeLists.txt (82%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/libsolvext.ver (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/pool_fileconflicts.c (74%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/pool_fileconflicts.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/pool_parserpmrichdep.c (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/pool_parserpmrichdep.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_appdata.c (66%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_appdata.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_arch.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_arch.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_autopattern.c (89%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_autopattern.h (100%) create mode 100644 libsolv-0.7.2/ext/repo_comps.c rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_comps.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_content.c (98%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_content.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_cudf.c (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_cudf.h (100%) create mode 100644 libsolv-0.7.2/ext/repo_deb.c rename libsolv-0.6.15/ext/repo_deb.c => libsolv-0.7.2/ext/repo_deb.c.orig (99%) mode change 100755 => 100644 rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_deb.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_deltainfoxml.c (64%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_deltainfoxml.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_haiku.cpp (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_haiku.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_helix.c (71%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_helix.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_mdk.c (75%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_mdk.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_products.c (65%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_products.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_pubkey.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_pubkey.h (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_releasefile_products.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_releasefile_products.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_repomdxml.c (66%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_repomdxml.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmdb.c (69%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmdb.h (98%) create mode 100644 libsolv-0.7.2/ext/repo_rpmdb_bdb.h create mode 100644 libsolv-0.7.2/ext/repo_rpmdb_librpm.h rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmmd.c (64%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_rpmmd.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_susetags.c (70%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_susetags.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_updateinfoxml.c (65%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_updateinfoxml.h (100%) create mode 100644 libsolv-0.7.2/ext/repo_zyppdb.c rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/repo_zyppdb.h (100%) create mode 100644 libsolv-0.7.2/ext/repodata_diskusage.c create mode 100644 libsolv-0.7.2/ext/repodata_diskusage.h create mode 100644 libsolv-0.7.2/ext/solv_jsonparser.c create mode 100644 libsolv-0.7.2/ext/solv_jsonparser.h rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/solv_pgpvrfy.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/solv_pgpvrfy.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/solv_xfopen.c (59%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/solv_xfopen.h (100%) create mode 100644 libsolv-0.7.2/ext/solv_xmlparser.c create mode 100644 libsolv-0.7.2/ext/solv_xmlparser.h create mode 100644 libsolv-0.7.2/ext/solv_zchunk.c create mode 100644 libsolv-0.7.2/ext/solv_zchunk.h rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/testcase.c (82%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/testcase.h (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/ext/tools_util.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/libsolv.pc.in (53%) create mode 100644 libsolv-0.7.2/libsolvext.pc.in rename {libsolv-0.6.15 => libsolv-0.7.2}/package/libsolv.changes (82%) create mode 100644 libsolv-0.7.2/package/libsolv.spec.in rename {libsolv-0.6.15 => libsolv-0.7.2}/src/CMakeLists.txt (90%) create mode 100644 libsolv-0.7.2/src/bitmap.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/bitmap.h (74%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/chksum.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/chksum.h (95%) create mode 100644 libsolv-0.7.2/src/cleandeps.c create mode 100644 libsolv-0.7.2/src/cplxdeps.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/cplxdeps.h (79%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/dataiterator.h (85%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/dirpool.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/dirpool.h (98%) create mode 100644 libsolv-0.7.2/src/diskusage.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/evr.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/evr.h (100%) create mode 100644 libsolv-0.7.2/src/filelistfilter.c create mode 100644 libsolv-0.7.2/src/fileprovides.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/hash.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/knownid.h (91%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/libsolv.ver (92%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/linkedpkg.c (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/linkedpkg.h (91%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/md5.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/md5.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/order.c (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/policy.c (84%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/policy.h (87%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/pool.c (66%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/pool.h (85%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolarch.c (79%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolarch.h (81%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolid.c (75%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolid.h (92%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolid_private.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/pooltypes.h (88%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolvendor.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/poolvendor.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/problems.c (81%) create mode 100644 libsolv-0.7.2/src/problems.h rename {libsolv-0.6.15 => libsolv-0.7.2}/src/qsort_r.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/queue.c (65%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/queue.h (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repo.c (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repo.h (86%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_solv.c (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_solv.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repo_write.c (57%) create mode 100644 libsolv-0.7.2/src/repo_write.h rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repodata.c (85%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repodata.h (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repopack.h (73%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repopage.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/repopage.h (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/rules.c (68%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/rules.h (57%) create mode 100644 libsolv-0.7.2/src/selection.c create mode 100644 libsolv-0.7.2/src/selection.h rename {libsolv-0.6.15 => libsolv-0.7.2}/src/sha1.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/sha1.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/sha2.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/sha2.h (98%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solvable.c (65%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solvable.h (78%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solver.c (68%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solver.h (90%) create mode 100644 libsolv-0.7.2/src/solver_private.h create mode 100644 libsolv-0.7.2/src/solver_util.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solverdebug.c (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solverdebug.h (98%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/solvversion.c (100%) create mode 100644 libsolv-0.7.2/src/solvversion.h.in rename {libsolv-0.6.15 => libsolv-0.7.2}/src/strpool.c (82%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/strpool.h (94%) create mode 100644 libsolv-0.7.2/src/suse.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/transaction.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/transaction.h (89%) create mode 100644 libsolv-0.7.2/src/userinstalled.c rename {libsolv-0.6.15 => libsolv-0.7.2}/src/util.c (98%) rename {libsolv-0.6.15 => libsolv-0.7.2}/src/util.h (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/CMakeLists.txt (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/runtestcases (100%) create mode 100644 libsolv-0.7.2/test/testcases/allowuninstall/conflict.t create mode 100644 libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/default.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/enhanced.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/oldversion.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/suggested.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/versioned.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/choose/versioned2.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/cleandeps/cleandeps_dup.t (60%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/cleandeps/cleandeps_in.t (81%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/cleandeps/cleandeps_up.t (54%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/cleandeps/mistake.t (100%) create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/and.t create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/andor.t create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/if.t create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/or.t create mode 100644 libsolv-0.7.2/test/testcases/cplxdeps/orand.t rename libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall => libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t (100%) rename libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1 => libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t (100%) rename libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 => libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t (94%) rename libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 => libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t (83%) rename libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange => libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t (67%) create mode 100644 libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t create mode 100644 libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t create mode 100644 libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t create mode 100644 libsolv-0.7.2/test/testcases/evrcmp/caret.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/evrcmp/conflicts.repo (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/evrcmp/system.repo (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/evrcmp/testevr.t (100%) create mode 100644 libsolv-0.7.2/test/testcases/favor/recommends.t create mode 100644 libsolv-0.7.2/test/testcases/favor/requires.t create mode 100644 libsolv-0.7.2/test/testcases/favor/supplements.t create mode 100644 libsolv-0.7.2/test/testcases/focus/best.t create mode 100644 libsolv-0.7.2/test/testcases/focus/installed.t create mode 100644 libsolv-0.7.2/test/testcases/focus/normal.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/forcebest/forcebest_dup.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/forcebest/forcebest_in.t (75%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/forcebest/forcebest_up.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/lockstep/lockstep_install.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/lockstep/lockstep_update.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/multiversion/multiversion.t (100%) create mode 100644 libsolv-0.7.2/test/testcases/multiversion/update.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/namespace/namespaceprovides.t (74%) create mode 100644 libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/recommended_version.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t create mode 100644 libsolv-0.7.2/test/testcases/recommendations/suggested_version.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/sat/assert.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/sat/mm-test.t (100%) create mode 100644 libsolv-0.7.2/test/testcases/sat/reuse.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_filelist.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_name.t create mode 100644 libsolv-0.7.2/test/testcases/selection/selection_provides.t create mode 100644 libsolv-0.7.2/test/testcases/strongrecommends/break.t create mode 100644 libsolv-0.7.2/test/testcases/strongrecommends/strongr.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/targeted/targeted_dup.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/targeted/targeted_up.t (97%) create mode 100644 libsolv-0.7.2/test/testcases/testcase/nested.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/testcase/str2dep.t (100%) create mode 100644 libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t rename {libsolv-0.6.15 => libsolv-0.7.2}/test/testcases/yumobs/split.t (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/CMakeLists.txt (91%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/appdata2solv.c (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/archpkgs2solv.c (93%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/archrepo2solv.c (94%) create mode 100644 libsolv-0.7.2/tools/common_write.c rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/common_write.h (74%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/comps2solv.c (91%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/cudftest.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/deb2solv.c (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/deltainfoxml2solv.c (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/diskusagexml2solv.c (79%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/dumpsolv.c (99%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/findfileconflicts.c (100%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/helix2solv.c (91%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/installcheck.c (96%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/mdk2solv.c (94%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/mergesolv.c (90%) create mode 100644 libsolv-0.7.2/tools/repo2solv.c rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/repomdxml2solv.c (97%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/rpmdb2solv.c (84%) create mode 100644 libsolv-0.7.2/tools/rpmmd2solv.c rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/rpms2solv.c (95%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/susetags2solv.c (86%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/testsolv.c (76%) rename {libsolv-0.6.15 => libsolv-0.7.2}/tools/updateinfoxml2solv.c (76%) diff --git a/BSSolv.pm b/BSSolv.pm index 82db1e1..7a2213a 100644 --- a/BSSolv.pm +++ b/BSSolv.pm @@ -6,7 +6,7 @@ require Exporter; our @ISA = qw(Exporter); -our $VERSION = '0.08'; +our $VERSION = '0.17'; require XSLoader; diff --git a/BSSolv.xs b/BSSolv.xs index c00237f..ffd992c 100644 --- a/BSSolv.xs +++ b/BSSolv.xs @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2009 - 2017 SUSE Linux Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the same terms as Perl itself. + * + */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -8,19 +15,49 @@ #define MULTI_SEMANTICS +#include "solvversion.h" +#if LIBSOLV_VERSION < 623 +#define LIBSOLVEXT_FEATURE_DEBIAN +#define LIBSOLVEXT_FEATURE_ARCHREPO +#endif + #include "pool.h" #include "repo.h" #include "util.h" #include "evr.h" #include "hash.h" #include "chksum.h" +#include "testcase.h" #include "repo_solv.h" #include "repo_write.h" #include "repo_rpmdb.h" +#if defined(LIBSOLVEXT_FEATURE_DEBIAN) #include "repo_deb.h" -#if 1 +#endif +#if defined(LIBSOLVEXT_FEATURE_ARCHREPO) #include "repo_arch.h" #endif +#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS) +#include "pool_parserpmrichdep.h" +#endif + +#ifndef REL_ERROR +# define REL_ERROR 27 /* for old libsolv versions */ +#endif +#ifndef REL_UNLESS +# define REL_UNLESS 29 /* for old libsolv versions */ +#endif + +#define EXPANDER_DEBUG_ALL (1 << 0) +#define EXPANDER_DEBUG_STDOUT (1 << 1) +#define EXPANDER_DEBUG_STR (1 << 2) + +#define EXPANDER_OPTION_IGNOREIGNORE (1 << 0) +#define EXPANDER_OPTION_IGNORECONFLICTS (1 << 1) +#define EXPANDER_OPTION_DORECOMMENDS (1 << 2) +#define EXPANDER_OPTION_DOSUPPLEMENTS (1 << 3) +#define EXPANDER_OPTION_USERECOMMENDSFORCHOICES (1 << 4) +#define EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES (1 << 5) typedef struct _Expander { Pool *pool; @@ -38,17 +75,54 @@ typedef struct _Expander { Queue conflictsq; Map conflicts; - int debug; int havefileprovides; - int ignoreconflicts; - int ignoreignore; + /* debug support */ + int debug; char *debugstr; int debugstrl; int debugstrf; + + /* options */ + int ignoreconflicts; + int ignoreignore; int userecommendsforchoices; + int usesupplementsforchoices; + int dorecommends; + int dosupplements; } Expander; +typedef struct _ExpanderCtx { + Pool *pool; + Expander *xp; + Queue *out; /* the result */ + Map installed; /* installed packages */ + Map conflicts; /* conflicts from installed packages */ + Queue conflictsinfo; /* source info for the above */ + int cidone; /* conflictsinfo done position */ + Queue todo; /* requires todo list */ + Queue errors; /* expansion errors */ + Queue cplxq; /* complex dep work queue */ + Queue cplxblks; /* complex dep block data, add only */ + Queue todo_cond; /* delayed requires/conflicts */ + Queue pruneq; /* multi purpose queue for pruning packages */ + Map todo_condmap; /* all neg packages in todo_cond blocks */ + Map recommended; /* recommended packages */ + int recdone; /* recommended done position */ + + /* options */ + int ignoreconflicts; + int ignoreignore; + int userecommendsforchoices; + int usesupplementsforchoices; + int dorecommends; + int dosupplements; + + /* hacks */ + Solvable *ignore_s; /* small hack: ignore requires of this solvable */ +} ExpanderCtx; + + typedef Pool *BSSolv__pool; typedef Repo *BSSolv__repo; typedef Expander *BSSolv__expander; @@ -57,8 +131,14 @@ static Id buildservice_id; static Id buildservice_repocookie; static Id buildservice_external; static Id buildservice_dodurl; -static Id expander_directdepsend; static Id buildservice_dodcookie; +static Id buildservice_dodresources; +static Id buildservice_annotation; +static Id buildservice_modules; +static Id expander_directdepsend; + +static int genmetaalgo; +static int depsortsccs; /* make sure bit n is usable */ #define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0) @@ -149,7 +229,7 @@ id2name(Pool *pool, Id id) } static Id -dep2id(Pool *pool, char *s) +dep2id_rec(Pool *pool, char *s) { char *n; Id id; @@ -157,17 +237,26 @@ dep2id(Pool *pool, char *s) if ((n = strchr(s, '|')) != 0) { - id = dep2id(pool, n + 1); + id = dep2id_rec(pool, n + 1); *n = 0; - id = pool_rel2id(pool, dep2id(pool, s), id, REL_OR, 1); + id = pool_rel2id(pool, dep2id_rec(pool, s), id, REL_OR, 1); *n = '|'; return id; } while (*s == ' ' || *s == '\t') s++; n = s; - while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>') - s++; + if (pool->disttype == DISTTYPE_RPM) + { + /* rpm delimits the name by whitespace only */ + while (*s && *s != ' ' && *s != '\t') + s++; + } + else + { + while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>') + s++; + } #ifdef REL_MULTIARCH if (s - n > 4 && s[-4] == ':' && !strncmp(s - 4, ":any", 4)) { @@ -185,13 +274,13 @@ dep2id(Pool *pool, char *s) for (;;s++) { if (*s == '<') - flags |= REL_LT; + flags |= REL_LT; else if (*s == '=') - flags |= REL_EQ; + flags |= REL_EQ; else if (*s == '>') - flags |= REL_GT; + flags |= REL_GT; else - break; + break; } if (!flags) return id; @@ -203,11 +292,38 @@ dep2id(Pool *pool, char *s) return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1); } -static inline Offset +static Id +parsedep_error(Pool *pool, const char *s) +{ + Id id; + id = pool_str2id(pool, s, 1); + return pool_rel2id(pool, pool_str2id(pool, "dependency parse error", 1), id, REL_ERROR, 1); +} + +static Id +dep2id(Pool *pool, char *s) +{ + Id id; + if (pool->disttype == DISTTYPE_RPM && *s == '(') + { +#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS) + id = pool_parserpmrichdep(pool, s); +#else + id = 0; +#endif + } + else + id = dep2id_rec(pool, s); + if (!id) + id = parsedep_error(pool, s); + return id; +} + +static Offset importdeps(HV *hv, const char *key, int keyl, Repo *repo) { Pool *pool = repo->pool; - int i; + SSize_t i; AV *av = hvlookupav(hv, key, keyl); Offset off = 0; if (av) @@ -216,13 +332,18 @@ importdeps(HV *hv, const char *key, int keyl, Repo *repo) { char *str = avlookupstr(av, i); if (str) - off = repo_addid_dep(repo, off, dep2id(pool, str), 0); + { + Id id = testcase_str2dep(pool, str); + if (!id) + id = parsedep_error(pool, str); + off = repo_addid_dep(repo, off, id, 0); + } } } return off; } -void +static void exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey) { Pool *pool = repo->pool; @@ -238,64 +359,7 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey) { if (id == SOLVABLE_FILEMARKER) break; - str = pool_dep2str(pool, id); - if (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - if (skey == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS) - { - if (!strncmp(str, "namespace:", 10)) - str += 10; - } - if (skey == SOLVABLE_SUPPLEMENTS) - { - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM) - { - if (!strncmp(str, "namespace:", 10)) - str += 10; - } - else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS) - { - if (!strncmp(str, "namespace:", 10)) - str += 10; - } - else if (rd->flags == REL_AND) - { - /* either packageand chain or modalias */ - str = 0; - if (ISRELDEP(rd->evr)) - { - Reldep *mrd = GETRELDEP(pool, rd->evr); - if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS) - { - str = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":"); - str = pool_tmpappend(pool, str, pool_dep2str(pool, mrd->evr), ")"); - } - else if (mrd->flags >= 8) - continue; - } - if (!str) - { - /* must be and chain */ - str = pool_dep2str(pool, rd->evr); - for (;;) - { - id = rd->name; - if (!ISRELDEP(id)) - break; - rd = GETRELDEP(pool, id); - if (rd->flags != REL_AND) - break; - str = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", str); - } - str = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", str); - str = pool_tmpjoin(pool, "packageand(", str, ")"); - } - } - else if (rd->flags >= 8) - continue; - } - } + str = testcase_dep2str(pool, id); if (skey == SOLVABLE_REQUIRES) { if (id == SOLVABLE_PREREQMARKER) @@ -311,104 +375,179 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey) (void)hv_store(hv, key, keyl, newRV_noinc((SV*)av), 0); } -void -data2solvables(Repo *repo, Repodata *data, HV *rhv) +static int +data2pkg(Repo *repo, Repodata *data, HV *hv, int isdod) { Pool *pool = repo->pool; - SV *sv; - HV *hv; - char *str, *key; - I32 keyl; + char *str; Id p; Solvable *s; + AV *av; - hv_iterinit(rhv); - while ((sv = hv_iternextsv(rhv, &key, &keyl)) != 0) + str = hvlookupstr(hv, "name", 4); + if (!str) + return 0; /* need to have a name */ + p = repo_add_solvable(repo); + s = pool_id2solvable(pool, p); + s->name = pool_str2id(pool, str, 1); + str = hvlookupstr(hv, "arch", 4); + if (!str) + str = ""; /* dummy, need to have arch */ + s->arch = pool_str2id(pool, str, 1); + s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7)); + str = hvlookupstr(hv, "path", 4); + if (str) { - if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV) - continue; - hv = (HV *)SvRV(sv); - str = hvlookupstr(hv, "name", 4); - if (!str) - continue; /* need to have a name */ - p = repo_add_solvable(repo); - s = pool_id2solvable(pool, p); - s->name = pool_str2id(pool, str, 1); - str = hvlookupstr(hv, "arch", 4); - if (!str) - str = ""; /* dummy, need to have arch */ - s->arch = pool_str2id(pool, str, 1); - s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7)); - str = hvlookupstr(hv, "path", 4); - if (str) + char *ss = strrchr(str, '/'); + if (ss) { - char *ss = strrchr(str, '/'); - if (ss) - { - *ss = 0; - repodata_set_str(data, p, SOLVABLE_MEDIADIR, str); - *ss++ = '/'; - } - else - ss = str; - repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss); + *ss = 0; + repodata_set_str(data, p, SOLVABLE_MEDIADIR, str); + *ss++ = '/'; } + else + ss = str; + repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss); + } + if (isdod) + repodata_set_str(data, p, buildservice_id, "dod"); + else + { str = hvlookupstr(hv, "id", 2); if (str) repodata_set_str(data, p, buildservice_id, str); - str = hvlookupstr(hv, "source", 6); - if (str) - repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str); + } + str = hvlookupstr(hv, "source", 6); + if (str) + repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str); + if (isdod) + { + static unsigned char dod_pkgid[16] = { 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0 }; + repodata_set_bin_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, dod_pkgid); + } + else + { str = hvlookupstr(hv, "hdrmd5", 6); if (str && strlen(str) == 32) repodata_set_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, str); - s->provides = importdeps(hv, "provides", 8, repo); - s->obsoletes = importdeps(hv, "obsoletes", 9, repo); - s->conflicts = importdeps(hv, "conflicts", 9, repo); - s->requires = importdeps(hv, "requires", 8, repo); - s->recommends = importdeps(hv, "recommends", 10, repo); - s->suggests = importdeps(hv, "suggests", 8, repo); - s->supplements = importdeps(hv, "supplements", 11, repo); - s->enhances = importdeps(hv, "enhances", 8, repo); - if (!s->evr && s->provides) - { - /* look for self provides */ - Id pro, *prop = s->repo->idarraydata + s->provides; - while ((pro = *prop++) != 0) - { - Reldep *rd; - if (!ISRELDEP(pro)) - continue; - rd = GETRELDEP(pool, pro); - if (rd->name == s->name && rd->flags == REL_EQ) - s->evr = rd->evr; - } + } + s->provides = importdeps(hv, "provides", 8, repo); + s->obsoletes = importdeps(hv, "obsoletes", 9, repo); + s->conflicts = importdeps(hv, "conflicts", 9, repo); + s->requires = importdeps(hv, "requires", 8, repo); + s->recommends = importdeps(hv, "recommends", 10, repo); + s->suggests = importdeps(hv, "suggests", 8, repo); + s->supplements = importdeps(hv, "supplements", 11, repo); + s->enhances = importdeps(hv, "enhances", 8, repo); + if (!s->evr && s->provides) + { + /* look for self provides */ + Id pro, *prop = s->repo->idarraydata + s->provides; + while ((pro = *prop++) != 0) + { + Reldep *rd; + if (!ISRELDEP(pro)) + continue; + rd = GETRELDEP(pool, pro); + if (rd->name == s->name && rd->flags == REL_EQ) + s->evr = rd->evr; + } + } + if (s->evr && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); + str = hvlookupstr(hv, "checksum", 8); + if (str) + { + char *cp, typebuf[8]; + Id ctype; + if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf)) + { + strncpy(typebuf, str, cp - str); + typebuf[cp - str] = 0; + ctype = solv_chksum_str2type(typebuf); + if (ctype) + repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1); + } + } + str = hvlookupstr(hv, "annotation", 10); + if (str && strlen(str) < 100000) + repodata_set_str(data, p, buildservice_annotation, str); + av = hvlookupav(hv, "modules", 7); + if (av) + { + SSize_t i; + for (i = 0; i <= av_len(av); i++) + { + char *str = avlookupstr(av, i); + repodata_add_idarray(data, p, buildservice_modules, pool_str2id(pool, str, 1)); + } + } + return p; +} + +static void +data2solvables(Repo *repo, Repodata *data, SV *rsv, int isdod) +{ + AV *rav = 0; + SSize_t ravi = 0; + HV *rhv = 0; + SV *sv; + char *key; + I32 keyl; + + if (SvTYPE(rsv) == SVt_PVAV) + rav = (AV *)rsv; + else + rhv = (HV *)rsv; + + if (rhv) + hv_iterinit(rhv); + for (;;) + { + if (rhv) + { + sv = hv_iternextsv(rhv, &key, &keyl); + if (!sv) + break; + } + else + { + SV **svp; + if (ravi > av_len(rav)) + break; + svp = av_fetch(rav, ravi++, 0); + if (!svp || !*svp) + continue; + sv = *svp; } - if (s->evr) - s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - str = hvlookupstr(hv, "checksum", 8); + if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV) + continue; + data2pkg(repo, data, (HV *)SvRV(sv), isdod); + } + + /* set meta information */ + repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE); + if (rhv) + { + char *str; + AV *av; + str = hvlookupstr(rhv, "/url", 4); if (str) + repodata_set_str(data, SOLVID_META, buildservice_dodurl, str); + str = hvlookupstr(rhv, "/dodcookie", 10); + if (str) + repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str); + av = hvlookupav(rhv, "/dodresources", 13); + if (av) { - char *cp, typebuf[8]; - Id ctype; - if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf)) + SSize_t i; + for (i = 0; i <= av_len(av); i++) { - strncpy(typebuf, str, cp - str); - typebuf[cp - str] = 0; - ctype = solv_chksum_str2type(typebuf); - if (ctype) - repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1); + Id id = pool_str2id(repo->pool, avlookupstr(av, i), 1); + repodata_add_idarray(data, SOLVID_META, buildservice_dodresources, id); } } } - - repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE); - str = hvlookupstr(rhv, "/url", 4); - if (str) - repodata_set_str(data, SOLVID_META, buildservice_dodurl, str); - str = hvlookupstr(rhv, "/dodcookie", 10); - if (str) - repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str); } static SV * @@ -524,133 +663,895 @@ retrieve(unsigned char **srcp, STRLEN *srclp, int depth) return sv; } -static void -expander_dbg(Expander *xp, const char *format, ...) +#define CPLXDEPS_TODNF (1 << 0) + +static int +invert_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r) { - va_list args; - char buf[1024]; - int l; - if (!xp->debug) - return; - va_start(args, format); - vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - printf("%s", buf); - l = strlen(buf); - if (buf[0] != ' ' || (l && buf[l - 1] == '\n')) - fflush(stdout); - if (l >= xp->debugstrf) /* >= because of trailing \0 */ + int i, j, end; + if (r == 0 || r == 1) + return r ? 0 : 1; + end = bq->count; + for (i = j = start; i < end; i++) { - xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024); - xp->debugstrf = l + 1024; + if (bq->elements[i]) + { + bq->elements[i] = -bq->elements[i]; + continue; + } + /* end of block reached, reverse */ + if (i - 1 > j) + { + int k; + for (k = i - 1; j < k; j++, k--) + { + Id t = bq->elements[j]; + bq->elements[j] = bq->elements[k]; + bq->elements[k] = t; + } + } + j = i + 1; } - strcpy(xp->debugstr + xp->debugstrl, buf); - xp->debugstrl += l; - xp->debugstrf -= l; -} - -static const char * -expander_solvid2name(Expander *xp, Id p) -{ - const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name); - Repo *r; - if (!xp->debug) - return n; - r = xp->pool->solvables[p].repo; - if (!r) - return n; - return pool_tmpjoin(xp->pool, n, "@", r->name); + return -1; } -static inline void -expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *conflictsinfo, int *cidone, Queue *out, Queue *todo) +static int +distribute_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int start2, int flags) { - Pool *pool = xp->pool; - Solvable *s = pool->solvables + p; - Id req, id, *reqp, con, *conp; - const char *n; - - MAPSET(installed, p); - queue_push(out, p); - if (MAPTST(&xp->conflicts, s->name)) - { - int i; - for (i = 0; i < xp->conflictsq.count; i++) - { - Id p2, pp2; - Id id = xp->conflictsq.elements[i]; - if (id != s->name) - continue; - id = xp->conflictsq.elements[i ^ 1]; - FOR_PROVIDES(p2, pp2, id) - { - if (pool->solvables[p2].name == id) - { - MAPEXP(conflicts, pool->nsolvables); - MAPSET(conflicts, p2); - } - } - } - } - if (s->requires) + int i, j, end2 = bq->count; + for (i = start; i < start2; i++) { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) + for (j = start2; j < end2; j++) { - if (req == SOLVABLE_PREREQMARKER) - continue; - id = id2name(pool, req); - if (!xp->ignoreignore) + int a, b; + int bqcnt4 = bq->count; + int k = i; + + /* distribute i block with j block, both blocks are sorted */ + while (bq->elements[k] && bq->elements[j]) { - if (MAPTST(&xp->ignored, id)) - continue; - if (MAPTST(&xp->ignoredx, id)) + if (bq->elements[k] < bq->elements[j]) + queue_push(bq, bq->elements[k++]); + else { - Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0); - if (xid && MAPTST(&xp->ignored, xid)) - continue; + if (bq->elements[k] == bq->elements[j]) + k++; + queue_push(bq, bq->elements[j++]); } } - n = pool_id2str(pool, id); - if (!strncmp(n, "rpmlib(", 7)) - { - MAPEXP(&xp->ignored, id); - MAPSET(&xp->ignored, id); - continue; - } - if (*n == '/') + while (bq->elements[j]) + queue_push(bq, bq->elements[j++]); + while (bq->elements[k]) + queue_push(bq, bq->elements[k++]); + + /* block is finished, check for A + -A */ + for (a = bqcnt4, b = bq->count - 1; a < b; ) { - if (!xp->havefileprovides || pool->whatprovides[id] <= 1) - { - MAPEXP(&xp->ignored, id); - MAPSET(&xp->ignored, id); - continue; - } + if (-bq->elements[a] == bq->elements[b]) + break; + if (-bq->elements[a] > bq->elements[b]) + a++; + else + b--; } - queue_push2(todo, req, p); + if (a < b) + queue_truncate(bq, bqcnt4); /* ignore this block */ + else + queue_push(bq, 0); /* finish block */ } + /* advance to next block */ + while (bq->elements[i]) + i++; } - if (!xp->ignoreconflicts) + queue_deleten(bq, start, end2 - start); + if (start == bq->count) + return flags & CPLXDEPS_TODNF ? 0 : 1; + return -1; +} + +#if 0 +static void +print_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r) +{ + Pool *pool = xpctx->pool; + int i; + + if (r == 0) { - if (s->conflicts) - { - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - Id p2, pp2; - FOR_PROVIDES(p2, pp2, con) - { - if (p2 == p) - continue; - MAPEXP(conflicts, pool->nsolvables); - MAPSET(conflicts, p2); - if (xp->debug) - queue_push2(conflictsinfo, p2, p); - } - } - } - if (s->obsoletes) - { + printf("[NONE]\n"); + return; + } + if (r == 1) + { + printf("[ALL]\n"); + return; + } + for (i = start; i < bq->count; i++) + { + if (bq->elements[i] > 0) + printf(" %s", pool_solvid2str(pool, bq->elements[i])); + else if (bq->elements[i] < 0) + printf(" -%s", pool_solvid2str(pool, -bq->elements[i])); + else + printf(" ||"); + } + printf("\n"); +} +#endif + + +static int +pool_is_complex_dep_rd(Pool *pool, Reldep *rd) +{ + for (;;) + { + if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS) /* those are the complex ones */ + return 1; + if (rd->flags != REL_OR) + return 0; + if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name))) + return 1; + if (!ISRELDEP(rd->evr)) + return 0; + rd = GETRELDEP(pool, rd->evr); + } +} + +static inline int +pool_is_complex_dep(Pool *pool, Id dep) +{ + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd)) + return 1; + } + return 0; +} + +static int normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags); + +static int +normalize_dep_or(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags) +{ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep(xpctx, dep1, bq, flags); + if (r1 == 1) + return 1; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags); + if (invflags) + r2 = invert_depblocks(xpctx, bq, bqcnt2, r2); + if (r1 == 1 || r2 == 1) + { + queue_truncate(bq, bqcnt); + return 1; + } + if (r1 == 0) + return r2; + if (r2 == 0) + return r1; + if ((flags & CPLXDEPS_TODNF) == 0) + return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_and(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags) +{ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep(xpctx, dep1, bq, flags); + if (r1 == 0) + return 0; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags); + if (invflags) + r2 = invert_depblocks(xpctx, bq, bqcnt2, r2); + if (r1 == 0 || r2 == 0) + { + queue_truncate(bq, bqcnt); + return 0; + } + if (r1 == 1) + return r2; + if (r2 == 1) + return r1; + if ((flags & CPLXDEPS_TODNF) != 0) + return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_if_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags) +{ + /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep_or(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF); + if (r1 == 0) + return 0; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep_or(xpctx, dep2, dep3, bq, flags, 0); + if (r1 == 0 || r2 == 0) + { + queue_truncate(bq, bqcnt); + return 0; + } + if (r1 == 1) + return r2; + if (r2 == 1) + return r1; + if ((flags & CPLXDEPS_TODNF) != 0) + return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_unless_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags) +{ + /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep_and(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF); + if (r1 == 1) + return 1; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep_and(xpctx, dep2, dep3, bq, flags, 0); + if (r1 == 1 || r2 == 1) + { + queue_truncate(bq, bqcnt); + return 1; + } + if (r1 == 0) + return r2; + if (r2 == 0) + return r1; + if ((flags & CPLXDEPS_TODNF) == 0) + return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int expander_isignored(Expander *xp, Solvable *s, Id req); + +static int +normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags) +{ + Pool *pool = xpctx->pool; + Id p, dp; + + if (pool_is_complex_dep(pool, dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND) + { + Id evr = rd->evr; + if (ISRELDEP(evr)) + { + Reldep *rd2 = GETRELDEP(pool, evr); + if (rd2->flags == REL_ELSE) + return normalize_dep_if_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags); + } + return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF); + } + if (rd->flags == REL_UNLESS) + { + Id evr = rd->evr; + if (ISRELDEP(evr)) + { + Reldep *rd2 = GETRELDEP(pool, evr); + if (rd2->flags == REL_ELSE) + return normalize_dep_unless_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags); + } + return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF); + } + if (rd->flags == REL_OR) + return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, 0); + if (rd->flags == REL_AND) + return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, 0); + } + + if (xpctx->ignore_s && (flags & CPLXDEPS_TODNF) == 0) + { + if (expander_isignored(xpctx->xp, xpctx->ignore_s, dep)) + return 1; + } + + dp = pool_whatprovides(pool, dep); + if (dp == 2) + return 1; + if (dp < 2 || !pool->whatprovidesdata[dp]) + return 0; + if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE) + return 1; + if ((flags & CPLXDEPS_TODNF) != 0) + { + while ((p = pool->whatprovidesdata[dp++]) != 0) + queue_push2(bq, p, 0); + } + else + { + while ((p = pool->whatprovidesdata[dp++]) != 0) + queue_push(bq, p); + queue_push(bq, 0); + } + return -1; +} + +#define ISCPLX(pool, d) (ISRELDEP(d) && GETRELID(d) >= pool->nrels) +#define GETCPLX(pool, d) (GETRELID(d) - pool->nrels) +#define MAKECPLX(pool, d) (MAKERELDEP(pool->nrels + d)) + +#define DEPTYPE_REQUIRES 0 +#define DEPTYPE_CONFLICTS 1 +#define DEPTYPE_OBSOLETES 2 +#define DEPTYPE_RECOMMENDS 3 +#define DEPTYPE_PROVIDES 4 + +#define ERROR_NOPROVIDER 1 +#define ERROR_CHOICE 2 +#define ERROR_CONFLICTINGPROVIDERS 3 +#define ERROR_PROVIDERINFO 4 +#define ERROR_PROVIDERINFO2 5 +#define ERROR_BADDEPENDENCY 6 +#define ERROR_CONFLICT 7 +#define ERROR_CONFLICT2 8 +#define ERROR_ALLCONFLICT 9 +#define ERROR_NOPROVIDERINFO 10 + +static void +expander_dbg(Expander *xp, const char *format, ...) +{ + va_list args; + char buf[1024]; + int l; + + if (!xp->debug) + return; + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + l = strlen(buf); + if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STDOUT)) != 0) + { + printf("%s", buf); + if (buf[0] != ' ' || (l && buf[l - 1] == '\n')) + fflush(stdout); + } + if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STR)) != 0) + { + if (l >= xp->debugstrf) /* >= because of trailing \0 */ + { + xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024); + xp->debugstrf = l + 1024; + } + strcpy(xp->debugstr + xp->debugstrl, buf); + xp->debugstrl += l; + xp->debugstrf -= l; + } +} + +static void +expander_clrdbg(Expander *xp) +{ + if (xp->debugstr) + free(xp->debugstr); + xp->debugstr = 0; + xp->debugstrl = xp->debugstrf = 0; +} + +static const char * +expander_solvid2name(Expander *xp, Id p) +{ + const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name); + Repo *r; + if (!xp->debug) + return n; + r = xp->pool->solvables[p].repo; + if (!r) + return n; + return pool_tmpjoin(xp->pool, n, "@", r->name); +} + +static const char * +expander_solvid2str(Expander *xp, Id p) +{ + const char *n = pool_solvid2str(xp->pool, p); + Repo *r; + if (!xp->debug) + return n; + r = xp->pool->solvables[p].repo; + if (!r) + return n; + return pool_tmpjoin(xp->pool, n, "@", r->name); +} + +static int +pkgname_sort_cmp(const void *ap, const void *bp, void *dp) +{ + Pool *pool = (Pool *)dp; + Id a = *(Id *)ap; + Id b = *(Id *)bp; + return strcmp(pool_id2str(pool, pool->solvables[a].name), pool_id2str(pool, pool->solvables[b].name)); +} + +static int +expander_isignored(Expander *xp, Solvable *s, Id req) +{ + Pool *pool = xp->pool; + Id id = id2name(pool, req); + const char *n; + + if (!xp->ignoreignore) + { + if (MAPTST(&xp->ignored, id)) + return 1; + if (MAPTST(&xp->ignoredx, id)) + { + Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0); + if (xid && MAPTST(&xp->ignored, xid)) + return 1; + } + } + n = pool_id2str(pool, id); + if (!strncmp(n, "rpmlib(", 7)) + { + MAPEXP(&xp->ignored, id); + MAPSET(&xp->ignored, id); + return 1; + } + if (*n == '/') + { + if (!xp->havefileprovides || pool->whatprovides[id] <= 1) + { + MAPEXP(&xp->ignored, id); + MAPSET(&xp->ignored, id); + return 1; + } + } + return 0; +} + +static int +expander_to_cplxblks(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr) +{ + int blkoff = xpctx->cplxblks.count; + queue_push(&xpctx->cplxblks, p); + queue_push(&xpctx->cplxblks, dep); + queue_push(&xpctx->cplxblks, deptype); + for (;;) + { + Id pp = *ptr++; + queue_push(&xpctx->cplxblks, pp); + if (!pp) + break; + } + return blkoff; +} + +static int +expander_check_cplxblock(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr, int blkoff) +{ + Pool *pool = xpctx->pool; + int posn = 0, posi = 0, negn = 0, negi = 0; + Id pp, *ptr2 = ptr; + Id lastcon = 0; + + while ((pp = *ptr2++) != 0) + { + if (pp > 0) + { + posn++; + if (MAPTST(&xpctx->installed, pp)) + posi++; + } + else + { + if (p == -pp) + continue; /* ignore redundant self-entry */ + negn++; + if (MAPTST(&xpctx->installed, -pp)) + negi++; + else + lastcon = -pp; + } + } +#if 0 + printf("expander_check_cplxblock pos: %d,%d neg: %d,%d\n", posn, posi, negn, negi); +#endif + if (posi) + return -1; + if (!posn && deptype == DEPTYPE_RECOMMENDS) + return -1; + if (negi == negn) + { + /* all neg installed */ + if (posn) + { + /* posn > 0 and all neg installed, add to todo */ + if (blkoff < 0) + blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr); +#if 0 + printf("put on todo, blkoff = %d\n", blkoff); +#endif + queue_push2(&xpctx->todo, MAKECPLX(pool, blkoff), p); + } + else + { + /* no posn, conflict */ + for (ptr2 = ptr; (pp = *ptr2++) != 0; ) + { + if (p == -pp) + continue; /* ignore redundant self-entry */ + if (deptype == DEPTYPE_REQUIRES) + { + /* do not report a requires as conflicts */ + queue_push(&xpctx->errors, ERROR_NOPROVIDER); + queue_push2(&xpctx->errors, dep, p); + break; + } + queue_push(&xpctx->errors, ERROR_CONFLICT); + queue_push2(&xpctx->errors, p, -pp); + } + } + return -1; + } + else if (!posn && negn && negi == negn - 1) + { + /* add conflict */ +#if 0 + printf("add conflict %d %d\n", lastcon, p); +#endif + MAPEXP(&xpctx->conflicts, pool->nsolvables); + MAPSET(&xpctx->conflicts, lastcon); + if (p) + queue_push2(&xpctx->conflictsinfo, lastcon, p); /* always do this for rich deps */ + return -1; + } + else + { +#ifdef DEBUG_COND + printf("put/stay on cond queue, blkoff = %d\n", blkoff); +#endif + /* either posn > 0 and 1 neg not installed or more than 1 neg not installed */ + if (blkoff < 0) + blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr); + return blkoff; + } +} + +static void +expander_installed_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype) +{ + Queue *cplxq = &xpctx->cplxq; + int r, i, start = cplxq->count, blkoff; + +#if 0 + printf("expander_installed_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype); +#endif + if (deptype == DEPTYPE_CONFLICTS) + { + r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF); + r = invert_depblocks(xpctx, cplxq, start, r); + } + else + r = normalize_dep(xpctx, dep, cplxq, 0); +#if 0 + print_depblocks(xpctx, cplxq, start, r); +#endif + if (r == 1) + return; + if (r == 0) + { + if (deptype == DEPTYPE_CONFLICTS) + { + queue_push(&xpctx->errors, ERROR_ALLCONFLICT); + queue_push2(&xpctx->errors, dep, p); + } + else if (deptype != DEPTYPE_RECOMMENDS) + { + queue_push(&xpctx->errors, ERROR_NOPROVIDER); + queue_push2(&xpctx->errors, dep, p); + } + return; + } + while (start < cplxq->count) + { + /* find end */ + for (i = start; cplxq->elements[i] != 0; i++) + ; + blkoff = expander_check_cplxblock(xpctx, p, dep, deptype, cplxq->elements + start, -1); + if (blkoff >= 0) + { + Pool *pool = xpctx->pool; + Id p; + MAPEXP(&xpctx->todo_condmap, pool->nsolvables); + for (i = start; (p = cplxq->elements[i]) != 0; i++) + if (p < 0) + MAPSET(&xpctx->todo_condmap, -p); + queue_push(&xpctx->todo_cond, blkoff); + } + start = i + 1; + } + queue_truncate(cplxq, start); +} + +static int +expander_checkconflicts_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype, int recorderrors) +{ + Queue *cplxq = &xpctx->cplxq; + int r, i, start = cplxq->count; + Id pp; + int ret = 0; + +#if 0 + printf("expander_checkconflicts_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype); +#endif + if (deptype == DEPTYPE_CONFLICTS) + { + r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF); + r = invert_depblocks(xpctx, cplxq, start, r); + } + else + r = normalize_dep(xpctx, dep, cplxq, 0); +#if 0 + print_depblocks(xpctx, cplxq, start, r); +#endif + /* r == 0: conflict with everything. Ignore here, pick error up when package gets installed */ + if (r == 0 || r == 1) + return 0; + while (start < cplxq->count) + { + for (i = start; (pp = cplxq->elements[i]) != 0; i++) + if (pp > 0 || (pp < 0 && !MAPTST(&xpctx->installed, -pp))) + break; + if (pp == 0) + { + /* no pos and all neg installed -> conflict */ + for (i = start; (pp = cplxq->elements[i]) != 0; i++) + { + pp = -cplxq->elements[i]; + if (recorderrors) + { + queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO); + queue_push2(&xpctx->errors, p, pp); + } + else if (xpctx->xp->debug) + { + Pool *pool = xpctx->pool; + expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, pp)); + } + ret = ret ? 1 : pp; + } + } + for (; cplxq->elements[i] != 0; i++) + ; + start = i + 1; + } + queue_truncate(cplxq, start); + return ret; +} + +static void +updateconflictsinfo(ExpanderCtx *xpctx) +{ + int i; + Pool *pool = xpctx->pool; + Queue *out = xpctx->out; + Queue *conflictsinfo = &xpctx->conflictsinfo; + + if (xpctx->ignoreconflicts) + return; + for (i = xpctx->cidone; i < out->count; i++) + { + Id p, p2, pp2; + Id con, *conp; + Solvable *s; + p = out->elements[i]; + s = pool->solvables + p; + /* keep in sync with expander_installed! */ + if (s->conflicts) + { + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + if (pool_is_complex_dep(pool, con)) + continue; /* already pushed */ + FOR_PROVIDES(p2, pp2, con) + { + if (p2 == p) + continue; + queue_push2(conflictsinfo, p2, p); + } + } + } + if (s->obsoletes) + { + conp = s->repo->idarraydata + s->obsoletes; + while ((con = *conp++) != 0) + { + FOR_PROVIDES(p2, pp2, con) + { + if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con)) + continue; + queue_push2(conflictsinfo, p2, -p); + } + } + } + } + xpctx->cidone = out->count; +} + +static int +findconflictsinfo(ExpanderCtx *xpctx, Id p, int recorderrors) +{ + Queue *conflictsinfo = &xpctx->conflictsinfo; + int i, ret = 0; + + if (xpctx->cidone < xpctx->out->count) + updateconflictsinfo(xpctx); + + for (i = 0; i < conflictsinfo->count; i++) + if (conflictsinfo->elements[i] == p) + { + ret = conflictsinfo->elements[i + 1]; + if (recorderrors) + { + queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2); + queue_push2(&xpctx->errors, p, ret); + } + else if (xpctx->xp->debug) + { + Pool *pool = xpctx->pool; + expander_dbg(xpctx->xp, "ignoring provider %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_solvid2str(pool, ret > 0 ? ret : -ret), ret > 0 ? "conflicts with" : "obsoletes"); + } + } + if (!ret) + { + /* conflict from our job, i.e. a !xxx dep */ + if (recorderrors) + { + queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2); + queue_push2(&xpctx->errors, p, 0); + } + else if (xpctx->xp->debug) + { + Pool *pool = xpctx->pool; + expander_dbg(xpctx->xp, "ignoring conflicted provider %s\n", pool_solvid2str(pool, p)); + } + } + return ret; +} + + +static void +recheck_conddeps(ExpanderCtx *xpctx) +{ + int i; + for (i = 0; i < xpctx->todo_cond.count; i++) + { + int blkoff = xpctx->todo_cond.elements[i]; +#ifdef DEBUG_COND + printf("todo_cond %d\n", blkoff); +#endif + Id *ptr = xpctx->cplxblks.elements + blkoff; + if (expander_check_cplxblock(xpctx, ptr[0], ptr[1], ptr[2], ptr + 3, blkoff) < 0) + { +#ifdef DEBUG_COND + printf("remove no longer needed cond entry\n"); +#endif + queue_delete(&xpctx->todo_cond, i); + i--; + } + } +} + +/* install a single package */ +static void +expander_installed(ExpanderCtx *xpctx, Id p) +{ + Pool *pool = xpctx->pool; + Expander *xp = xpctx->xp; + Solvable *s = pool->solvables + p; + Id req, *reqp, con, *conp; + +#if 0 +printf("expander_installed %s\n", pool_solvid2str(pool, p)); +#endif + MAPSET(&xpctx->installed, p); + queue_push(xpctx->out, p); + + if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p)) + findconflictsinfo(xpctx, p, 2); + + /* add synthetic conflicts from the project config */ + if (MAPTST(&xp->conflicts, s->name)) + { + int i; + for (i = 0; i < xp->conflictsq.count; i++) + { + Id p2, pp2; + Id id = xp->conflictsq.elements[i]; + if (id != s->name) + continue; + id = xp->conflictsq.elements[i ^ 1]; + FOR_PROVIDES(p2, pp2, id) + { + if (pool->solvables[p2].name != id) + continue; + if (MAPTST(&xpctx->installed, p2)) + { + queue_push(&xpctx->errors, ERROR_CONFLICT); + queue_push2(&xpctx->errors, p, p2); + continue; + } + MAPEXP(&xpctx->conflicts, pool->nsolvables); + MAPSET(&xpctx->conflicts, p2); + queue_push2(&xpctx->conflictsinfo, p2, p); + } + } + } + + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + if (req == SOLVABLE_PREREQMARKER) + continue; + if (ISRELDEP(req) && GETRELDEP(pool, req)->flags == REL_ERROR) + { + queue_push(&xpctx->errors, ERROR_BADDEPENDENCY); + queue_push2(&xpctx->errors, GETRELDEP(pool, req)->evr, p); + continue; + } + if (pool_is_complex_dep(pool, req)) + { + xpctx->ignore_s = s; + expander_installed_complexdep(xpctx, p, req, DEPTYPE_REQUIRES); + xpctx->ignore_s = 0; + continue; + } + if (expander_isignored(xp, s, req)) + continue; + queue_push2(&xpctx->todo, req, p); + } + } + if (!xpctx->ignoreconflicts) + { + if (s->conflicts) + { + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + Id p2, pp2; + if (ISRELDEP(con) && GETRELDEP(pool, con)->flags == REL_ERROR) + { + queue_push(&xpctx->errors, ERROR_BADDEPENDENCY); + queue_push2(&xpctx->errors, GETRELDEP(pool, con)->evr, p); + continue; + } + if (pool_is_complex_dep(pool, con)) + { + expander_installed_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS); + continue; + } + FOR_PROVIDES(p2, pp2, con) + { + if (p2 == p) + continue; + if (MAPTST(&xpctx->installed, p2)) + { + queue_push(&xpctx->errors, ERROR_CONFLICT); + queue_push2(&xpctx->errors, p, p2); + continue; + } + MAPEXP(&xpctx->conflicts, pool->nsolvables); + MAPSET(&xpctx->conflicts, p2); + if (xp->debug) + queue_push2(&xpctx->conflictsinfo, p2, p); + } + } + } + if (s->obsoletes) + { conp = s->repo->idarraydata + s->obsoletes; while ((con = *conp++) != 0) { @@ -659,28 +1560,77 @@ expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *co { if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con)) continue; - MAPEXP(conflicts, pool->nsolvables); - MAPSET(conflicts, p2); + if (MAPTST(&xpctx->installed, p2)) + { + queue_push(&xpctx->errors, ERROR_CONFLICT); + queue_push2(&xpctx->errors, p, -p2); + continue; + } + MAPEXP(&xpctx->conflicts, pool->nsolvables); + MAPSET(&xpctx->conflicts, p2); if (xp->debug) - queue_push2(conflictsinfo, p2, -p); + queue_push2(&xpctx->conflictsinfo, p2, -p); } } } if (xp->debug) - *cidone = out->count; + xpctx->cidone = xpctx->out->count; } + if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p)) + recheck_conddeps(xpctx); } -static inline int -expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int isobsoletes) +/* same as expander_installed, but install multiple packages + * in one block */ +static void +expander_installed_multiple(ExpanderCtx *xpctx, Queue *toinstall) { - Pool *pool = xp->pool; + int i, j, havecond = 0; + + /* unify */ + for (i = j = 0; i < toinstall->count; i++) + { + Id p = toinstall->elements[i]; + if (MAPTST(&xpctx->installed, p)) + continue; /* already seen */ + MAPSET(&xpctx->installed, p); + toinstall->elements[j++] = p; + if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p)) + { + havecond = 1; + MAPCLR(&xpctx->todo_condmap, p); /* no longer needed */ + } + } + queue_truncate(toinstall, j); + + /* run conditionals first */ + if (havecond) + recheck_conddeps(xpctx); + + if (!xpctx->errors.count) + for (i = 0; i < toinstall->count; i++) + expander_installed(xpctx, toinstall->elements[i]); + queue_empty(toinstall); +} + +static int +expander_checkconflicts(ExpanderCtx *xpctx, Id p, Id *conflicts, int isobsoletes, int recorderrors) +{ + Map *installed = &xpctx->installed; + Pool *pool = xpctx->pool; Id con, p2, pp2; + int ret = 0; - if (xp->ignoreconflicts) + if (xpctx->ignoreconflicts) return 0; while ((con = *conflicts++) != 0) { + if (!isobsoletes && pool_is_complex_dep(pool, con)) + { + p2 = expander_checkconflicts_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS, recorderrors); + ret = ret ? 1 : p2; + continue; + } FOR_PROVIDES(p2, pp2, con) { if (p == p2) @@ -688,154 +1638,500 @@ expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int i if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con)) continue; if (MAPTST(installed, p2)) - return p2; + { + if (recorderrors) + { + queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO); + queue_push2(&xpctx->errors, p, isobsoletes ? -p2 : p2); + } + else if (xpctx->xp->debug) + { + if (isobsoletes) + expander_dbg(xpctx->xp, "ignoring provider %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2)); + else + expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2)); + } + ret = ret ? 1 : p2; + } } } - return 0; + return ret; } static void -expander_updateconflictsinfo(Expander *xp, Queue *conflictsinfo, int *cidone, Queue *out) +expander_updaterecommendedmap(ExpanderCtx *xpctx) { - Pool *pool = xp->pool; + Pool *pool = xpctx->pool; + Queue *out = xpctx->out; + Map *recommended = &xpctx->recommended; + int i; - if (xp->ignoreconflicts) - return; - for (i = *cidone; i < out->count; i++) + Id p, pp, rec, *recp; + for (i = xpctx->recdone; i < out->count; i++) { - Id p, p2, pp2; - Id con, *conp; Solvable *s; - p = out->elements[i]; - s = pool->solvables + p; - /* keep in sync with expander_installed! */ - if (s->conflicts) + s = pool->solvables + out->elements[i]; + if (s->recommends) { - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) + MAPEXP(recommended, pool->nsolvables); + for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; ) + FOR_PROVIDES(p, pp, rec) + MAPSET(recommended, p); + } + } + xpctx->recdone = out->count; +} + +static int +expander_dep_fulfilled(ExpanderCtx *xpctx, Id dep) +{ + Pool *pool = xpctx->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND) + { + if (ISRELDEP(rd->evr)) { - FOR_PROVIDES(p2, pp2, con) + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) { - if (p2 == p) - continue; - queue_push2(conflictsinfo, p2, p); + if (expander_dep_fulfilled(xpctx, rd2->name)) + return expander_dep_fulfilled(xpctx, rd->name); + return expander_dep_fulfilled(xpctx, rd2->evr); } } + if (expander_dep_fulfilled(xpctx, rd->name)) /* A OR ~B */ + return 1; + return !expander_dep_fulfilled(xpctx, rd->evr); } - if (s->obsoletes) + if (rd->flags == REL_UNLESS) { - conp = s->repo->idarraydata + s->obsoletes; - while ((con = *conp++) != 0) + if (ISRELDEP(rd->evr)) { - FOR_PROVIDES(p2, pp2, con) + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) { - if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con)) - continue; - queue_push2(conflictsinfo, p2, -p); + if (!expander_dep_fulfilled(xpctx, rd2->name)) + return expander_dep_fulfilled(xpctx, rd->name); + return expander_dep_fulfilled(xpctx, rd2->evr); } } + if (!expander_dep_fulfilled(xpctx, rd->name)) /* A AND ~B */ + return 0; + return !expander_dep_fulfilled(xpctx, rd->evr); + } + if (rd->flags == REL_AND) + { + if (!expander_dep_fulfilled(xpctx, rd->name)) + return 0; + return expander_dep_fulfilled(xpctx, rd->evr); + } + if (rd->flags == REL_OR) + { + if (expander_dep_fulfilled(xpctx, rd->name)) + return 1; + return expander_dep_fulfilled(xpctx, rd->evr); } } - *cidone = out->count; + FOR_PROVIDES(p, pp, dep) + { + if (MAPTST(&xpctx->installed, p)) + return 1; + } + return 0; } -static void -expander_updaterecommendedmap(Expander *xp, Map *recommended, int *recdone, Queue *out) +static int +prune_neg_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n) { - Pool *pool = xp->pool; + Expander *xp = xpctx->xp; + Pool *pool = xpctx->pool; + Id whon = who ? pool->solvables[who].name : 0; + int i, j; + for (i = j = 0; i < n; i++) + { + Id p = e[i]; + Id pn = pool->solvables[p].name; + if (MAPTST(&xp->preferneg, pn)) + continue; + if (who && MAPTST(&xp->prefernegx, pn)) + { + Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); + if (xid && MAPTST(&xp->preferneg, xid)) + continue; + } + e[j++] = p; + } + return j ? j : n; +} - int i; +static int +prune_pos_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n, int domulti) +{ + Expander *xp = xpctx->xp; + Queue *pruneq = &xpctx->pruneq; + Pool *pool = xpctx->pool; + Id whon = who ? pool->solvables[who].name : 0; + int i, j; + + if (pruneq->count) + queue_empty(pruneq); + for (i = j = 0; i < n; i++) + { + Id p = e[i]; + Id pn = pool->solvables[p].name; + if (MAPTST(&xp->preferpos, pn)) + queue_push2(pruneq, pn, p); + else if (who && MAPTST(&xp->preferposx, pn)) + { + Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); + if (xid && MAPTST(&xp->preferpos, xid)) + queue_push2(pruneq, xid, p); + } + } + if (!pruneq->count) + return n; + if (pruneq->count > 2) + { + if (!domulti) + return n; + /* pos prefers are ordered, the first one wins */ + for (i = 0; i < xp->preferposq.count; i++) + { + Id xid = xp->preferposq.elements[i]; + for (j = 0; j < pruneq->count; j += 2) + if (pruneq->elements[j] == xid) + { + e[0] = pruneq->elements[j + 1]; + return 1; + } + } + } + e[0] = pruneq->elements[1]; /* simple case, just one prefer */ + return 1; +} + +static int +prune_or_dep(ExpanderCtx *xpctx, Id dep, Id *e, int n) +{ + Pool *pool = xpctx->pool; + int i, j; + Id p, pp; + + for (;;) + { + Reldep *rd = 0; + if (ISRELDEP(dep)) + { + rd = GETRELDEP(pool, dep); + if (rd->flags != REL_OR) + rd = 0; + } + if (rd) + dep = rd->name; + i = j = 0; + /* both sets are ordered */ + FOR_PROVIDES(p, pp, dep) + { + if (p < e[i]) + continue; + while (i < n && p > e[i]) + i++; + if (i == n) + break; + if (p == e[i]) + e[j++] = p; + } + if (j) + return j; + if (rd) + dep = rd->evr; + else + break; + } + return n; +} + +static int +prune_supplemented(ExpanderCtx *xpctx, Id *e, int n) +{ + Pool *pool = xpctx->pool; + int i, j; + Id sup, *supp; + + for (i = j = 0; i < n; i++) + { + Id p = e[i]; + Solvable *s = pool->solvables + p; + if (!s->supplements) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (expander_dep_fulfilled(xpctx, sup)) + break; + if (sup) + e[j++] = p; + } + return j ? j : n; +} + +static void +add_recommended_packages(ExpanderCtx *xpctx, Solvable *s) +{ + Pool *pool = xpctx->pool; Id p, pp, rec, *recp; - for (i = *recdone; i < out->count; i++) + for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; ) { - Solvable *s; - s = pool->solvables + out->elements[i]; - if (s->recommends) - { - MAPEXP(recommended, pool->nsolvables); - for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; ) - FOR_PROVIDES(p, pp, rec) - MAPSET(recommended, p); - } + int haveone = 0; + if (pool_is_complex_dep(pool, rec)) + { + expander_installed_complexdep(xpctx, s - pool->solvables, rec, DEPTYPE_RECOMMENDS); + continue; + } + FOR_PROVIDES(p, pp, rec) + { + if (MAPTST(&xpctx->installed, p)) + break; + if (haveone) + continue; + if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p)) + continue; + if (pool->solvables[p].conflicts && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0) != 0) + continue; + if (pool->solvables[p].obsoletes && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0) != 0) + continue; + haveone = 1; + } + if (p) + continue; /* already fulfilled */ + if (haveone) + queue_push2(&xpctx->todo, rec, s - pool->solvables); } - *recdone = out->count; } -static inline int -findconflictsinfo(Queue *conflictsinfo, Id p) +static void +expander_growmaps(Expander *xp) { - int i; + Pool *pool = xp->pool; + MAPEXP(&xp->ignored, pool->ss.nstrings); + MAPEXP(&xp->ignoredx, pool->ss.nstrings); + MAPEXP(&xp->preferpos, pool->ss.nstrings); + MAPEXP(&xp->preferposx, pool->ss.nstrings); + MAPEXP(&xp->preferneg, pool->ss.nstrings); + MAPEXP(&xp->prefernegx, pool->ss.nstrings); + MAPEXP(&xp->conflicts, pool->ss.nstrings); +} - for (i = 0; i < conflictsinfo->count; i++) - if (conflictsinfo->elements[i] == p) - return conflictsinfo->elements[i + 1]; - return 0; +static Id +str2id_dup(Pool *pool, const char *str) +{ + char buf[256]; + size_t l = strlen(str); + if (l < 256) { + memcpy(buf, str, l + 1); + return pool_str2id(pool, buf, 1); + } else { + return pool_str2id(pool, pool_tmpjoin(pool, str, 0, 0), 1); + } } -#define ERROR_NOPROVIDER 1 -#define ERROR_CHOICE 2 -#define ERROR_CONFLICTINGPROVIDER 3 -#define ERROR_CONFLICTINGPROVIDERS 4 -#define ERROR_PROVIDERINFO 5 -#define ERROR_PROVIDERINFO2 6 +static void +add_noproviderinfo(ExpanderCtx *xpctx, Id dep, Id who) +{ + Pool *pool = xpctx->pool; + Reldep *rd, *prd; + Id p, pp, prov, *provp; + int nprovinfo; + if (xpctx->xp->debug) + { + if (who) + expander_dbg(xpctx->xp, "nothing provides %s needed by %s\n", pool_dep2str(pool, dep), expander_solvid2str(xpctx->xp, who)); + else + expander_dbg(xpctx->xp, "nothing provides %s\n", pool_dep2str(pool, dep)); + } + if (!ISRELDEP(dep)) + return; + rd = GETRELDEP(pool, dep); + if (rd->flags >= 8 || ISRELDEP(rd->name) || ISRELDEP(rd->evr)) + return; + nprovinfo = 0; + FOR_PROVIDES(p, pp, rd->name) + { + Solvable *s = pool->solvables + p; + if (!s->repo || !s->provides) + continue; + for (provp = s->repo->idarraydata + s->provides; (prov = *provp++) != 0; ) + { + if (!ISRELDEP(prov)) + continue; + prd = GETRELDEP(pool, prov); + if (prd->name != rd->name || ISRELDEP(prd->evr)) + continue; + queue_push(&xpctx->errors, ERROR_NOPROVIDERINFO); + if (prd->name == s->name && prd->evr == s->evr) + { + if (xpctx->xp->debug) + expander_dbg(xpctx->xp, "%s has version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr)); + queue_push2(&xpctx->errors, prd->evr, 0); + } + else + { + if (xpctx->xp->debug) + expander_dbg(xpctx->xp, "%s provides version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr)); + queue_push2(&xpctx->errors, prd->evr, p); + } + if (++nprovinfo >= 4) + return; /* only show the first 4 providers */ + } + } +} -int -expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl) +static int +expander_expand(Expander *xp, Queue *in, Queue *indep, Queue *out, Queue *ignoreq, int options) { + ExpanderCtx xpctx; Pool *pool = xp->pool; - Queue todo, errors, cerrors, qq, posfoundq; - Map installed; - Map conflicts; - Map recommended; - Queue conflictsinfo; - int cidone; - int recdone; + Queue toinstall; + Queue qq, choices; Solvable *s; Id q, p, pp; - int i, j, nerrors, doamb, ambcnt; - Id id, who, whon, pn; - Id conflprov, conflprovpc; - int haverecommended = 0; - int haverecommended_done = 0; - - map_init(&installed, pool->nsolvables); - map_init(&conflicts, 0); - map_init(&recommended, 0); - queue_init(&conflictsinfo); - queue_init(&todo); + int i, j, nerrors; + int ti, tj, tc; + Id todoid, id, who, whon; + Id conflprovpc; + int pass; + Queue revertignore; + int oldignoreignore = xp->ignoreignore; + Map oldignored, oldignoredx; + int ignoremapssaved = 0; + int dorecstart = 0; + + memset(&xpctx, 0, sizeof(xpctx)); + xpctx.xp = xp; + xpctx.pool = pool; + xpctx.out = out; + xpctx.ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : xp->ignoreignore; + xpctx.ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : xp->ignoreconflicts; + xpctx.userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : xp->userecommendsforchoices; + xpctx.usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : xp->usesupplementsforchoices; + xpctx.dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : xp->dorecommends; + xpctx.dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : xp->dosupplements; + map_init(&xpctx.installed, pool->nsolvables); + map_init(&xpctx.conflicts, 0); + map_init(&xpctx.recommended, 0); + queue_init(&xpctx.conflictsinfo); + queue_init(&xpctx.todo); + queue_init(&xpctx.todo_cond); + map_init(&xpctx.todo_condmap, 0); + queue_init(&xpctx.errors); + queue_init(&xpctx.cplxq); + queue_init(&xpctx.cplxblks); + queue_init(&xpctx.pruneq); + + queue_init(&toinstall); queue_init(&qq); - queue_init(&errors); - queue_init(&cerrors); - queue_init(&posfoundq); + queue_init(&choices); + queue_init(&revertignore); queue_empty(out); - cidone = 0; - recdone = 0; - if (inconfl) + + /* process ignored. hack: we mess with the ignore config in xp */ + xp->ignoreignore = 0; + if (xpctx.ignoreignore && ignoreq->count) + { + /* bad: have direct ignores and we need to zero the project config ignores */ + oldignored = xp->ignored; + oldignoredx = xp->ignoredx; + ignoremapssaved = 1; + /* clear project config maps */ + memset(&xp->ignored, 0, sizeof(xp->ignored)); + memset(&xp->ignoredx, 0, sizeof(xp->ignoredx)); + } + if (ignoreq->count) { - for (i = 0; i < inconfl->count; i += 2) + /* mix direct ignores with ignores from project config */ + for (i = 0; i < ignoreq->count; i++) { - Id con = inconfl->elements[i]; - FOR_PROVIDES(p, pp, con) + const char *ss; + id = ignoreq->elements[i]; + MAPEXP(&xp->ignored, id); + if (MAPTST(&xp->ignored, id)) + continue; + MAPSET(&xp->ignored, id); + queue_push(&revertignore, id); + if ((ss = strchr(pool_id2str(pool, id), ':')) != 0) { - if (inconfl->elements[i + 1] && !pool_match_nevr(pool, pool->solvables + p, con)) + id = str2id_dup(pool, ss + 1); + MAPEXP(&xp->ignoredx, id); + if (MAPTST(&xp->ignoredx, id)) continue; - MAPEXP(&conflicts, pool->nsolvables); - MAPSET(&conflicts, p); + MAPSET(&xp->ignoredx, id); + queue_push(&revertignore, -id); + } + } + } + else if (xpctx.ignoreignore) + { + /* no direct ignores, ignore project config ignores. + * easy: just disable ignore processing */ + xp->ignoreignore = 1; + } + + /* grow maps to make bit tests cheaper */ + expander_growmaps(xp); + + /* process standard dependencies */ + if (indep) + { + for (i = 0; i < indep->count; i += 2) + { + int deptype = indep->elements[i]; + Id dep = indep->elements[i + 1]; + if (ISRELDEP(dep) && GETRELDEP(pool, dep)->flags == REL_ERROR) + { + queue_push(&xpctx.errors, ERROR_BADDEPENDENCY); + queue_push2(&xpctx.errors, GETRELDEP(pool, dep)->evr, 0); + continue; + } + if ((deptype == DEPTYPE_REQUIRES || deptype == DEPTYPE_CONFLICTS) && pool_is_complex_dep(pool, dep)) + { + expander_installed_complexdep(&xpctx, 0, dep, deptype); + continue; + } + if (deptype == DEPTYPE_REQUIRES) + { + queue_push2(&xpctx.todo, dep, 0); + } + else if (deptype == DEPTYPE_CONFLICTS || deptype == DEPTYPE_OBSOLETES) + { + FOR_PROVIDES(p, pp, dep) + { + if (deptype == DEPTYPE_OBSOLETES && !pool_match_nevr(pool, pool->solvables + p, dep)) + continue; + MAPEXP(&xpctx.conflicts, pool->nsolvables); + MAPSET(&xpctx.conflicts, p); + } } } } - /* do direct expands */ + /* process direct dependencies */ for (i = 0; i < in->count; i++) { id = in->elements[i]; - if (id == expander_directdepsend) + if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_ERROR) { - for (i = i + 1; i < in->count; i++) - if (in->elements[i] != expander_directdepsend) - queue_push2(&todo, in->elements[i], 0); - break; + queue_push(&xpctx.errors, ERROR_BADDEPENDENCY); + queue_push2(&xpctx.errors, GETRELDEP(pool, id)->evr, 0); + continue; + } + if (pool_is_complex_dep(pool, id)) + { + expander_installed_complexdep(&xpctx, 0, id, DEPTYPE_REQUIRES); + continue; } q = 0; FOR_PROVIDES(p, pp, id) @@ -852,425 +2148,738 @@ expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl) } if (!q) { - /* unclear, resolve later */ - queue_push2(&todo, id, 0); + queue_push2(&xpctx.todo, id, 0); /* unclear, resolve later */ continue; } - if (MAPTST(&installed, q)) + if (xp->debug) + expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id)); + queue_push(&toinstall, q); + } + + /* unify toinstall, check against conflicts */ + for (i = 0; i < toinstall.count; i++) + { + p = toinstall.elements[i]; + MAPSET(&xpctx.installed, p); + } + for (i = j = 0; i < toinstall.count; i++) + { + p = toinstall.elements[i]; + if (!MAPTST(&xpctx.installed, p)) continue; - if (conflicts.size && MAPTST(&conflicts, q)) - { - queue_push(&errors, ERROR_CONFLICTINGPROVIDER); - queue_push2(&errors, id, 0); - if (cidone < out->count) - expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out); - queue_push(&errors, ERROR_PROVIDERINFO2); - queue_push2(&errors, q, findconflictsinfo(&conflictsinfo, q)); - continue; - } - if (pool->solvables[q].conflicts && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].conflicts, 0)) != 0) + MAPCLR(&xpctx.installed, p); + toinstall.elements[j++] = p; + } + queue_truncate(&toinstall, j); + if (xpctx.conflicts.size) + { + for (i = 0; i < toinstall.count; i++) { - queue_push(&errors, ERROR_CONFLICTINGPROVIDER); - queue_push2(&errors, id, 0); - queue_push(&errors, ERROR_PROVIDERINFO); - queue_push2(&errors, q, pp); - continue; + p = toinstall.elements[i]; + if (MAPTST(&xpctx.conflicts, p)) + findconflictsinfo(&xpctx, p, 2); } - if (pool->solvables[q].obsoletes && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].obsoletes, 1)) != 0) + } + + /* here is the big expansion loop */ + pass = 0; + while (!xpctx.errors.count) + { + if (toinstall.count) { - queue_push(&errors, ERROR_CONFLICTINGPROVIDER); - queue_push2(&errors, id, 0); - queue_push(&errors, ERROR_PROVIDERINFO); - queue_push2(&errors, q, -pp); + expander_installed_multiple(&xpctx, &toinstall); + pass = 0; continue; } - if (xp->debug) - expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id)); - expander_installed(xp, q, &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); /* unique match! */ - } - - doamb = 0; - ambcnt = todo.count; - while (todo.count) - { - id = queue_shift(&todo); - who = queue_shift(&todo); - if (ambcnt == 0) - { - if (doamb >= 2) - break; /* amb pass had no progress, stop */ - doamb = xp->userecommendsforchoices ? doamb + 1 : 3; - if (doamb == 1 && !haverecommended) - { - for (i = haverecommended_done; i < out->count; i++) - if (pool->solvables[out->elements[i]].recommends) - haverecommended = 1; - haverecommended_done = out->count; - if (!haverecommended) - doamb = 3; - } - if (xp->debug) - { - if (doamb == 2) - expander_dbg(xp, "now doing undecided dependencies with recommends\n"); - else - expander_dbg(xp, "now doing undecided dependencies\n"); - } - ambcnt = todo.count; - } - else - ambcnt -= 2; -// printf("todo %s %s ambcnt %d\n", pool_id2str(pool, pool->solvables[who].name), pool_dep2str(pool, id), ambcnt); -// fflush(stdout); - whon = who ? pool->solvables[who].name : 0; - queue_empty(&qq); - conflprov = 0; - conflprovpc = 0; - FOR_PROVIDES(p, pp, id) + + if (!xpctx.todo.count) { - Id pc; - if (MAPTST(&installed, p)) - break; - if (who && !xp->ignoreignore) + /* almost finished. now do weak deps if requested */ + pass = 0; + if (xpctx.dorecommends) { - Id pn = pool->solvables[p].name; - if (MAPTST(&xp->ignored, pn)) - break; - if (MAPTST(&xp->ignoredx, pn)) + expander_dbg(xp, "--- now doing recommended packages\n"); + for (; dorecstart < out->count; dorecstart++) { - Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); - if (xid && MAPTST(&xp->ignored, xid)) - break; + s = pool->solvables + out->elements[dorecstart]; + if (s->recommends) + add_recommended_packages(&xpctx, s); } + if (xpctx.todo.count) + continue; } - if (conflicts.size && MAPTST(&conflicts, p)) + if (xpctx.dosupplements) { - if (xp->debug) + Id sup, *supp; + expander_dbg(xp, "--- now doing supplemented packages\n"); + for (p = 1; p < pool->nsolvables; p++) { - Id pc = findconflictsinfo(&conflictsinfo, p); - if (pc) - expander_dbg(xp, "ignoring provider %s of %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc > 0 ? pc : -pc), pc > 0 ? "conflicts with" : "obsoletes"); - else - expander_dbg(xp, "ignoring conflicted provider %s of %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id)); + s = pool->solvables + p; + if (!s->supplements || !s->repo) + continue; + if (MAPTST(&xpctx.installed, p)) + continue; + if (!pool_installable(pool, s)) + continue; + if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p)) + continue; + if (s->conflicts && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->conflicts, 0, 0) != 0) + continue; + if (s->obsoletes && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->obsoletes, 1, 0) != 0) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (expander_dep_fulfilled(&xpctx, sup)) + break; + if (!sup) + continue; + expander_dbg(xp, "added %s because it supplements %s\n", expander_solvid2name(xp, p), pool_dep2str(pool, sup)); + queue_push(&toinstall, p); } - conflprov = conflprov ? 1 : p; - conflprovpc = 0; - continue; + if (toinstall.count) + continue; } - if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0) + /* no new stuff to do, we're finished! */ + break; + } + + expander_dbg(xp, "--- now doing normal dependencies\n"); + + if (pass == 1) + queue_empty(&choices); + + for (ti = tj = 0; ti < xpctx.todo.count; ti += 2) + { + int deptype = DEPTYPE_REQUIRES; + todoid = id = xpctx.todo.elements[ti]; + who = xpctx.todo.elements[ti + 1]; + if (!id) /* deleted entry? */ + continue; + queue_empty(&qq); + if (ISCPLX(pool, id)) { - expander_dbg(xp, "ignoring provider %s of %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc)); - conflprov = conflprov ? 1 : p; - conflprovpc = pc; - continue; + pp = GETCPLX(pool, id); /* p, dep, deptype, ids... */ + id = xpctx.cplxblks.elements[pp + 1]; + deptype = xpctx.cplxblks.elements[pp + 2]; + pp += 3; + while ((p = xpctx.cplxblks.elements[pp++])) + if (p > 0) + queue_push(&qq, p); } - if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0) + else { - expander_dbg(xp, "ignoring provider %s of %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc)); - conflprov = conflprov ? 1 : p; - conflprovpc = -pc; - continue; + FOR_PROVIDES(p, pp, id) + queue_push(&qq, p); } - queue_push(&qq, p); - } - if (p) - continue; - if (qq.count == 0) - { - if (!conflprov) + + if (qq.count == 0) { - queue_push(&errors, ERROR_NOPROVIDER); - queue_push2(&errors, id, who); + if (deptype == DEPTYPE_RECOMMENDS) + continue; + queue_push(&xpctx.errors, ERROR_NOPROVIDER); + queue_push2(&xpctx.errors, id, who); + add_noproviderinfo(&xpctx, id, who); continue; } - /* more work for conflicts */ - if (conflprov != 1) + + /* check installed and ignores */ + whon = who ? pool->solvables[who].name : 0; + for (i = 0; i < qq.count; i++) { - /* nice, just one provider */ - queue_push(&errors, ERROR_CONFLICTINGPROVIDER); - queue_push2(&errors, id, who); - if (!conflprovpc) - { - if (cidone < out->count) - expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out); - conflprovpc = findconflictsinfo(&conflictsinfo, conflprov); - queue_push(&errors, ERROR_PROVIDERINFO2); - queue_push2(&errors, conflprov, conflprovpc); - } - else + p = qq.elements[i]; + if (MAPTST(&xpctx.installed, p)) + break; + if (who && deptype == DEPTYPE_REQUIRES && !xp->ignoreignore) { - queue_push(&errors, ERROR_PROVIDERINFO); - queue_push2(&errors, conflprov, conflprovpc); + Id pn = pool->solvables[p].name; + if (MAPTST(&xp->ignored, pn)) + break; + if (MAPTST(&xp->ignoredx, pn)) + { + Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); + if (xid && MAPTST(&xp->ignored, xid)) + break; + } } + } + if (i < qq.count) + continue; /* ignored dependency or fulfilled */ + + if (pass == 0 && qq.count > 1) + { + xpctx.todo.elements[tj++] = todoid; + xpctx.todo.elements[tj++] = who; continue; } - /* even more work if all providers conflict */ - queue_push(&errors, ERROR_CONFLICTINGPROVIDERS); - queue_push2(&errors, id, who); - if (cidone < out->count) - expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out); - FOR_PROVIDES(p, pp, id) + + /* do conflict pruning */ + conflprovpc = 0; + for (i = j = 0; i < qq.count; i++) { Id pc; - if (conflicts.size && MAPTST(&conflicts, p)) + p = qq.elements[i]; + if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p)) { - pc = findconflictsinfo(&conflictsinfo, p); - queue_push(&errors, ERROR_PROVIDERINFO2); - queue_push2(&errors, p, pc); + if (xp->debug) + findconflictsinfo(&xpctx, p, 0); + conflprovpc = 0; continue; } - if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0) + if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0)) != 0) { - queue_push(&errors, ERROR_PROVIDERINFO); - queue_push2(&errors, p, pc); + conflprovpc = pc; continue; } - if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0) + if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0)) != 0) { - queue_push(&errors, ERROR_PROVIDERINFO); - queue_push2(&errors, p, -pc); + conflprovpc = -pc; continue; } + qq.elements[j++] = p; } - continue; - } - if (qq.count > 1 && !doamb) - { - /* try again later */ - queue_push2(&todo, id, who); + if (j == 0) + { + if (deptype == DEPTYPE_RECOMMENDS) + continue; + queue_push(&xpctx.errors, ERROR_CONFLICTINGPROVIDERS); + queue_push2(&xpctx.errors, id, who); + if (qq.count == 1 && conflprovpc != 1 && conflprovpc != -1) + { + p = qq.elements[0]; + if (conflprovpc) + { + queue_push(&xpctx.errors, ERROR_PROVIDERINFO); + queue_push2(&xpctx.errors, p, conflprovpc); + continue; + } + findconflictsinfo(&xpctx, p, 1); + continue; + } + /* even more work if all providers conflict */ + for (j = 0; j < qq.count; j++) + { + p = qq.elements[j]; + if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p)) + findconflictsinfo(&xpctx, p, 1); + if (pool->solvables[p].conflicts) + expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 1); + if (pool->solvables[p].obsoletes) + expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 1); + } + continue; + } + queue_truncate(&qq, j); + if (qq.count == 1) + { + p = qq.elements[0]; + if (xp->debug) + expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); + queue_push(&toinstall, p); + continue; + } + /* pass is == 1 and we have multiple choices */ if (xp->debug) { expander_dbg(xp, "undecided about %s:%s:", whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); for (i = 0; i < qq.count; i++) - expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i])); - expander_dbg(xp, "\n"); + expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i])); + expander_dbg(xp, "\n"); } + queue_push2(&choices, qq.count + 3, id); + queue_push(&choices, qq.count); + queue_insertn(&choices, choices.count, qq.count, qq.elements); + xpctx.todo.elements[tj++] = todoid; + xpctx.todo.elements[tj++] = who; + } + queue_truncate(&xpctx.todo, tj); + + if (toinstall.count) + continue; + + if (!xpctx.todo.count) + continue; + + /* did not find a package to install, only choices left on todo list */ + if (pass == 0) + { + pass = 1; /* now do conflict pruning */ continue; } - /* prune neg prefers */ - if (qq.count > 1) + expander_dbg(xp, "--- now doing undecided dependencies\n"); + + /* prune prefers */ + for (ti = tc = 0; ti < xpctx.todo.count; ti += 2) { - for (i = j = 0; i < qq.count; i++) + Id who = xpctx.todo.elements[ti + 1]; + Id *qe = choices.elements + tc + 3; + Id id = choices.elements[tc + 1]; + int qn = choices.elements[tc + 2]; + whon = who ? pool->solvables[who].name : 0; + if (qn > 1) + qn = prune_neg_prefers(&xpctx, who, qe, qn); + if (qn > 1) + qn = prune_pos_prefers(&xpctx, who, qe, qn, 0); + if (qn == 1) { - p = qq.elements[i]; - pn = pool->solvables[p].name; - if (MAPTST(&xp->preferneg, pn)) - continue; - if (who && MAPTST(&xp->prefernegx, pn)) - { - Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); - if (xid && MAPTST(&xp->preferneg, xid)) - continue; - } - qq.elements[j++] = p; + p = qe[0]; + if (xp->debug) + expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); + queue_push(&toinstall, p); + xpctx.todo.elements[ti] = 0; /* kill entry */ } - if (j) - queue_truncate(&qq, j); + choices.elements[tc + 2] = qn; + tc += choices.elements[tc]; } + if (toinstall.count) + continue; - /* prune pos prefers */ - if (qq.count > 1) + /* prune pos prefers with domulti and debian or */ + for (ti = tc = 0; ti < xpctx.todo.count; ti += 2) { - queue_empty(&posfoundq); - for (i = j = 0; i < qq.count; i++) + Id who = xpctx.todo.elements[ti + 1]; + Id *qe = choices.elements + tc + 3; + Id id = choices.elements[tc + 1]; + int qn = choices.elements[tc + 2]; + whon = who ? pool->solvables[who].name : 0; + if (qn > 1) + qn = prune_pos_prefers(&xpctx, who, qe, qn, 1); + if (qn > 1 && pool->disttype != DISTTYPE_RPM) { - p = qq.elements[i]; - pn = pool->solvables[p].name; - if (MAPTST(&xp->preferpos, pn)) - { - queue_push2(&posfoundq, pn, p); - qq.elements[j++] = p; - continue; - } - if (who && MAPTST(&xp->preferposx, pn)) - { - Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0); - if (xid && MAPTST(&xp->preferpos, xid)) - { - queue_push2(&posfoundq, xid, p); - qq.elements[j++] = p; - continue; - } - } + if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR) + qn = prune_or_dep(&xpctx, id, qe, qn); } - if (posfoundq.count == 2) + if (qn == 1) { - queue_empty(&qq); - queue_push(&qq, posfoundq.elements[1]); + p = qe[0]; + if (xp->debug) + expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); + queue_push(&toinstall, p); + xpctx.todo.elements[ti] = 0; /* kill entry */ } - else if (posfoundq.count) + choices.elements[tc + 2] = qn; + tc += choices.elements[tc]; + } + if (toinstall.count) + continue; + + /* prune recommended packages */ + if (xpctx.userecommendsforchoices) + expander_updaterecommendedmap(&xpctx); + if (xpctx.recommended.size) + { + expander_dbg(xp, "now doing undecided dependencies with recommends\n"); + for (ti = tc = 0; ti < xpctx.todo.count; ti += 2) { - /* found a pos prefer, now find first hit */ - /* (prefers are ordered) */ - for (i = 0; i < xp->preferposq.count; i++) + Id who = xpctx.todo.elements[ti + 1]; + Id *qe = choices.elements + tc + 3; + Id id = choices.elements[tc + 1]; + int qn = choices.elements[tc + 2]; + whon = who ? pool->solvables[who].name : 0; + for (i = j = 0; i < qn; i++) + if (MAPTST(&xpctx.recommended, qe[i])) + qe[j++] = qe[i]; + if (j) + qn = j; + if (qn == 1) { - Id xid = xp->preferposq.elements[i]; - for (j = 0; j < posfoundq.count; j += 2) - if (posfoundq.elements[j] == xid) - break; - if (j < posfoundq.count) - { - queue_empty(&qq); - queue_push(&qq, posfoundq.elements[j + 1]); - break; - } + p = qe[0]; + if (xp->debug) + expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); + queue_push(&toinstall, p); + xpctx.todo.elements[ti] = 0; /* kill entry */ } + choices.elements[tc + 2] = qn; + tc += choices.elements[tc]; } + if (toinstall.count) + continue; } - - /* prune OR deps */ - if (qq.count > 1 && ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR) + if (xpctx.usesupplementsforchoices) { - Id rid = id; - for (;;) + expander_dbg(xp, "now doing undecided dependencies with supplements\n"); + for (ti = tc = 0; ti < xpctx.todo.count; ti += 2) { - Reldep *rd = 0; - if (ISRELDEP(rid)) + Id who = xpctx.todo.elements[ti + 1]; + Id *qe = choices.elements + tc + 3; + Id id = choices.elements[tc + 1]; + int qn = choices.elements[tc + 2]; + whon = who ? pool->solvables[who].name : 0; + qn = prune_supplemented(&xpctx, qe, qn); + if (qn == 1) { - rd = GETRELDEP(pool, rid); - if (rd->flags != REL_OR) - rd = 0; + p = qe[0]; + if (xp->debug) + expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); + queue_push(&toinstall, p); + xpctx.todo.elements[ti] = 0; /* kill entry */ } - if (rd) - rid = rd->name; - queue_empty(&qq); - FOR_PROVIDES(p, pp, rid) - queue_push(&qq, p); - if (qq.count) - break; - if (rd) - rid = rd->evr; - else - break; + choices.elements[tc + 2] = qn; + tc += choices.elements[tc]; } + if (toinstall.count) + continue; } - if (qq.count > 1 && doamb == 1) - { - queue_push2(&todo, id, who); - continue; - } - - /* prioritize recommended packages. */ - if (qq.count > 1 && doamb == 2) - { - expander_updaterecommendedmap(xp, &recommended, &recdone, out); - if (recommended.size) - { - for (i = j = 0; i < qq.count; i++) - if (MAPTST(&recommended, qq.elements[i])) - qq.elements[j++] = qq.elements[i]; - if (j) - queue_truncate(&qq, j); - } - } - + /* nothing more to prune. record errors. */ + for (ti = tc = 0; ti < xpctx.todo.count; ti += 2) + { + Id who = xpctx.todo.elements[ti + 1]; + Id *qe = choices.elements + tc + 3; + Id id = choices.elements[tc + 1]; + int qn = choices.elements[tc + 2]; + queue_push(&xpctx.errors, ERROR_CHOICE); + queue_push2(&xpctx.errors, id, who); + for (i = 0; i < qn; i++) + queue_push(&xpctx.errors, qe[i]); + queue_push(&xpctx.errors, 0); + tc += choices.elements[tc]; + } + } - if (qq.count > 1) + /* free data */ + map_free(&xpctx.installed); + map_free(&xpctx.conflicts); + map_free(&xpctx.recommended); + map_free(&xpctx.todo_condmap); + queue_free(&xpctx.conflictsinfo); + queue_free(&xpctx.todo_cond); + queue_free(&xpctx.todo); + queue_free(&toinstall); + queue_free(&qq); + queue_free(&choices); + queue_free(&xpctx.pruneq); + queue_free(&xpctx.cplxq); + queue_free(&xpctx.cplxblks); + + /* revert ignores */ + xp->ignoreignore = oldignoreignore; + if (ignoremapssaved) + { + map_free(&xp->ignored); + map_free(&xp->ignoredx); + xp->ignored = oldignored; + xp->ignoredx = oldignoredx; + } + else + { + for (i = 0; i < revertignore.count; i++) { - queue_push(&cerrors, ERROR_CHOICE); - queue_push2(&cerrors, id, who); - for (i = 0; i < qq.count; i++) - queue_push(&cerrors, qq.elements[i]); - queue_push(&cerrors, 0); - /* try again later */ - queue_push2(&todo, id, who); - continue; + id = revertignore.elements[i]; + if (id > 0) + MAPCLR(&xp->ignored, id); + else + MAPCLR(&xp->ignoredx, -id); } - if (xp->debug) - expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, qq.elements[0]), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id)); - expander_installed(xp, qq.elements[0], &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); - doamb = 0; - ambcnt = todo.count; - queue_empty(&cerrors); - } - map_free(&installed); - map_free(&conflicts); - map_free(&recommended); - queue_free(&conflictsinfo); + } + queue_free(&revertignore); + + /* finish return queue, count errors */ nerrors = 0; - if (errors.count || cerrors.count) + if (xpctx.errors.count) { queue_empty(out); - for (i = 0; i < errors.count; i += 3) + queue_insertn(out, 0, xpctx.errors.count, xpctx.errors.elements); + for (i = 0; i < out->count; i += 3) { - queue_push(out, errors.elements[i]); - queue_push(out, errors.elements[i + 1]); - queue_push(out, errors.elements[i + 2]); nerrors++; + if (out->elements[i] == ERROR_CHOICE) + while (out->elements[i + 3]) + i++; } - for (i = 0; i < cerrors.count; ) + } + queue_free(&xpctx.errors); + return nerrors; +} + +static Expander * +expander_create(Pool *pool, Queue *preferpos, Queue *preferneg, Queue *ignore, Queue *conflict, Queue *fileprovides, int debug, int options) +{ + Expander *xp; + int i, j; + Id id, id2; + const char *str; + Queue q; + + xp = calloc(sizeof(Expander), 1); + xp->pool = pool; + xp->debug = debug; + xp->ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : 0; + xp->ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : 0; + xp->userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : 0; + xp->usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : 0; + xp->dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : 0; + xp->dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : 0; + + queue_init(&xp->preferposq); + for (i = 0; i < preferpos->count; i++) + { + id = preferpos->elements[i]; + queue_push(&xp->preferposq, id); + MAPEXP(&xp->preferpos, id); + MAPSET(&xp->preferpos, id); + if ((str = strchr(pool_id2str(pool, id), ':')) != 0) + { + id = str2id_dup(pool, str + 1); + MAPEXP(&xp->preferposx, id); + MAPSET(&xp->preferposx, id); + } + } + for (i = 0; i < preferneg->count; i++) + { + id = preferneg->elements[i]; + MAPEXP(&xp->preferneg, id); + MAPSET(&xp->preferneg, id); + if ((str = strchr(pool_id2str(pool, id), ':')) != 0) + { + id = str2id_dup(pool, str + 1); + MAPEXP(&xp->prefernegx, id); + MAPSET(&xp->prefernegx, id); + } + } + + for (i = 0; i < ignore->count; i++) + { + id = ignore->elements[i]; + MAPEXP(&xp->ignored, id); + MAPSET(&xp->ignored, id); + if ((str = strchr(pool_id2str(pool, id), ':')) != 0) + { + id = str2id_dup(pool, str + 1); + MAPEXP(&xp->ignoredx, id); + MAPSET(&xp->ignoredx, id); + } + } + + queue_init(&xp->conflictsq); + for (i = 0; i < conflict->count; i += 2) + { + id = conflict->elements[i]; + id2 = conflict->elements[i + 1]; + queue_push2(&xp->conflictsq, id, id2); + MAPEXP(&xp->conflicts, id); + MAPSET(&xp->conflicts, id); + MAPEXP(&xp->conflicts, id2); + MAPSET(&xp->conflicts, id2); + } + + if (fileprovides->count) + xp->havefileprovides = 1; + queue_init(&q); + for (i = 0; i < fileprovides->count; i++) + { + Id p, pp; + id = fileprovides->elements[i]; + int havenew = 0; + + /* XXX: this modifies the pool, which is somewhat unclean! */ + /* get old providers */ + queue_empty(&q); + FOR_PROVIDES(p, pp, id) + queue_push(&q, p); + for (j = i + 1; j < fileprovides->count && (id2 = fileprovides->elements[j]) != 0; j++) { - queue_push(out, cerrors.elements[i]); - queue_push(out, cerrors.elements[i + 1]); - queue_push(out, cerrors.elements[i + 2]); - i += 3; - while (cerrors.elements[i]) + FOR_PROVIDES(p, pp, id2) { - queue_push(out, cerrors.elements[i]); - i++; + int k; + if (pool->solvables[p].name != id2) + continue; /* match name only */ + /* insert sorted */ + for (k = 0; ; k++) + { + if (k == q.count || q.elements[k] > p) + { + queue_insert(&q, k, p); + havenew = 1; + break; + } + if (q.elements[k] == p) + break; + } } - queue_push(out, 0); - i++; - nerrors++; } + if (havenew) + pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q); + i = j; } - else + queue_free(&q); + return xp; +} + +static void +expander_free(Expander *xp) +{ + map_free(&xp->ignored); + map_free(&xp->ignoredx); + queue_free(&xp->preferposq); + map_free(&xp->preferpos); + map_free(&xp->preferposx); + map_free(&xp->preferneg); + map_free(&xp->prefernegx); + queue_free(&xp->conflictsq); + map_free(&xp->conflicts); + solv_free(xp->debugstr); + solv_free(xp); +} + + + +static void +set_disttype(Pool *pool, int disttype) +{ + pool_setdisttype(pool, disttype); +#ifdef POOL_FLAG_HAVEDISTEPOCH + /* make newer mandriva work, hopefully there are no ill effects... */ + pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0); +#endif +} + +static void +set_disttype_from_location(Pool *pool, Solvable *so) +{ + unsigned int medianr; + const char *s = solvable_get_location(so, &medianr); + int disttype = -1; + int sl; + if (!s) + return; + sl = strlen(s); + if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm")) + disttype = DISTTYPE_RPM; +#ifdef DISTTYPE_DEB + if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb")) + disttype = DISTTYPE_DEB; +#endif +#ifdef DISTTYPE_ARCH + if (disttype < 0 && sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst"))) + disttype = DISTTYPE_ARCH; +#endif + if (disttype >= 0 && pool->disttype != disttype) + set_disttype(pool, disttype); +} + +static inline const char * +solvid2name(Pool *pool, Id p) +{ + return pool_id2str(pool, pool->solvables[p].name); +} + +#define ISNOARCH(arch) (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY) + +static int +has_keyname(Repo *repo, Id keyname) +{ + Repodata *data; + int rdid; + FOR_REPODATAS(repo, rdid, data) + if (repodata_has_keyname(data, keyname)) + return 1; + return 0; +} + +static inline int +match_modules_req(Pool *pool, Id id) +{ + const char *dep = pool_id2str(pool, id); + Id *modules; + if (strncmp(dep, "platform", 8) == 0 && (dep[8] == 0 || dep[8] == '-')) + return 1; + for (modules = pool->appdata; *modules; modules++) + { + const char *name, *rname; + if (*modules == id) + return 1; + name = pool_id2str(pool, *modules); + if ((rname = strrchr(name, '-')) == 0 || rname == name) + continue; + if (!strncmp(dep, rname, rname - name) && dep[rname - name] == 0) + return 1; + } + return 0; +} + +static void +create_module_map(Repo *repo, Map *modulemap, Queue *modulemapq) +{ + Pool *pool = repo->pool; + Id *modules = pool->appdata; + int i, have_moduleinfo = 0; + Id id, p, *pp; + Solvable *s; + + if (!modulemap->size) + map_grow(modulemap, pool->ss.nstrings); + if (!modules) + return; + if (!*modules) + { + map_setall(modulemap); + return; + } + /* clear old bits */ + if (modulemapq->count) + { + for (i = 0; i < modulemapq->count; i++) + MAPCLR(modulemap, modulemapq->elements[i]); + queue_empty(modulemapq); + } + for (modules = pool->appdata; *modules; modules++) + MAPSET(modulemap, *modules); + /* look for module information stored in "buildservice:modules" solvables */ + FOR_REPO_SOLVABLES(repo, p, s) + { + if (s->name != buildservice_modules || s->arch != ARCH_SRC) + continue; + have_moduleinfo = 1; + if (s->evr >= 1 && s->evr < pool->ss.nstrings && MAPTST(modulemap, s->evr)) + { + queue_push(modulemapq, s->evr); /* directly addressed */ + continue; + } + id = s->repo->idarraydata[s->provides]; + if (id < 1 || id >= pool->ss.nstrings || !MAPTST(modulemap, id)) + continue; /* not what we're looking for */ + for (pp = s->repo->idarraydata + s->requires; (id = *pp) != 0; pp++) + { + /* check if the dep is fulfilled by any module in the list */ + if (id < 1 || id >= pool->ss.nstrings) + break; /* hey! */ + if (!MAPTST(modulemap, id) && !match_modules_req(pool, id)) + break; /* could not fulfil requires */ + } + if (id) + continue; /* could not fulfil one of the requires, ignore module */ + queue_push(modulemapq, s->evr); + } + if (!have_moduleinfo) { - if (todo.count) - { - fprintf(stderr, "Internal expansion error!\n"); - queue_empty(out); - queue_push(out, ERROR_NOPROVIDER); - queue_push(out, 0); - queue_push(out, 0); - } + /* old style repo with no moduleinfo at all. simple use the unexpanded ids */ + for (modules = pool->appdata; *modules; modules++) + queue_push(modulemapq, *modules); + return; } - queue_free(&todo); - queue_free(&qq); - queue_free(&errors); - queue_free(&cerrors); - queue_free(&posfoundq); - return nerrors; + for (modules = pool->appdata; *modules; modules++) + MAPCLR(modulemap, *modules); + for (i = 0; i < modulemapq->count; i++) + MAPSET(modulemap, modulemapq->elements[i]); } -static void -set_disttype(Pool *pool, int disttype) +static int +in_module_map(Pool *pool, Map *modulemap, Queue *modules) { - pool_setdisttype(pool, disttype); -#ifdef POOL_FLAG_HAVEDISTEPOCH - /* make newer mandriva work, hopefully there are no ill effects... */ - pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0); -#endif + int i; + for (i = 0; i < modules->count; i++) + { + Id id = modules->elements[i]; + if (id > 1 && id < pool->ss.nstrings && MAPTST(modulemap, id)) + return 1; + } + return 0; } -static void -set_disttype_from_location(Pool *pool, Solvable *so) -{ - unsigned int medianr; - const char *s = solvable_get_location(so, &medianr); - int disttype = -1; - int sl; - if (!s) - return; - sl = strlen(s); - if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm")) - disttype = DISTTYPE_RPM; -#ifdef DISTTYPE_DEB - if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb")) - disttype = DISTTYPE_DEB; -#endif -#ifdef DISTTYPE_ARCH - if (disttype < 0 && sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz"))) - disttype = DISTTYPE_ARCH; -#endif - if (disttype >= 0 && pool->disttype != disttype) - set_disttype(pool, disttype); -} -void -create_considered(Pool *pool, Repo *repoonly, Map *considered) +static void +create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepos) { Id p, pb,*best; Solvable *s, *sb; @@ -1278,41 +2887,70 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered) Repo *repo; int olddisttype = -1; int dodrepo; + int mayhave_modules; + Queue modules; + Map modulemap; + Queue modulemapq; + int modulemap_uptodate; map_init(considered, pool->nsolvables); best = solv_calloc(sizeof(Id), pool->ss.nstrings); + queue_init(&modules); + map_init(&modulemap, 0); + queue_init(&modulemapq); FOR_REPOS(ridx, repo) { if (repoonly && repo != repoonly) continue; dodrepo = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl) != 0; + mayhave_modules = has_keyname(repo, buildservice_modules) ? 1 : 0; + modulemap_uptodate = 0; FOR_REPO_SOLVABLES(repo, p, s) { + int inmodule = 0; if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) continue; pb = best[s->name]; - if (pb) + sb = pb ? pool->solvables + pb : 0; + if (mayhave_modules) { - sb = pool->solvables + pb; - if (s->repo != sb->repo) - continue; /* first repo wins */ - if (s->arch != sb->arch) + solvable_lookup_idarray(s, buildservice_modules, &modules); + inmodule = modules.count ? 1 : 0; + if (inmodule) { - int r; - if (s->arch == ARCH_NOARCH || s->arch == ARCH_ALL || s->arch == ARCH_ANY) - continue; - if (sb->arch != ARCH_NOARCH && sb->arch != ARCH_ALL && sb->arch != ARCH_ANY) + if (!modulemap_uptodate) { - /* the strcmp is kind of silly, but works for most archs */ - r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch)); - if (r >= 0) - continue; + create_module_map(repo, &modulemap, &modulemapq); + modulemap_uptodate = 1; } + if (!in_module_map(pool, &modulemap, &modules)) + continue; /* nope, ignore package */ + } + } + if (unorderedrepos && sb && s->repo->priority != sb->repo->priority) + { + if (s->repo->priority < sb->repo->priority) + continue; /* lower prio, ignore */ + } + else if (sb) + { + int sbinmodule = 0; + /* we already have that name. decide which one to take */ + if (!unorderedrepos && s->repo != sb->repo) + continue; /* first repo wins */ + + if (s->repo == sb->repo && mayhave_modules) + sbinmodule = solvable_lookup_type(sb, buildservice_modules) ? 1 : 0; + + if (inmodule != sbinmodule) + { + if (inmodule < sbinmodule) + continue; } else if (s->evr != sb->evr) { - /* same repo, check versions */ + /* check versions */ int r; if (olddisttype < 0) { @@ -1320,16 +2958,27 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered) set_disttype_from_location(pool, s); } r = pool_evrcmp(pool, sb->evr, s->evr, EVRCMP_COMPARE); - if (r > 0) + if (r == 0) + r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr)); + if (r >= 0) + continue; + } + else if (s->arch != sb->arch) + { + /* same versions, check arch */ + if (ISNOARCH(sb->arch) && !ISNOARCH(s->arch)) continue; - else if (r == 0) + if (ISNOARCH(sb->arch) || !ISNOARCH(s->arch)) { - r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr)); + int r; + /* the strcmp is kind of silly, but works for most archs */ + r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch)); if (r >= 0) continue; } } } + if (dodrepo) { /* we only consider dod packages */ @@ -1342,7 +2991,7 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered) best[s->name] = p; MAPSET(considered, p); } - /* dodrepos have a second pass: replace dod entries with downloaded ones */ + /* dodrepos have a second pass: replace dod entries with identical downloaded ones */ if (dodrepo) { const char *bsid; @@ -1366,15 +3015,18 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered) } } solv_free(best); + queue_free(&modules); + map_free(&modulemap); + queue_free(&modulemapq); if (olddisttype >= 0 && pool->disttype != olddisttype) set_disttype(pool, olddisttype); } struct metaline { - char *l; - int lastoff; - int nslash; - int killed; + char *l; /* pointer to line */ + int lastoff; /* line offset of last path element */ + int nslash; /* number of slashes */ + int killed; /* 1: line has been killed. 2: because of a cycle package */ }; static int metacmp(const void *ap, const void *bp) @@ -1396,6 +3048,87 @@ static int metacmp(const void *ap, const void *bp) return a - b; } +static char * +slurp(FILE *fp, int *lenp) +{ + int l, ll; + char *buf = 0; + int bufl = 0; + + for (l = 0; ; l += ll) + { + if (bufl - l < 4096) + { + bufl += 4096; + if (bufl < 0) + { + buf = solv_free(buf); + l = 0; + break; + } + buf = solv_realloc(buf, bufl); + } + ll = fread(buf + l, 1, bufl - l, fp); + if (ll < 0) + { + buf = solv_free(buf); + l = 0; + break; + } + if (ll == 0) + { + buf[l] = 0; /* always zero-terminate */ + break; + } + } + if (lenp) + *lenp = l; + return buf; +} + + +Id +repo_add_obsbinlnk(Repo *repo, const char *path, int flags) +{ + Repodata *data; + FILE *fp; + char *buf; + int len; + SV *sv; + unsigned char *src; + STRLEN srcl; + Id p; + + if ((fp = fopen(path, "r")) == 0) + return 0; + buf = slurp(fp, &len); + fclose(fp); + if (!buf || len <= 0) + return 0; + src = (unsigned char *)buf; + srcl = len; + sv = 0; + if (srcl >= 7 && src[0] == 'p' && src[1] == 's' && src[2] == 't' && src[3] == '0' && (src[4] & 1) == 1 && src[4] >= 5) { + src += 6; + srcl -= 6; + sv = retrieve(&src, &srcl, 0); + } + free(buf); + if (!sv) + return 0; + if (SvTYPE(sv) != SVt_PVHV) + { + SvREFCNT_dec(sv); + return 0; + } + data = repo_add_repodata(repo, flags); + p = data2pkg(repo, data, (HV *)sv, 0); + SvREFCNT_dec(sv); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return p; +} + #ifndef REPO_NO_LOCATION # define REPO_NO_LOCATION 0 #endif @@ -1412,10 +3145,21 @@ repodata_addbin(Repodata *data, char *prefix, char *s, int sl, char *sid) path = solv_dupjoin(prefix, "/", s); if (sl >= 4 && !strcmp(s + sl - 4, ".rpm")) p = repo_add_rpm(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|RPM_ADD_WITH_PKGID|RPM_ADD_NO_FILELIST|RPM_ADD_NO_RPMLIBREQS); +#if defined(LIBSOLVEXT_FEATURE_DEBIAN) else if (sl >= 4 && !strcmp(s + sl - 4, ".deb")) p = repo_add_deb(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|DEBS_ADD_WITH_PKGID); -#ifdef ARCH_ADD_WITH_PKGID - else if (sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz"))) +#endif + else if (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk")) + { + p = repo_add_obsbinlnk(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION); + /* do not overwrite location from obsbinlnk file */ + solv_free(path); + if (p) + repodata_set_str(data, p, buildservice_id, sid); + return p; + } +#if defined(LIBSOLVEXT_FEATURE_ARCHREPO) && defined(ARCH_ADD_WITH_PKGID) + else if (sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst"))) p = repo_add_arch_pkg(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|ARCH_ADD_WITH_PKGID); #endif solv_free(path); @@ -3485,38 +5229,173 @@ printobscpioinstr(FILE *fp, int fdstore, int withmeta) printf("stats file_size %lld\n", (unsigned long long)ftell(fp)); } +static int +unifymodules_cmp(const void *ap, const void *bp, void *dp) +{ + return *(Id *)ap - *(Id *)bp; +} + +static int +missingmodules_cmp(const void *ap, const void *bp, void *dp) +{ + const Id *a = ap; + const Id *b = bp; + if (a[0] != b[0]) + return a[0] - b[0]; + if (!a[1] && b[1]) + return -1; + if (!b[1] && a[1]) + return 1; + return a[1] - b[1]; +} + +static int +is_dod_package(Solvable *s) +{ + const char *str = solvable_lookup_str(s, buildservice_id); + return str && !strcmp(str, "dod") ? 1 : 0; +} + +static Solvable * +find_corresponding_dod(Solvable *s) +{ + Repo *repo = s->repo; + Id p2; + Solvable *s2; + + if (!repo) + return 0; + FOR_REPO_SOLVABLES(repo, p2, s2) + { + if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch && s != s2 && is_dod_package(s2)) + return s2; + } + return 0; +} + +struct scc_data { + Id *edata; + Id *vedge; + Queue *sccs; + int *stack; + int nstack; + int *low; + int idx; +}; + +static void +scc_collect(struct scc_data *scc, int node) +{ + int *low = scc->low; + Id *e; + queue_push(scc->sccs, node); + low[node] = -1; + for (e = scc->edata + scc->vedge[node]; *e; e++) + if (*e != -1 && low[*e] > 0) + scc_collect(scc, *e); +} + +/* Tarjan's SCC algorithm */ +static int +scc_visit(struct scc_data *scc, int node) +{ + int l, myidx, *low = scc->low, nontrivial = 0; + Id *e; + low[node] = myidx = scc->idx++; + for (e = scc->edata + scc->vedge[node]; *e; e++) + { + if (*e == -1 || *e == node) + continue; + if (!(l = low[*e])) + l = scc_visit(scc, *e); + if (l > 0) + nontrivial = 1; + if (l > 0 && l < low[node]) + low[node] = l; + } + if (low[node] != myidx) + return low[node]; + low[node] = -1; + if (nontrivial) + { + scc_collect(scc, node); + queue_push(scc->sccs, 0); + } + return -1; +} + +static void +find_sccs(Queue *edata, Queue *vedge, Queue *sccs) +{ + struct scc_data scc; + int i; + scc.edata = edata->elements; + scc.vedge = vedge->elements; + scc.sccs = sccs; + scc.low = solv_calloc(vedge->count, sizeof(int)); + scc.idx = 1; + for (i = 1; i < vedge->count; i++) + if (!scc.edata[vedge->elements[i]]) + scc.low[i] = -1; + for (i = 1; i < vedge->count; i++) + if (!scc.low[i]) + scc_visit(&scc, i); + solv_free(scc.low); +} + + MODULE = BSSolv PACKAGE = BSSolv void depsort(HV *deps, SV *mapp, SV *cycp, ...) + ALIAS: + depsort2 = 1 PPCODE: { int i, j, k, cy, cycstart, nv; + int pkgstart = 3; SV *sv, **svp; + SV *pkg2srcp = 0; Id id, *e; Id *mark; char **names; + char **depnames; Hashtable ht; Hashval h, hh, hm; HV *mhv = 0; + HV *pkg2srchv = 0; Queue edata; Queue vedge; Queue todo; Queue cycles; + Map edgeunifymap; + int didsccs = 0; - if (items == 3) + if (ix) + { + /* called as depsort2 */ + if (items < 4) + XSRETURN_EMPTY; /* nothing to sort */ + pkgstart = 4; + pkg2srcp = cycp; + cycp = ST(3); + } + if (items == pkgstart) XSRETURN_EMPTY; /* nothing to sort */ - if (items == 4) + if (items == pkgstart + 1) { /* only one item */ - char *s = SvPV_nolen(ST(3)); + char *s = SvPV_nolen(ST(pkgstart)); EXTEND(SP, 1); sv = newSVpv(s, 0); PUSHs(sv_2mortal(sv)); XSRETURN(1); /* nothing to sort */ } + if (pkg2srcp && SvROK(pkg2srcp) && SvTYPE(SvRV(pkg2srcp)) == SVt_PVHV) + pkg2srchv = (HV *)SvRV(pkg2srcp); + if (mapp && SvROK(mapp) && SvTYPE(SvRV(mapp)) == SVt_PVHV) mhv = (HV *)SvRV(mapp); @@ -3527,9 +5406,11 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) hm = mkmask(items); ht = solv_calloc(hm + 1, sizeof(*ht)); - names = solv_calloc(items, sizeof(char *)); + names = depnames = solv_calloc(items, sizeof(char *)); + + /* create pkgname -> edge hash, store edge -> pkgname data */ nv = 1; - for (i = 3; i < items; i++) + for (i = pkgstart; i < items; i++) { char *s = SvPV_nolen(ST(i)); h = strhash(s) & hm; @@ -3547,14 +5428,40 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) names[id] = s; } + if (pkg2srchv) + { + /* redo the hash with src names instead of pkg names */ + depnames = solv_calloc(nv, sizeof(char *)); + memset(ht, 0, (hm + 1) * sizeof(*ht)); + for (i = 1; i < nv; i++) + { + char *s = names[i]; + svp = hv_fetch(pkg2srchv, s, strlen(s), 0); + if (svp) + { + char *ns = SvPV_nolen(*svp); + if (ns) + s = ns; + } + depnames[i] = s; + h = strhash(s) & hm; + hh = HASHCHAIN_START; + while ((id = ht[h]) != 0) + h = HASHCHAIN_NEXT(h, hh, hm); + ht[h] = i; + } + } + /* we now know all vertices, create edges */ queue_push(&vedge, 0); queue_push(&edata, 0); + map_init(&edgeunifymap, nv); for (i = 1; i < nv; i++) { + int edgestart = edata.count; svp = hv_fetch(deps, names[i], strlen(names[i]), 0); sv = svp ? *svp : 0; - queue_push(&vedge, edata.count); + queue_push(&vedge, edgestart); if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) { AV *av = (AV *)SvRV(sv); @@ -3586,20 +5493,35 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) hh = HASHCHAIN_START; while ((id = ht[h]) != 0) { - if (!strcmp(names[id], s)) - break; + if (!strcmp(depnames[id], s)) + { + if (id != i && !MAPTST(&edgeunifymap, id)) + { + MAPSET(&edgeunifymap, id); + queue_push(&edata, id); + } + if (names == depnames) + break; /* no other entry with same name */ + } h = HASHCHAIN_NEXT(h, hh, hm); } - if (!id) - continue; /* not known, ignore */ - if (id == i) - continue; /* no self edge */ - queue_push(&edata, id); } } - queue_push(&edata, 0); + for (j = edgestart; j < edata.count; j++) + { +#ifdef MAPCLR_AT + MAPCLR_AT(&edgeunifymap, edata.elements[j]); +#else + MAPCLR(&edgeunifymap, edata.elements[j]); +#endif + } + queue_push(&edata, 0); /* terminate edge array */ } + /* free no longer needed stuff */ + map_free(&edgeunifymap); solv_free(ht); + if (depnames != names) + depnames = solv_free(depnames); if (0) { @@ -3659,6 +5581,13 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) continue; } /* oh no, we found a cycle, record and break it */ + if (depsortsccs && !didsccs && cycp) + { + /* use Tarjan's SCC algorithm */ + find_sccs(&edata, &vedge, &cycles); + queue_push(&cycles, 0); + didsccs = cycles.count; + } cy = cycles.count; for (j = todo.count - 1; j >= 0; j--) if (todo.elements[j] == -i) @@ -3694,7 +5623,10 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) todo.count = cycstart + 1; } - /* recored cycles */ + if (didsccs && depsortsccs != 2) + queue_truncate(&cycles, didsccs - 1); + + /* record cycles */ if (cycles.count && cycp && SvROK(cycp) && SvTYPE(SvRV(cycp)) == SVt_PVAV) { AV *av = (AV *)SvRV(cycp); @@ -3719,6 +5651,27 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...) solv_free(names); } +int +setdepsortsccs(int flag) + CODE: + depsortsccs = flag; + RETVAL = flag; + OUTPUT: + RETVAL + +int +setgenmetaalgo(int algo) + CODE: + if (algo < 0) + algo = 1; + if (algo > 1) + croak("BSSolv::setgenmetaalgo: unsupported algo %d\n", algo); + genmetaalgo = algo; + RETVAL = algo; + OUTPUT: + RETVAL + + void gen_meta(AV *subp, ...) PPCODE: @@ -3804,7 +5757,7 @@ gen_meta(AV *subp, ...) } if (cycle) { - lp->killed = 1; + lp->killed = 1; /* killed because line includes a subpackage */ if (cycle > 1) /* ignore self cycles */ queue_push(&cycles, i); } @@ -3820,9 +5773,9 @@ gen_meta(AV *subp, ...) char *cycledata = 0; int cycledatalen = 0; + /* create hash of cycle packages */ cycledata = solv_extend(cycledata, cycledatalen, 1, 1, 255); - cycledata[0] = 0; - cycledatalen += 1; + cycledata[cycledatalen++] = 0; hm = mkmask(cycles.count); ht = solv_calloc(hm + 1, sizeof(*ht)); for (i = 0; i < cycles.count; i++) @@ -3840,18 +5793,23 @@ gen_meta(AV *subp, ...) break; h = HASHCHAIN_NEXT(h, hh, hm); } - if (id) - continue; - cycledata = solv_extend(cycledata, cycledatalen, strlen(s) + 1, 1, 255); - ht[h] = cycledatalen; - strcpy(cycledata + cycledatalen, s); - cycledatalen += strlen(s) + 1; + if (!id) + { + int l = strlen(s); + cycledata = solv_extend(cycledata, cycledatalen, l + 1, 1, 255); + ht[h] = cycledatalen; /* point to name */ + strcpy(cycledata + cycledatalen, s); + cycledatalen += l + 1; + } if (se) *se = '/'; } + for (i = 0, lp = lines; i < nlines; i++, lp++) { - if (lp->killed || !lp->nslash) + if (!lp->nslash) + continue; + if (lp->killed && genmetaalgo == 0) continue; lo = strchr(lp->l + 34, '/') + 1; for (s2 = lo; *s2; s2++) @@ -3869,12 +5827,12 @@ gen_meta(AV *subp, ...) *s2 = '/'; if (id) { - lp->killed = 1; + lp->killed = 2; /* killed because it containes a cycle package */ break; } lo = s2 + 1; } - if (lp->killed) + if (lp->killed == 2) continue; h = strhash(lo) & hm; hh = HASHCHAIN_START; @@ -3885,14 +5843,12 @@ gen_meta(AV *subp, ...) h = HASHCHAIN_NEXT(h, hh, hm); } if (id) - { - lp->killed = 1; - } + lp->killed = 2; /* killed because it containes a cycle package */ } solv_free(ht); cycledata = solv_free(cycledata); - queue_free(&cycles); } + queue_free(&cycles); /* cycles are pruned, now sort array */ if (nlines > 1) @@ -3903,7 +5859,10 @@ gen_meta(AV *subp, ...) for (i = 0, lp = lines; i < nlines; i++, lp++) { if (lp->killed) - continue; + { + if (genmetaalgo == 0 || lp->killed != 2) + continue; + } s = lp->l; h = strnhash(s, 10); h = strhash_cont(s + lp->lastoff, h) & hm; @@ -3915,6 +5874,13 @@ gen_meta(AV *subp, ...) break; h = HASHCHAIN_NEXT(h, hh, hm); } + if (id && genmetaalgo == 1 && lp->killed == 2) + { + /* also kill old line of same level */ + struct metaline *lp2 = lines + (id - 1); + if (!lp2->killed && lp2->nslash == lp->nslash) + lp2->killed = 1; + } if (id) lp->killed = 1; else @@ -3937,6 +5903,66 @@ gen_meta(AV *subp, ...) solv_free(lines); } +void +add_meta(AV *new_meta, SV *sv, const char *bin, const char *packid = 0) + PPCODE: + { + const char *p, *np; + char *buf; + size_t l, bufl, binl, packidl; + int first = 1; + if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) { + AV *av = (AV *)SvRV(sv); + SV **svp = av_fetch(av, 0, 0); + sv = svp ? *svp : 0; + } + if (!sv) + XSRETURN_EMPTY; + p = SvPV_nolen(sv); + binl = strlen(bin); + bufl = binl + 256; + buf = malloc(bufl); + if (!buf) { + croak("out of mem\n"); + XSRETURN_EMPTY; + } + packidl = packid ? strlen(packid) : 0; + for (;;) { + np = strchr(p, '\n'); + l = np ? np - p : strlen(p); + if (l > 34) { + if (l + binl + 1 + 1 > bufl) { + bufl = l + binl + 256; + buf = realloc(buf, bufl); + if (!buf) { + croak("out of mem\n"); + XSRETURN_EMPTY; + } + } + strncpy(buf, p, 34); + strcpy(buf + 34, bin); + buf[34 + binl] = '/'; + strncpy(buf + 34 + binl + 1, p + 34, l - 34); + l += binl + 1; + buf[l] = 0; + if (first) { + if (packidl && l > packidl + 1 && buf[l - packidl - 1] == '/' && !strcmp(buf + l - packidl, packid)) { + free(buf); + XSRETURN_EMPTY; + } + l = 34 + binl; + buf[l] = 0; + first = 0; + } + av_push(new_meta, newSVpvn(buf, l)); + } + if (!np) + break; + p = np + 1; + } + free(buf); + } + SV * thawcache(SV *sv) CODE: @@ -4266,6 +6292,9 @@ new(char *packname = "BSSolv::pool") buildservice_dodurl = pool_str2id(pool, "buildservice:dodurl", 1); expander_directdepsend = pool_str2id(pool, "-directdepsend--", 1); buildservice_dodcookie = pool_str2id(pool, "buildservice:dodcookie", 1); + buildservice_dodresources = pool_str2id(pool, "buildservice:dodresources", 1); + buildservice_annotation = pool_str2id(pool, "buildservice:annotation", 1); + buildservice_modules = pool_str2id(pool, "buildservice:modules", 1); pool_freeidhashes(pool); RETVAL = pool; } @@ -4342,9 +6371,11 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...) continue; if (strcmp(s + sl - 4, ".rpm") && strcmp(s + sl - 4, ".deb") + && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk")) #ifdef ARCH_ADD_WITH_PKGID && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz")) && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz")) + && (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst")) #endif ) continue; @@ -4364,14 +6395,16 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...) RETVAL BSSolv::repo -repofromdata(BSSolv::pool pool, char *name, HV *rhv) +repofromdata(BSSolv::pool pool, char *name, SV *rv) CODE: { Repo *repo; Repodata *data; + if (!SvROK(rv) || (SvTYPE(SvRV(rv)) != SVt_PVHV && SvTYPE(SvRV(rv)) != SVt_PVAV)) + croak("BSSolv::pool::repofromdata: rv is not a HASH or ARRAY reference"); repo = repo_create(pool, name); data = repo_add_repodata(repo, 0); - data2solvables(repo, data, rhv); + data2solvables(repo, data, SvRV(rv), 0); if (name && !strcmp(name, "/external/")) repodata_set_void(data, SOLVID_META, buildservice_external); repo_internalize(repo); @@ -4381,7 +6414,7 @@ repofromdata(BSSolv::pool pool, char *name, HV *rhv) RETVAL void -createwhatprovides(BSSolv::pool pool) +createwhatprovides(BSSolv::pool pool, int unorderedrepos = 0) CODE: if (pool->considered) { @@ -4389,7 +6422,7 @@ createwhatprovides(BSSolv::pool pool) solv_free(pool->considered); } pool->considered = solv_calloc(sizeof(Map), 1); - create_considered(pool, 0, pool->considered); + create_considered(pool, 0, pool->considered, unorderedrepos); pool_createwhatprovides(pool); void @@ -4402,7 +6435,7 @@ whatprovides(BSSolv::pool pool, char *str) PPCODE: { Id p, pp, id; - id = dep2id(pool, str); + id = testcase_str2dep(pool, str); if (id) FOR_PROVIDES(p, pp, id) XPUSHs(sv_2mortal(newSViv((IV)p))); @@ -4415,7 +6448,7 @@ whatrequires(BSSolv::pool pool, char *str) Id p, id; Id *pp; Solvable *s; - id = dep2id(pool, str); + id = testcase_str2dep(pool, str); if (id) { for (p = 2; p < pool->nsolvables; p++) @@ -4470,6 +6503,20 @@ pkg2name(BSSolv::pool pool, int p) RETVAL const char * +pkg2evr(BSSolv::pool pool, int p) + CODE: + RETVAL = pool_id2str(pool, pool->solvables[p].evr); + OUTPUT: + RETVAL + +const char * +pkg2arch(BSSolv::pool pool, int p) + CODE: + RETVAL = pool_id2str(pool, pool->solvables[p].arch); + OUTPUT: + RETVAL + +const char * pkg2srcname(BSSolv::pool pool, int p) CODE: if (solvable_lookup_void(pool->solvables + p, SOLVABLE_SOURCENAME)) @@ -4555,6 +6602,33 @@ pkg2checksum(BSSolv::pool pool, int p) RETVAL int +pkg2inmodule(BSSolv::pool pool, int p) + CODE: + RETVAL = solvable_lookup_type(pool->solvables + p, buildservice_modules) != 0; + OUTPUT: + RETVAL + +void +pkg2modules(BSSolv::pool pool, int p) + PPCODE: + { + Solvable *s = pool->solvables + p; + Queue modules; + int i; + queue_init(&modules); + solvable_lookup_idarray(s, buildservice_modules, &modules); + if (!modules.count && !is_dod_package(s)) + { + Solvable *s2 = find_corresponding_dod(s); + if (s2) + solvable_lookup_idarray(s2, buildservice_modules, &modules); + } + for (i = 0; i < modules.count; i++) + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules.elements[i]), 0))); + queue_free(&modules); + } + +int verifypkgchecksum(BSSolv::pool pool, int p, char *path) CODE: { @@ -4639,10 +6713,34 @@ pkg2data(BSSolv::pool pool, int p) ss = solvable_lookup_str(s, buildservice_id); if (ss) (void)hv_store(RETVAL, "id", 2, newSVpv(ss, 0), 0); + ss = solvable_lookup_str(s, buildservice_annotation); + if (ss) + (void)hv_store(RETVAL, "annotation", 10, newSVpv(ss, 0), 0); + if (solvable_lookup_type(s, buildservice_modules)) + { + Queue modules; + int i; + queue_init(&modules); + solvable_lookup_idarray(s, buildservice_modules, &modules); + if (modules.count) + { + AV *av = newAV(); + for (i = 0; i < modules.count; i++) + av_push(av, newSVpv(pool_id2str(pool, modules.elements[i]), 0)); + (void)hv_store(RETVAL, "modules", 7, newRV_noinc((SV*)av), 0); + } + } } OUTPUT: RETVAL +const char * +pkg2annotation(BSSolv::pool pool, int p) + CODE: + RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_annotation); + OUTPUT: + RETVAL + void repos(BSSolv::pool pool) PPCODE: @@ -4761,6 +6859,32 @@ preparehashes(BSSolv::pool pool, char *prp, SV *gctxprpnotreadysv = 0) } void +setmodules(BSSolv::pool pool, AV *modulesav) + CODE: + { + SSize_t i, n = av_len(modulesav); + pool->appdata = solv_free(pool->appdata); + if (n >= 0 && n < 1000000) + { + Id *modules = pool->appdata = solv_calloc(n + 2, sizeof(Id)); + for (i = 0; i <= n; i++) + modules[i] = pool_str2id(pool, avlookupstr(modulesav, i), 1); + modules[i] = 0; + } + } + +void +getmodules(BSSolv::pool pool) + PPCODE: + if (pool->appdata) + { + Id *modules = pool->appdata; + int i; + for (i = 0; modules[i]; i++) + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules[i]), 0))); + } + +void DESTROY(BSSolv::pool pool) CODE: if (pool->considered) @@ -4768,6 +6892,7 @@ DESTROY(BSSolv::pool pool) map_free(pool->considered); pool->considered = solv_free(pool->considered); } + pool->appdata = solv_free(pool->appdata); pool_free(pool); @@ -4776,6 +6901,24 @@ DESTROY(BSSolv::pool pool) MODULE = BSSolv PACKAGE = BSSolv::repo PREFIX = repo void +freerepo(BSSolv::repo repo) + CODE: + { + repo_free(repo, 1); + } + +void +allpackages(BSSolv::repo repo) + PPCODE: + { + Id p; + Solvable *s; + EXTEND(SP, repo->nsolvables); + FOR_REPO_SOLVABLES(repo, p, s) + PUSHs(sv_2mortal(newSViv(p))); + } + +void pkgnames(BSSolv::repo repo) PPCODE: { @@ -4783,8 +6926,8 @@ pkgnames(BSSolv::repo repo) Id p; Solvable *s; Map c; - - create_considered(pool, repo, &c); + + create_considered(pool, repo, &c, 0); EXTEND(SP, 2 * repo->nsolvables); FOR_REPO_SOLVABLES(repo, p, s) { @@ -4807,7 +6950,7 @@ pkgpaths(BSSolv::repo repo) const char *str; unsigned int medianr; - create_considered(pool, repo, &c); + create_considered(pool, repo, &c, 0); EXTEND(SP, 2 * repo->nsolvables); FOR_REPO_SOLVABLES(repo, p, s) { @@ -4923,7 +7066,7 @@ updatefrombins(BSSolv::repo repo, char *dir, ...) continue; h = strhash(str) & hm; hh = HASHCHAIN_START; - while ((id = ht[h]) != 0) + while (ht[h]) h = HASHCHAIN_NEXT(h, hh, hm); ht[h] = p; } @@ -4939,11 +7082,14 @@ updatefrombins(BSSolv::repo repo, char *dir, ...) continue; if (strcmp(s + sl - 4, ".rpm") && strcmp(s + sl - 4, ".deb") + && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk")) #ifdef ARCH_ADD_WITH_PKGID && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz")) && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz")) + && (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst")) #endif ) + continue; if (sl > 10 && !strcmp(s + sl - 10, ".patch.rpm")) continue; if (sl > 10 && !strcmp(s + sl - 10, ".nosrc.rpm")) @@ -4957,12 +7103,12 @@ updatefrombins(BSSolv::repo repo, char *dir, ...) const char *str = solvable_lookup_str(pool->solvables + id, buildservice_id); if (!strcmp(str, sid)) { - /* check location */ + /* check location (unless it's a obsbinlnk where the location comes from the content) */ unsigned int medianr; str = solvable_get_location(pool->solvables + id, &medianr); if (str[0] == '.' && str[1] == '/') str += 2; - if (!strcmp(str, s)) + if (!strcmp(str, s) || (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk"))) break; } h = HASHCHAIN_NEXT(h, hh, hm); @@ -5020,6 +7166,139 @@ updatefrombins(BSSolv::repo repo, char *dir, ...) OUTPUT: RETVAL +void +modulesfrombins(BSSolv::repo repo, ...) + PPCODE: + { + Pool *pool = repo->pool; + Hashtable ht; + Hashval h, hh, hm; + Queue modules; + Queue collectedmodules; + Id p, lastid; + Solvable *s; + int i, j; + + queue_init(&collectedmodules); + queue_init(&modules); + hm = mkmask(2 * repo->nsolvables + 1); + ht = solv_calloc(hm + 1, sizeof(*ht)); + FOR_REPO_SOLVABLES(repo, p, s) + { + const char *bsid = solvable_lookup_str(s, buildservice_id); + if (!bsid) + continue; + if (!strcmp(bsid, "dod")) + h = s->name + s->evr * 37 + s->arch * 129; + else + h = strhash(bsid); + h &= hm; + hh = HASHCHAIN_START; + while (ht[h]) + h = HASHCHAIN_NEXT(h, hh, hm); + ht[h] = p; + } + + for (i = 1; i + 1 < items; i += 2) + { + const char *bsid = SvPV_nolen(ST(i + 1)); + h = strhash(bsid) & hm; + hh = HASHCHAIN_START; + while ((p = ht[h]) != 0) + { + const char *bsid2 = solvable_lookup_str(pool->solvables + p, buildservice_id); + if (!strcmp(bsid, bsid2)) + break; + h = HASHCHAIN_NEXT(h, hh, hm); + } + if (!p) + continue; + s = pool->solvables + p; + h = (s->name + s->evr * 37 + s->arch * 129) & hm; + hh = HASHCHAIN_START; + while ((p = ht[h]) != 0) + { + Solvable *s2 = pool->solvables + p; + if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch) + { + lastid = collectedmodules.count ? collectedmodules.elements[collectedmodules.count - 1] : 0; + solvable_lookup_idarray(s2, buildservice_modules, &modules); + for (j = 0; j < modules.count; j++) + if (modules.elements[j] != lastid) + queue_push(&collectedmodules, modules.elements[j]); + } + h = HASHCHAIN_NEXT(h, hh, hm); + } + } + solv_free(ht); + queue_free(&modules); + /* sort and unify */ + solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0); + lastid = -1; + for (i = 0; i < collectedmodules.count; i++) + { + if (collectedmodules.elements[i] == lastid) + continue; + lastid = collectedmodules.elements[i]; + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0))); + } + queue_free(&collectedmodules); + } + +void +missingmodules(BSSolv::repo repo, ...) + PPCODE: + { + Pool *pool = repo->pool; + Id p, *pp, *modules, id, req, lastid1, lastid2; + Solvable *s; + Queue missingq; + int i, missing; + + queue_init(&missingq); + if (pool->appdata && ((Id *)pool->appdata)[0] && has_keyname(repo, buildservice_modules)) + { + FOR_REPO_SOLVABLES(repo, p, s) + { + if (s->name != buildservice_modules || s->arch != ARCH_SRC || !s->requires) + continue; + id = s->repo->idarraydata[s->provides]; + for (modules = pool->appdata; *modules; modules++) + if (id == *modules) + break; + if (!*modules) + continue; + missing = 0; + for (pp = s->repo->idarraydata + s->requires; (req = *pp) != 0; pp++) + if (!match_modules_req(pool, req)) + { + missing = 1; + queue_push2(&missingq, id, req); + } + if (!missing) /* we're good */ + queue_push2(&missingq, id, 0); + } + /* sort and unify */ + solv_sort(missingq.elements, missingq.count / 2, sizeof(Id) * 2, missingmodules_cmp, 0); + lastid1 = lastid2 = -1; + for (i = 0; i < missingq.count; i += 2) + { + if (missingq.elements[i] == lastid1 && missingq.elements[i + 1] == lastid2) + continue; + if (missingq.elements[i] != lastid1) + { + lastid1 = missingq.elements[i]; + lastid2 = missingq.elements[i + 1]; + } + if (!lastid2) + continue; + lastid2 = missingq.elements[i + 1]; + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid1), 0))); + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid2), 0))); + } + queue_free(&missingq); + } + } void getpathid(BSSolv::repo repo) @@ -5033,6 +7312,11 @@ getpathid(BSSolv::repo repo) unsigned int medianr; const char *str; str = solvable_get_location(s, &medianr); + /* We need to special case .obsbinlink here where the location + * points back into the package. We currently assume that + * the name in the full tree is always .obsbinlnk */ + if (!strncmp(str, "../", 3)) + str = pool_tmpjoin(repo->pool, pool_id2str(repo->pool, s->name), ".obsbinlnk", 0); PUSHs(sv_2mortal(newSVpv(str, 0))); str = solvable_lookup_str(s, buildservice_id); PUSHs(sv_2mortal(newSVpv(str, 0))); @@ -5068,6 +7352,21 @@ dodcookie(BSSolv::repo repo) RETVAL void +dodresources(BSSolv::repo repo) + PPCODE: + { + Pool *pool = repo->pool; + Queue dodresources; + int i; + + queue_init(&dodresources); + repo_lookup_idarray(repo, SOLVID_META, buildservice_dodresources, &dodresources); + for (i = 0; i < dodresources.count; i++) + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, dodresources.elements[i]), 0))); + queue_free(&dodresources); + } + +void updatedoddata(BSSolv::repo repo, HV *rhv = 0) CODE: { @@ -5084,28 +7383,131 @@ updatedoddata(BSSolv::repo repo, HV *rhv = 0) data = repo_add_repodata(repo, REPO_REUSE_REPODATA); repodata_unset(data, SOLVID_META, buildservice_dodurl); repodata_unset(data, SOLVID_META, buildservice_dodcookie); + repodata_unset(data, SOLVID_META, buildservice_dodresources); /* add new data */ if (rhv) - data2solvables(repo, data, rhv); + data2solvables(repo, data, (SV *)rhv, 1); repo_internalize(repo); } +void +setpriority(BSSolv::repo repo, int priority) + PPCODE: + repo->priority = priority; + +int +mayhavemodules(BSSolv::repo repo) + CODE: + RETVAL = has_keyname(repo, buildservice_modules); + OUTPUT: + RETVAL + +void +getmodules(BSSolv::repo repo) + PPCODE: + if (has_keyname(repo, buildservice_modules)) + { + Pool *pool = repo->pool; + Id p, lastid = -1; + Solvable *s; + Queue collectedmodules; + int i; + + queue_init(&collectedmodules); + FOR_REPO_SOLVABLES(repo, p, s) + if (s->name == buildservice_modules && s->arch == ARCH_SRC && s->repo->idarraydata[s->provides]) + queue_push(&collectedmodules, s->repo->idarraydata[s->provides]); + if (!collectedmodules.count) + { + Queue modules; + queue_init(&modules); + FOR_REPO_SOLVABLES(repo, p, s) + { + solvable_lookup_idarray(pool->solvables + p, buildservice_modules, &modules); + for (i = 0; i < modules.count; i++) + { + if (modules.elements[i] == lastid) + continue; + lastid = modules.elements[i]; + queue_push(&collectedmodules, modules.elements[i]); + } + } + queue_free(&modules); + } + /* sort and unify */ + solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0); + lastid = -1; + for (i = 0; i < collectedmodules.count; i++) + { + if (collectedmodules.elements[i] == lastid) + continue; + lastid = collectedmodules.elements[i]; + XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0))); + } + queue_free(&collectedmodules); + } + +void +getdodblobs(BSSolv::repo repo) + PPCODE: + { + Pool *pool = repo->pool; + int i; + Id p; + Solvable *s; + Stringpool ss; + stringpool_init_empty(&ss); + FOR_REPO_SOLVABLES(repo, p, s) + { + const char *str = solvable_lookup_str(s, buildservice_id); + unsigned int medianr; + const char *s, *se; + if (!str || strcmp(str, "dod") != 0) + continue; + s = solvable_get_location(pool->solvables + p, &medianr); + if ((s = strrchr(s, '?')) == 0) + continue; + for (++s; s; s = se ? se + 1 : 0) + { + se = strchr(s, ','); + if (se) + stringpool_strn2id(&ss, s, se - s, 1); + else + stringpool_str2id(&ss, s, 1); + } + } + for (i = 2; i < ss.nstrings; i++) + { + XPUSHs(sv_2mortal(newSVpv(stringpool_id2str(&ss, i), 0))); + } + stringpool_free(&ss); + } -MODULE = BSSolv PACKAGE = BSSolv::expander PREFIX = expander +MODULE = BSSolv PACKAGE = BSSolv::expander PREFIX = expander BSSolv::expander new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) CODE: { SV *sv, **svp; - char *str; - int i, neg; - Id id, id2; + char *str, *p; + int i; + Id id; Expander *xp; - - xp = calloc(sizeof(Expander), 1); - xp->pool = pool; + Queue preferpos; + Queue preferneg; + Queue ignore; + Queue conflict; + Queue fileprovides; + int debug = 0; + int options = 0; + + queue_init(&preferpos); + queue_init(&preferneg); + queue_init(&ignore); + queue_init(&conflict); + queue_init(&fileprovides); svp = hv_fetch(config, "prefer", 6, 0); sv = svp ? *svp : 0; if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) @@ -5120,37 +7522,10 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) str = SvPV_nolen(sv); if (!str) continue; - neg = 0; if (*str == '-') - { - neg = 1; - str++; - } - id = pool_str2id(pool, str, 1); - id2 = 0; - if ((str = strchr(str, ':')) != 0) - id2 = pool_str2id(pool, str + 1, 1); - if (neg) - { - MAPEXP(&xp->preferneg, id); - MAPSET(&xp->preferneg, id); - if (id2) - { - MAPEXP(&xp->prefernegx, id2); - MAPSET(&xp->prefernegx, id2); - } - } + queue_push(&preferneg, pool_str2id(pool, str + 1, 1)); else - { - queue_push(&xp->preferposq, id); - MAPEXP(&xp->preferpos, id); - MAPSET(&xp->preferpos, id); - if (id2) - { - MAPEXP(&xp->preferposx, id2); - MAPSET(&xp->preferposx, id2); - } - } + queue_push(&preferpos, pool_str2id(pool, str, 1)); } } svp = hv_fetch(config, "ignoreh", 7, 0); @@ -5159,7 +7534,6 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) { HV *hv = (HV *)SvRV(sv); HE *he; - hv_iterinit(hv); while ((he = hv_iternext(hv)) != 0) { @@ -5167,18 +7541,7 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) str = hv_iterkey(he, &strl); if (!str) continue; - - id = pool_str2id(pool, str, 1); - id2 = 0; - if ((str = strchr(str, ':')) != 0) - id2 = pool_str2id(pool, str + 1, 1); - MAPEXP(&xp->ignored, id); - MAPSET(&xp->ignored, id); - if (id2) - { - MAPEXP(&xp->ignoredx, id2); - MAPSET(&xp->ignoredx, id2); - } + queue_push(&ignore, pool_str2id(pool, str, 1)); } } svp = hv_fetch(config, "conflict", 8, 0); @@ -5188,9 +7551,6 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) AV *av = (AV *)SvRV(sv); for (i = 0; i <= av_len(av); i++) { - char *p; - Id id2; - svp = av_fetch(av, i, 0); if (!svp) continue; @@ -5205,46 +7565,28 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) str = p + 1; while ((p = strchr(str, ',')) != 0) { - id2 = pool_strn2id(pool, str, p - str, 1); - queue_push2(&xp->conflictsq, id, id2); - MAPEXP(&xp->conflicts, id); - MAPSET(&xp->conflicts, id); - MAPEXP(&xp->conflicts, id2); - MAPSET(&xp->conflicts, id2); + queue_push2(&conflict, id, pool_strn2id(pool, str, p - str, 1)); str = p + 1; } - id2 = pool_str2id(pool, str, 1); - queue_push2(&xp->conflictsq, id, id2); - MAPEXP(&xp->conflicts, id); - MAPSET(&xp->conflicts, id); - MAPEXP(&xp->conflicts, id2); - MAPSET(&xp->conflicts, id2); + queue_push2(&conflict, id, pool_str2id(pool, str, 1)); } } - /* XXX: this modifies the pool, which is a bit unclean! */ svp = hv_fetch(config, "fileprovides", 12, 0); sv = svp ? *svp : 0; if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV) { HV *hv = (HV *)SvRV(sv); I32 strl; - Queue q; - xp->havefileprovides = 1; hv_iterinit(hv); - queue_init(&q); while ((sv = hv_iternextsv(hv, &str, &strl)) != 0) { AV *av; - Id p, pp; - int havenew = 0; + Id id2; if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) continue; id = pool_str2id(pool, str, 1); - queue_empty(&q); - FOR_PROVIDES(p, pp, id) - queue_push(&q, p); av = (AV *)SvRV(sv); for (i = 0; i <= av_len(av); i++) { @@ -5256,44 +7598,48 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config) if (!str) continue; id2 = pool_str2id(pool, str, 0); - FOR_PROVIDES(p, pp, id2) + if (!id2) + continue; + if (id) { - int j; - for (j = 0; j < q.count; j++) - { - if (q.elements[j] == p) - break; - if (q.elements[j] > p) - { - queue_insert(&q, j, p); - havenew = 1; - break; - } - } - if (j == q.count) - { - queue_push(&q, p); - havenew = 1; - } + queue_push(&fileprovides, id); /* start name block */ + id = 0; } + queue_push(&fileprovides, id2); } - if (havenew) - pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q); + if (id == 0) + queue_push(&fileprovides, 0); /* had at least one entry, finish name block */ } - queue_free(&q); } + options |= EXPANDER_OPTION_USERECOMMENDSFORCHOICES; svp = hv_fetch(config, "expandflags:ignoreconflicts", 27, 0); sv = svp ? *svp : 0; if (sv && SvTRUE(sv)) - xp->ignoreconflicts = 1; - svp = hv_fetch(config, "expand_dbg", 10, 0); + options |= EXPANDER_OPTION_IGNORECONFLICTS; + svp = hv_fetch(config, "expandflags:dorecommends", 24, 0); sv = svp ? *svp : 0; if (sv && SvTRUE(sv)) - xp->debug = 1; - sv = get_sv("Build::expand_dbg", FALSE); + options |= EXPANDER_OPTION_DORECOMMENDS; + svp = hv_fetch(config, "expandflags:dosupplements", 25, 0); + sv = svp ? *svp : 0; if (sv && SvTRUE(sv)) - xp->debug = 1; - xp->userecommendsforchoices = 1; + options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES; + svp = hv_fetch(config, "expand_dbg", 10, 0); + sv = svp ? *svp : 0; + if (sv && SvOK(sv)) + debug = SvIV(sv); + else + { + sv = get_sv("Build::expand_dbg", FALSE); + if (sv && SvOK(sv)) + debug = SvIV(sv); + } + xp = expander_create(pool, &preferpos, &preferneg, &ignore, &conflict, &fileprovides, debug, options); + queue_free(&preferpos); + queue_free(&preferneg); + queue_free(&ignore); + queue_free(&conflict); + queue_free(&fileprovides); RETVAL = xp; } OUTPUT: @@ -5306,131 +7652,71 @@ expand(BSSolv::expander xp, ...) { Pool *pool; int i, nerrors; - Id id, who, conflbuf[16]; - Queue revertignore, in, out, confl; - int oldignoreignore = xp->ignoreignore; - int ignoreignore = 0; - Map oldignored, oldignoredx; - int ignoremapssaved = 0; - - queue_init(&revertignore); + Id id, who, indepbuf[64]; + Queue ignoreq, in, out, indep; + int directdepsend = 0; + int options = 0; + + queue_init(&ignoreq); queue_init(&in); queue_init(&out); - queue_init_buffer(&confl, conflbuf, sizeof(conflbuf)/sizeof(*conflbuf)); + queue_init_buffer(&indep, indepbuf, sizeof(indepbuf)/sizeof(*indepbuf)); pool = xp->pool; if (xp->debug) expander_dbg(xp, "expand args:"); for (i = 1; i < items; i++) { char *s = SvPV_nolen(ST(i)); + int deptype = DEPTYPE_REQUIRES; + if (xp->debug) expander_dbg(xp, " %s", s); + if (*s == '-' && s[1] == '-') + { + /* expand option */ + if (!strcmp(s, "--ignoreignore--")) + options |= EXPANDER_OPTION_IGNOREIGNORE; + else if (!strcmp(s, "--directdepsend--")) + directdepsend = 1; + else if (!strcmp(s, "--dorecommends--")) + options |= EXPANDER_OPTION_DORECOMMENDS; + else if (!strcmp(s, "--dosupplements--")) + options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES; + else if (!strcmp(s, "--ignoreconflicts--")) + options |= EXPANDER_OPTION_IGNORECONFLICTS; + continue; + } if (*s == '-') { - Id id; - if (s[1] == '-' && !strcmp(s, "--ignoreignore--")) - { - ignoreignore = 1; - continue; - } + /* ignore dependency */ id = pool_str2id(pool, s + 1, 1); - if (id == expander_directdepsend) - { - queue_push(&in, id); - continue; - } - queue_push(&revertignore, id); + queue_push(&ignoreq, id); + continue; } - else if (*s == '!') + if (*s == '!') { - Id id = dep2id(pool, s + (s[1] == '!' ? 2 : 1)); - queue_push2(&confl, id, s[1] == '!' ? 1 : 0); + deptype = DEPTYPE_CONFLICTS; + s++; + if (*s == '!') + { + deptype = DEPTYPE_OBSOLETES; + s++; + } } + id = dep2id(pool, s); + if (deptype == DEPTYPE_REQUIRES && !directdepsend) + queue_push(&in, id); else - { - Id id = dep2id(pool, s); - queue_push(&in, id); - } + queue_push2(&indep, deptype, id); } if (xp->debug) expander_dbg(xp, "\n"); - if (ignoreignore && revertignore.count) - { - /* bad: have direct ignores and project config ignores */ - oldignored = xp->ignored; - oldignoredx = xp->ignoredx; - ignoremapssaved = 1; - /* clear project config maps */ - memset(&xp->ignored, 0, sizeof(xp->ignored)); - memset(&xp->ignoredx, 0, sizeof(xp->ignoredx)); - } - - if (revertignore.count) - { - /* mix direct ignores with ignores from project config */ - int revertcnt = revertignore.count; - for (i = 0; i < revertcnt; i++) - { - const char *ss; - id = revertignore.elements[i]; - MAPEXP(&xp->ignored, id); - if (MAPTST(&xp->ignored, id)) - continue; - MAPSET(&xp->ignored, id); - queue_push(&revertignore, id); - if ((ss = strchr(pool_id2str(pool, id), ':')) != 0) - { - id = pool_str2id(pool, ss + 1, 1); - MAPEXP(&xp->ignoredx, id); - if (MAPTST(&xp->ignoredx, id)) - continue; - MAPSET(&xp->ignoredx, id); - queue_push(&revertignore, -id); - } - } - queue_deleten(&revertignore, 0, revertcnt); - } - else if (ignoreignore) - { - /* no direct ignores, disable ignore processing */ - xp->ignoreignore = 1; - } - - MAPEXP(&xp->ignored, pool->ss.nstrings); - MAPEXP(&xp->ignoredx, pool->ss.nstrings); - MAPEXP(&xp->preferpos, pool->ss.nstrings); - MAPEXP(&xp->preferposx, pool->ss.nstrings); - MAPEXP(&xp->preferneg, pool->ss.nstrings); - MAPEXP(&xp->prefernegx, pool->ss.nstrings); - MAPEXP(&xp->conflicts, pool->ss.nstrings); - - nerrors = expander_expand(xp, &in, &out, &confl); - - /* revert ignores */ - xp->ignoreignore = oldignoreignore; - if (ignoremapssaved) - { - map_free(&xp->ignored); - map_free(&xp->ignoredx); - xp->ignored = oldignored; - xp->ignoredx = oldignoredx; - } - else - { - for (i = 0; i < revertignore.count; i++) - { - id = revertignore.elements[i]; - if (id > 0) - MAPCLR(&xp->ignored, id); - else - MAPCLR(&xp->ignoredx, -id); - } - } - queue_free(&revertignore); + nerrors = expander_expand(xp, &in, &indep, &out, &ignoreq, options); queue_free(&in); - queue_free(&confl); + queue_free(&indep); + queue_free(&ignoreq); if (nerrors) { @@ -5445,19 +7731,43 @@ expand(BSSolv::expander xp, ...) id = out.elements[i + 1]; who = out.elements[i + 2]; if (who) - sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name)); + sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who)); else sv = newSVpvf("nothing provides %s", pool_dep2str(pool, id)); i += 3; } - else if (type == ERROR_CONFLICTINGPROVIDER) + else if (type == ERROR_ALLCONFLICT) { id = out.elements[i + 1]; who = out.elements[i + 2]; if (who) - sv = newSVpvf("conflict for provider of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name)); + sv = newSVpvf("%s conflicts with always true %s", solvid2name(pool, who), pool_dep2str(pool, id)); + else + sv = newSVpvf("conflict with always true %s", pool_dep2str(pool, id)); + i += 3; + } + else if (type == ERROR_CONFLICT) + { + Id who2 = out.elements[i + 2]; + who = out.elements[i + 1]; + if (!who && who2 >= 0) + sv = newSVpvf("conflicts with %s", solvid2name(pool, who2)); + else if (who2 < 0) + sv = newSVpvf("%s obsoletes %s", solvid2name(pool, who), solvid2name(pool, -who2)); + else + sv = newSVpvf("%s conflicts with %s", solvid2name(pool, who), solvid2name(pool, who2)); + i += 3; + } + else if (type == ERROR_CONFLICT2) + { + Id who2 = out.elements[i + 2]; + who = out.elements[i + 1]; + if (who2 < 0) + sv = newSVpvf("%s is obsoleted by %s", solvid2name(pool, who), solvid2name(pool, -who2)); + else if (who2 > 0) + sv = newSVpvf("%s is in conflict with %s", solvid2name(pool, who), solvid2name(pool, who2)); else - sv = newSVpvf("conflict for provider of %s", pool_dep2str(pool, id)); + sv = newSVpvf("%s is in conflict", solvid2name(pool, who)); i += 3; } else if (type == ERROR_CONFLICTINGPROVIDERS) @@ -5465,9 +7775,9 @@ expand(BSSolv::expander xp, ...) id = out.elements[i + 1]; who = out.elements[i + 2]; if (who) - sv = newSVpvf("conflict for all providers of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name)); + sv = newSVpvf("conflict for providers of %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who)); else - sv = newSVpvf("conflict for all providers of %s", pool_dep2str(pool, id)); + sv = newSVpvf("conflict for providers of %s", pool_dep2str(pool, id)); i += 3; } else if (type == ERROR_PROVIDERINFO) @@ -5475,9 +7785,9 @@ expand(BSSolv::expander xp, ...) Id who2 = out.elements[i + 2]; who = out.elements[i + 1]; if (who2 < 0) - sv = newSVpvf("(provider %s obsoletes installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name)); + sv = newSVpvf("(provider %s obsoletes %s)", solvid2name(pool, who), solvid2name(pool, -who2)); else - sv = newSVpvf("(provider %s conflicts with installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name)); + sv = newSVpvf("(provider %s conflicts with %s)", solvid2name(pool, who), solvid2name(pool, who2)); i += 3; } else if (type == ERROR_PROVIDERINFO2) @@ -5485,11 +7795,11 @@ expand(BSSolv::expander xp, ...) Id who2 = out.elements[i + 2]; who = out.elements[i + 1]; if (who2 < 0) - sv = newSVpvf("(provider %s is obsoleted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name)); + sv = newSVpvf("(provider %s is obsoleted by %s)", solvid2name(pool, who), solvid2name(pool, -who2)); else if (who2 > 0) - sv = newSVpvf("(provider %s is conflicted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name)); + sv = newSVpvf("(provider %s is in conflict with %s)", solvid2name(pool, who), solvid2name(pool, who2)); else - sv = newSVpvf("(provider %s is conflicted by the build config)", pool_id2str(pool, pool->solvables[who].name)); + sv = newSVpvf("(provider %s is in conflict)", solvid2name(pool, who)); i += 3; } else if (type == ERROR_CHOICE) @@ -5497,6 +7807,9 @@ expand(BSSolv::expander xp, ...) int j; char *str = ""; for (j = i + 3; out.elements[j]; j++) + ; + solv_sort(out.elements + i + 3, j - (i + 3), sizeof(Id), pkgname_sort_cmp, pool); + for (j = i + 3; out.elements[j]; j++) { Solvable *s = pool->solvables + out.elements[j]; str = pool_tmpjoin(pool, str, " ", pool_id2str(pool, s->name)); @@ -5506,11 +7819,31 @@ expand(BSSolv::expander xp, ...) id = out.elements[i + 1]; who = out.elements[i + 2]; if (who) - sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name), str); + sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), solvid2name(pool, who), str); else sv = newSVpvf("have choice for %s: %s", pool_dep2str(pool, id), str); i = j + 1; } + else if (type == ERROR_BADDEPENDENCY) + { + id = out.elements[i + 1]; + who = out.elements[i + 2]; + if (who) + sv = newSVpvf("cannot parse dependency %s from %s", pool_dep2str(pool, id), solvid2name(pool, who)); + else + sv = newSVpvf("cannot parse dependency %s", pool_dep2str(pool, id)); + i += 3; + } + else if (type == ERROR_NOPROVIDERINFO) + { + id = out.elements[i + 1]; + who = out.elements[i + 2]; + if (who) + sv = newSVpvf("(got version %s provided by %s)", pool_id2str(pool, id), solvid2name(pool, who)); + else + sv = newSVpvf("(got version %s)", pool_id2str(pool, id)); + i += 3; + } else croak("expander: bad error type\n"); PUSHs(sv_2mortal(sv)); @@ -5529,27 +7862,31 @@ expand(BSSolv::expander xp, ...) queue_free(&out); } +void +debug(BSSolv::expander xp, const char *str) + CODE: + expander_dbg(xp, "%s", str); + + const char * debugstr(BSSolv::expander xp) CODE: - if (!xp->debugstr) - xp->debugstr = calloc(1, 1); - RETVAL = xp->debugstr; + RETVAL = xp->debugstr ? xp->debugstr : ""; OUTPUT: RETVAL +const char * +debugstrclr(BSSolv::expander xp) + + CODE: + RETVAL = xp->debugstr ? xp->debugstr : ""; + OUTPUT: + RETVAL + CLEANUP: + expander_clrdbg(xp); void DESTROY(BSSolv::expander xp) CODE: - map_free(&xp->ignored); - map_free(&xp->ignoredx); - queue_free(&xp->preferposq); - map_free(&xp->preferpos); - map_free(&xp->preferposx); - map_free(&xp->preferneg); - map_free(&xp->prefernegx); - queue_free(&xp->conflictsq); - map_free(&xp->conflicts); - solv_free(xp->debugstr); - solv_free(xp); + expander_free(xp); + diff --git a/Makefile.PL b/Makefile.PL index ea70fa2..f219477 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -3,15 +3,16 @@ use ExtUtils::MakeMaker; my $solvprefix = '/usr'; my $inc = "-I$solvprefix/include/solv"; -my $lib = ''; +my $lib; if (grep {$_ eq '--bundled-libsolv'} @ARGV) { my $builddir = 'libsolv'; $inc = "-I$builddir/src -I$builddir/ext"; - $lib = "-L$builddir/src -L$builddir/ext"; + $lib = "-L$builddir/src -L$builddir/ext -lsolvext -lsolv -lz -llzma -lzstd"; +} else { + $lib = '-lsolvext -lsolv'; } -$lib = ($lib ? "$lib " : '') . '-lsolvext -lsolv -lz -llzma'; WriteMakefile( NAME => 'BSSolv', diff --git a/debian/control b/debian/control index 787479d..e66c082 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: perl-bssolv Section: devel Priority: extra Maintainer: Shuai Fu -Build-Depends: debhelper (>= 7.0.15), cdbs, libpython2.7, python-dev, dh-python, python-docutils, cmake, dpatch, libbz2-dev, librpm-dev, liblzma-dev, libcurl3 | libcurl4, libcurl4-openssl-dev, libmagic-dev, libexpat1, doxygen, pkg-config, libglib2.0-dev, libssl-dev +Build-Depends: debhelper (>= 7.0.15), cdbs, libpython2.7, python-dev, dh-python, python-docutils, cmake, dpatch, libbz2-dev, librpm-dev, liblzma-dev, libcurl3 | libcurl4, libcurl4-openssl-dev, libmagic-dev, libexpat1, doxygen, pkg-config, libglib2.0-dev, libssl-dev, libzstd-devel Standards-Version: 0.28.0 Homepage: http://www.tizen.org diff --git a/libsolv-0.6.15/BUGS b/libsolv-0.6.15/BUGS deleted file mode 100644 index 0e33eb5..0000000 --- a/libsolv-0.6.15/BUGS +++ /dev/null @@ -1,7 +0,0 @@ - -Having the same key in multiple repodatas of a repo does not work -- searching will return both entries -- repo_write will write a broken solv file -Fixing the search so that it only returns the last entry will also -fix repo_write. - diff --git a/libsolv-0.6.15/NEWS b/libsolv-0.6.15/NEWS deleted file mode 100644 index a265cc4..0000000 --- a/libsolv-0.6.15/NEWS +++ /dev/null @@ -1,52 +0,0 @@ - -This file contains the major changes between -libsolv versions: - -Version 0.6.12: -- new features: - * tcl bindings -- new functions: - * solv_chksum_cmp - -Version 0.6.11: -- new functions: - * pool_ids2whatprovides - -Version 0.6.9: -- new features: - * much improved package choosing code - * new testcase dependency format - * alternatives introspection -- new functions: - * pool_deb_get_autoinstalled - * solver_alternative2str - * solver_alternatives_count - * solver_get_alternative - * solver_rule2pkgrule - * testcase_dep2str - -Version 0.6.5: -- new features: - * support yum style obsolete handling - -Version 0.6.1: -- API change: - repodata_stringify() now returns the string -- new features: - * add BREAK_ORPHANS and KEEP_ORPHANS solver flags - -Version 0.6.0: -- ABI change: cleaned up and reordered knownid.h -- added support for sha224/sha384/sha512 -- API change in the bindings: - * dropped solvid arg from most Dataiterator - constructors - * changed Datamatch results from methods to - attributes - * automatically delete the pool if the owner - object is freed (use the disown method to - get the old behavior). -- new functions: - * pool_add_userinstalled_jobs - * solver_get_userinstalled - diff --git a/libsolv-0.6.15/ext/repo_comps.c b/libsolv-0.6.15/ext/repo_comps.c deleted file mode 100644 index 8f364dd..0000000 --- a/libsolv-0.6.15/ext/repo_comps.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * repo_comps.c - * - * Parses RedHat comps format - * - * Copyright (c) 2012, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pool.h" -#include "repo.h" -#include "util.h" -#define DISABLE_SPLIT -#include "tools_util.h" -#include "repo_comps.h" - -/* - * TODO: - * - * what's the difference between group/category? - * handle "default" and "langonly". - * - * maybe handle REL_COND in solver recommends handling? - */ - -enum state { - STATE_START, - STATE_COMPS, - STATE_GROUP, - STATE_ID, - STATE_NAME, - STATE_DESCRIPTION, - STATE_DISPLAY_ORDER, - STATE_DEFAULT, - STATE_LANGONLY, - STATE_LANG_ONLY, - STATE_USERVISIBLE, - STATE_PACKAGELIST, - STATE_PACKAGEREQ, - STATE_CATEGORY, - STATE_CID, - STATE_CNAME, - STATE_CDESCRIPTION, - STATE_CDISPLAY_ORDER, - STATE_GROUPLIST, - STATE_GROUPID, - NUMSTATES -}; - -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* must be sorted by first column */ -static struct stateswitch stateswitches[] = { - { STATE_START, "comps", STATE_COMPS, 0 }, - { STATE_COMPS, "group", STATE_GROUP, 0 }, - { STATE_COMPS, "category", STATE_CATEGORY, 0 }, - { STATE_GROUP, "id", STATE_ID, 1 }, - { STATE_GROUP, "name", STATE_NAME, 1 }, - { STATE_GROUP, "description", STATE_DESCRIPTION, 1 }, - { STATE_GROUP, "uservisible", STATE_USERVISIBLE, 1 }, - { STATE_GROUP, "display_order", STATE_DISPLAY_ORDER, 1 }, - { STATE_GROUP, "default", STATE_DEFAULT, 1 }, - { STATE_GROUP, "langonly", STATE_LANGONLY, 1 }, - { STATE_GROUP, "lang_only", STATE_LANG_ONLY, 1 }, - { STATE_GROUP, "packagelist", STATE_PACKAGELIST, 0 }, - { STATE_PACKAGELIST, "packagereq", STATE_PACKAGEREQ, 1 }, - { STATE_CATEGORY, "id", STATE_CID, 1 }, - { STATE_CATEGORY, "name", STATE_CNAME, 1 }, - { STATE_CATEGORY, "description", STATE_CDESCRIPTION, 1 }, - { STATE_CATEGORY , "grouplist", STATE_GROUPLIST, 0 }, - { STATE_CATEGORY , "display_order", STATE_CDISPLAY_ORDER, 1 }, - { STATE_GROUPLIST, "groupid", STATE_GROUPID, 1 }, - { NUMSTATES } -}; - -struct parsedata { - Pool *pool; - Repo *repo; - Repodata *data; - const char *filename; - const char *basename; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; - - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; - struct joindata jd; - - const char *tmplang; - Id reqtype; - Id condreq; - - Solvable *solvable; - Id handle; -}; - - -/* - * find_attr - * find value for xml attribute - * I: txt, name of attribute - * I: atts, list of key/value attributes - * O: pointer to value of matching key, or NULL - * - */ - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} - - -/* - * XML callback: startElement - */ - -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) -{ - struct parsedata *pd = userData; - Pool *pool = pd->pool; - Solvable *s = pd->solvable; - struct stateswitch *sw; - -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) /* no statetable -> no substates */ - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - - switch(pd->state) - { - case STATE_GROUP: - case STATE_CATEGORY: - s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); - pd->handle = s - pool->solvables; - break; - - case STATE_NAME: - case STATE_CNAME: - case STATE_DESCRIPTION: - case STATE_CDESCRIPTION: - pd->tmplang = join_dup(&pd->jd, find_attr("xml:lang", atts)); - break; - - case STATE_PACKAGEREQ: - { - const char *type = find_attr("type", atts); - pd->condreq = 0; - pd->reqtype = SOLVABLE_RECOMMENDS; - if (type && !strcmp(type, "conditional")) - { - const char *requires = find_attr("requires", atts); - if (requires && *requires) - pd->condreq = pool_str2id(pool, requires, 1); - } - else if (type && !strcmp(type, "mandatory")) - pd->reqtype = SOLVABLE_REQUIRES; - else if (type && !strcmp(type, "optional")) - pd->reqtype = SOLVABLE_SUGGESTS; - break; - } - - default: - break; - } -} - - -static void XMLCALL -endElement(void *userData, const char *name) -{ - struct parsedata *pd = userData; - Solvable *s = pd->solvable; - Id id; - -#if 0 - fprintf(stderr, "end: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - - switch (pd->state) - { - case STATE_GROUP: - case STATE_CATEGORY: - if (!s->arch) - s->arch = ARCH_NOARCH; - if (!s->evr) - s->evr = ID_EMPTY; - if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) - s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0); - pd->solvable = 0; - break; - - case STATE_ID: - case STATE_CID: - s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->state == STATE_ID ? "group" : "category", ":", pd->content), 1); - break; - - case STATE_NAME: - case STATE_CNAME: - repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content); - break; - - case STATE_DESCRIPTION: - case STATE_CDESCRIPTION: - repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content); - break; - - case STATE_PACKAGEREQ: - id = pool_str2id(pd->pool, pd->content, 1); - if (pd->condreq) - id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1); - repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id); - break; - - case STATE_GROUPID: - id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", pd->content), 1); - s->requires = repo_addid_dep(pd->repo, s->requires, id, 0); - break; - - case STATE_USERVISIBLE: - repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE); - break; - - case STATE_DISPLAY_ORDER: - case STATE_CDISPLAY_ORDER: - repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, pd->content); - break; - - case STATE_DEFAULT: - break; - - case STATE_LANGONLY: - case STATE_LANG_ONLY: - break; - - default: - break; - } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - -#if 0 - fprintf(stderr, "end: [%s] -> %d\n", name, pd->state); -#endif -} - - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; -} - -#define BUFF_SIZE 8192 - - -int -repo_add_comps(Repo *repo, FILE *fp, int flags) -{ - Repodata *data; - struct parsedata pd; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; - XML_Parser parser; - - data = repo_add_repodata(repo, flags); - - memset(&pd, 0, sizeof(pd)); - pd.repo = repo; - pd.pool = repo->pool; - pd.data = data; - - pd.content = solv_malloc(256); - pd.acontent = 256; - - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } - - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); - - solv_free(pd.content); - join_freemem(&pd.jd); - - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); - return 0; -} - -/* EOF */ diff --git a/libsolv-0.6.15/ext/repo_zyppdb.c b/libsolv-0.6.15/ext/repo_zyppdb.c deleted file mode 100644 index 5200c29..0000000 --- a/libsolv-0.6.15/ext/repo_zyppdb.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * repo_zyppdb.c - * - * Parses legacy /var/lib/zypp/db/products/... files. - * They are old (pre Code11) product descriptions. See bnc#429177 - * - * - * Copyright (c) 2008, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pool.h" -#include "repo.h" -#include "util.h" -#define DISABLE_SPLIT -#include "tools_util.h" -#include "repo_zyppdb.h" - - -enum state { - STATE_START, - STATE_PRODUCT, - STATE_NAME, - STATE_VERSION, - STATE_ARCH, - STATE_SUMMARY, - STATE_VENDOR, - STATE_INSTALLTIME, - NUMSTATES -}; - -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { - { STATE_START, "product", STATE_PRODUCT, 0 }, - { STATE_PRODUCT, "name", STATE_NAME, 1 }, - { STATE_PRODUCT, "version", STATE_VERSION, 0 }, - { STATE_PRODUCT, "arch", STATE_ARCH, 1 }, - { STATE_PRODUCT, "summary", STATE_SUMMARY, 1 }, - { STATE_PRODUCT, "install-time", STATE_INSTALLTIME, 1 }, - { STATE_PRODUCT, "vendor", STATE_VENDOR, 1 }, - { NUMSTATES } -}; - -struct parsedata { - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; - Pool *pool; - Repo *repo; - Repodata *data; - - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; - struct joindata jd; - - const char *tmplang; - - Solvable *solvable; - Id handle; -}; - - -/* - * find_attr - * find value for xml attribute - * I: txt, name of attribute - * I: atts, list of key/value attributes - * O: pointer to value of matching key, or NULL - * - */ - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} - - -/* - * XML callback: startElement - */ - -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) -{ - struct parsedata *pd = userData; - Pool *pool = pd->pool; - Solvable *s = pd->solvable; - struct stateswitch *sw; - -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) /* no statetable -> no substates */ - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - - switch(pd->state) - { - case STATE_PRODUCT: - { - /* parse 'type' */ - const char *type = find_attr("type", atts); - s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); - pd->handle = s - pool->solvables; - if (type) - repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, type); - } - break; - case STATE_VERSION: - { - const char *ver = find_attr("ver", atts); - const char *rel = find_attr("rel", atts); - /* const char *epoch = find_attr("epoch", atts); ignored */ - s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel)); - } - break; - /* ... */ - case STATE_SUMMARY: - pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts)); - break; - default: - break; - } -} - - -static void XMLCALL -endElement(void *userData, const char *name) -{ - struct parsedata *pd = userData; - Solvable *s = pd->solvable; - -#if 0 - fprintf(stderr, "end: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - - switch (pd->state) - { - case STATE_PRODUCT: - if (!s->arch) - s->arch = ARCH_NOARCH; - if (!s->evr) - s->evr = ID_EMPTY; - if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) - s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0); - pd->solvable = 0; - break; - case STATE_NAME: - s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1); - break; - case STATE_ARCH: - s->arch = pool_str2id(pd->pool, pd->content, 1); - break; - case STATE_SUMMARY: - repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content); - break; - case STATE_VENDOR: - s->vendor = pool_str2id(pd->pool, pd->content, 1); - break; - case STATE_INSTALLTIME: - repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(pd->content)); - default: - break; - } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - -#if 0 - fprintf(stderr, "end: [%s] -> %d\n", name, pd->state); -#endif -} - - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; -} - -#define BUFF_SIZE 8192 - - -/* - * add single product to repo - * - */ - -static void -add_zyppdb_product(struct parsedata *pd, FILE *fp) -{ - char buf[BUFF_SIZE]; - int l; - - XML_Parser parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - if (pd->solvable) - { - repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); - pd->solvable = 0; - } - return; - } - if (l == 0) - break; - } - XML_ParserFree(parser); -} - - -/* - * read all installed products - * - * parse each one as a product - */ - -int -repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags) -{ - int i; - struct parsedata pd; - struct stateswitch *sw; - struct dirent *entry; - char *fullpath; - DIR *dir; - FILE *fp; - Repodata *data; - - data = repo_add_repodata(repo, flags); - memset(&pd, 0, sizeof(pd)); - pd.repo = repo; - pd.pool = repo->pool; - pd.data = data; - - pd.content = malloc(256); - pd.acontent = 256; - - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } - - if (flags & REPO_USE_ROOTDIR) - dirpath = pool_prepend_rootdir(repo->pool, dirpath); - dir = opendir(dirpath); - if (dir) - { - while ((entry = readdir(dir))) - { - if (strlen(entry->d_name) < 3) - continue; /* skip '.' and '..' */ - fullpath = join2(&pd.jd, dirpath, "/", entry->d_name); - if ((fp = fopen(fullpath, "r")) == 0) - { - pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno)); - continue; - } - add_zyppdb_product(&pd, fp); - fclose(fp); - } - } - closedir(dir); - - free(pd.content); - join_freemem(&pd.jd); - if (flags & REPO_USE_ROOTDIR) - solv_free((char *)dirpath); - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); - return 0; -} - -/* EOF */ diff --git a/libsolv-0.6.15/package/libsolv.spec.in b/libsolv-0.6.15/package/libsolv.spec.in deleted file mode 100644 index c2251ec..0000000 --- a/libsolv-0.6.15/package/libsolv.spec.in +++ /dev/null @@ -1,268 +0,0 @@ -# -# spec file for package libsolv -# -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. -# -# All modifications and additions to the file contributed by third parties -# remain the property of their copyright owners, unless otherwise agreed -# upon. The license for this file, and modifications and additions to the -# file, is the same license as for the pristine package itself (unless the -# license for the pristine package is not an Open Source License, in which -# case the license is the MIT License). An "Open Source License" is a -# license that conforms to the Open Source Definition (Version 1.9) -# published by the Open Source Initiative. - -# Please submit bugfixes or comments via http://bugs.opensuse.org/ -# - -Name: libsolv -Version: @VERSION@ -Release: 0 -Url: https://github.com/openSUSE/libsolv -Source: libsolv-%{version}.tar.bz2 -BuildRoot: %{_tmppath}/%{name}-%{version}-build - -%bcond_without enable_static -%bcond_without disable_shared -%bcond_without perl_binding -%bcond_without python_binding -%bcond_without ruby_binding -%bcond_with zypp - -%if 0%{?mandriva_version} -# force this version on mandriva -BuildRequires: libneon0.26-devel -%endif -%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 -BuildRequires: db-devel -%endif -%if 0%{?suse_version} -%if 0%{?suse_version} < 1030 -BuildRequires: expat -%else -BuildRequires: libexpat-devel -%endif -%if 0%{?suse_version} < 1100 -BuildRequires: graphviz -%endif -%if 0%{?suse_version} > 1020 -BuildRequires: fdupes -%endif -%else -BuildRequires: expat-devel -%endif -BuildRequires: cmake -BuildRequires: gcc-c++ -BuildRequires: rpm-devel -BuildRequires: zlib-devel - -%if %{with perl_binding} -BuildRequires: perl -%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 -BuildRequires: perl-devel -%endif -BuildRequires: swig -%endif -%if %{with ruby_binding} -%global ruby_vendorarch %(ruby -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']") -BuildRequires: ruby -BuildRequires: ruby-devel -BuildRequires: swig -%endif -%if %{with python_binding} -%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True);") -BuildRequires: python-devel -BuildRequires: swig -%endif - -Summary: A new approach to package dependency solving -License: BSD-3-Clause -Group: Development/Libraries/C and C++ - -%description -A new approach to package dependency solving - -%if !%{with disable_shared} -%package -n libsolv@LIBSOLV_SOVERSION@ -Summary: A new approach to package dependency solving -Group: Development/Libraries/C and C++ - -%description -n libsolv@LIBSOLV_SOVERSION@ -A new approach to package dependency solving - -%endif -%package devel -Summary: A new approach to package dependency solving -Group: Development/Libraries/C and C++ -%if !%{with disable_shared} -Requires: libsolv@LIBSOLV_SOVERSION@ = %version -%endif -Requires: rpm-devel -Conflicts: libsatsolver-devel - -%description devel -Development files for libsolv, a new approach to package dependency solving - -%package tools -Summary: A new approach to package dependency solving -Group: Development/Libraries/C and C++ -Obsoletes: satsolver-tools < 0.18 -Provides: satsolver-tools = 0.18 -Conflicts: satsolver-tools-obsolete -Requires: gzip bzip2 coreutils findutils - -%description tools -A new approach to package dependency solving. - -%package demo -Summary: Applications demoing the libsolv library -Group: System/Management -Requires: curl -%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 -Requires: gnupg2 -%endif -%if 0%{?suse_version} -Requires: gpg2 -%endif -Conflicts: libsatsolver-demo - -%description demo -Applications demoing the libsolv library. - -%package -n ruby-solv -Summary: Ruby bindings for the libsolv library -Group: Development/Languages/Ruby - -%description -n ruby-solv -Ruby bindings for sat solver. - -%package -n python-solv -%if 0%{?py_requires:1} && %{with python_binding} -%py_requires -%endif -Summary: Python bindings for the libsolv library -Group: Development/Languages/Python - -%description -n python-solv -Python bindings for sat solver. - -%package -n perl-solv -Requires: perl = %{perl_version} -Summary: Perl bindings for the libsolv library -Group: Development/Languages/Perl - -%description -n perl-solv -Perl bindings for sat solver. - -%prep -%setup -n libsolv-%{version} - -%build -export CFLAGS="$RPM_OPT_FLAGS" -export CXXFLAGS="$CFLAGS" - -CMAKE_FLAGS= -%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 -CMAKE_FLAGS="-DFEDORA=1" -%endif -%if 0%{?suse_version} -CMAKE_FLAGS="-DSUSE=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1" -%endif - -cmake $CMAKE_FLAGS \ - -DCMAKE_INSTALL_PREFIX=%{_prefix} \ - -DLIB=%{_lib} \ - -DCMAKE_VERBOSE_MAKEFILE=TRUE \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - %{?with_enable_static:-DENABLE_STATIC=1} \ - %{?with_disable_shared:-DDISABLE_SHARED=1} \ - %{?with_perl_binding:-DENABLE_PERL=1} \ - %{?with_python_binding:-DENABLE_PYTHON=1} \ - %{?with_ruby_binding:-DENABLE_RUBY=1} \ - %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \ - -DUSE_VENDORDIRS=1 \ - -DCMAKE_SKIP_RPATH=1 -make %{?jobs:-j %jobs} - -%install -make DESTDIR=$RPM_BUILD_ROOT install -%if %{with python_binding} -%if 0%{?suse_version} -pushd $RPM_BUILD_ROOT/%{python_sitearch} -python %py_libdir/py_compile.py *.py -python -O %py_libdir/py_compile.py *.py -popd -%endif -%endif -%if %{with disable_shared} -# we want to leave the .a file untouched -export NO_BRP_STRIP_DEBUG=true -%endif - -%clean -rm -rf "$RPM_BUILD_ROOT" - -%if !%{with disable_shared} -%post -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig - -%postun -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig - -%files -n libsolv@LIBSOLV_SOVERSION@ -%defattr(-,root,root) -%doc LICENSE* -%{_libdir}/libsolv.so.* -%{_libdir}/libsolvext.so.* -%endif - -%files tools -%defattr(-,root,root) -%if 0%{?suse_version} -%exclude %{_bindir}/helix2solv -%exclude %{_mandir}/man1/helix2solv* -%endif -%exclude %{_bindir}/solv -%{_bindir}/* -%{_mandir}/man1/* - -%files devel -%defattr(-,root,root) -%if %{with enable_static} -%{_libdir}/libsolv.a -%{_libdir}/libsolvext.a -%endif -%if !%{with disable_shared} -%{_libdir}/libsolv.so -%{_libdir}/libsolvext.so -%endif -%{_includedir}/solv -%if 0%{?suse_version} -%{_bindir}/helix2solv -%{_mandir}/man1/helix2solv* -%endif -%{_datadir}/cmake/Modules/* -%{_libdir}/pkgconfig/libsolv.pc -%{_mandir}/man3/* - -%files demo -%defattr(-,root,root) -%{_bindir}/solv - -%if %{with perl_binding} -%files -n perl-solv -%defattr(-,root,root) -%{perl_vendorarch}/* -%endif - -%if %{with ruby_binding} -%files -n ruby-solv -%defattr(-,root,root) -%{ruby_vendorarch}/* -%endif - -%if %{with python_binding} -%files -n python-solv -%defattr(-,root,root) -%{python_sitearch}/* -%endif - -%changelog diff --git a/libsolv-0.6.15/src/bitmap.c b/libsolv-0.6.15/src/bitmap.c deleted file mode 100644 index 1bf1666..0000000 --- a/libsolv-0.6.15/src/bitmap.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2007, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * bitmap.c - * - */ - -#include -#include - -#include "bitmap.h" -#include "util.h" - -/* constructor */ -void -map_init(Map *m, int n) -{ - m->size = (n + 7) >> 3; - m->map = m->size ? solv_calloc(m->size, 1) : 0; -} - -/* destructor */ -void -map_free(Map *m) -{ - m->map = solv_free(m->map); - m->size = 0; -} - -/* copy constructor t <- s */ -void -map_init_clone(Map *t, Map *s) -{ - t->size = s->size; - if (s->size) - { - t->map = solv_malloc(s->size); - memcpy(t->map, s->map, s->size); - } - else - t->map = 0; -} - -/* grow a map */ -void -map_grow(Map *m, int n) -{ - n = (n + 7) >> 3; - if (m->size < n) - { - m->map = solv_realloc(m->map, n); - memset(m->map + m->size, 0, n - m->size); - m->size = n; - } -} - -/* bitwise-ands maps t and s, stores the result in t. */ -void -map_and(Map *t, Map *s) -{ - unsigned char *ti, *si, *end; - ti = t->map; - si = s->map; - end = ti + (t->size < s->size ? t->size : s->size); - while (ti < end) - *ti++ &= *si++; -} - -/* bitwise-ors maps t and s, stores the result in t. */ -void -map_or(Map *t, Map *s) -{ - unsigned char *ti, *si, *end; - if (t->size < s->size) - map_grow(t, s->size << 3); - ti = t->map; - si = s->map; - end = ti + (t->size < s->size ? t->size : s->size); - while (ti < end) - *ti++ |= *si++; -} - -/* remove all set bits in s from t. */ -void -map_subtract(Map *t, Map *s) -{ - unsigned char *ti, *si, *end; - ti = t->map; - si = s->map; - end = ti + (t->size < s->size ? t->size : s->size); - while (ti < end) - *ti++ &= ~*si++; -} - -/* EOF */ diff --git a/libsolv-0.6.15/src/cplxdeps.c b/libsolv-0.6.15/src/cplxdeps.c deleted file mode 100644 index aadbc48..0000000 --- a/libsolv-0.6.15/src/cplxdeps.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2014, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * cplxdeps.c - * - * normalize complex dependencies into CNF/DNF form - */ - -#include -#include -#include -#include -#include - -#include "pool.h" -#include "cplxdeps.h" - -#ifdef ENABLE_COMPLEX_DEPS - -#undef CPLXDEBUG - -int -pool_is_complex_dep_rd(Pool *pool, Reldep *rd) -{ - for (;;) - { - if (rd->flags == REL_AND || rd->flags == REL_COND) /* those two are the complex ones */ - return 1; - if (rd->flags != REL_OR) - return 0; - if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name))) - return 1; - if (!ISRELDEP(rd->evr)) - return 0; - rd = GETRELDEP(pool, rd->evr); - } -} - -/* expand simple dependencies into package lists */ -static int -expand_simpledeps(Pool *pool, Queue *bq, int start, int split) -{ - int end = bq->count; - int i, x; - int newsplit = 0; - for (i = start; i < end; i++) - { - if (i == split) - newsplit = bq->count - (end - start); - x = bq->elements[i]; - if (x == pool->nsolvables) - { - Id *dp = pool->whatprovidesdata + bq->elements[++i]; - for (; *dp; dp++) - queue_push(bq, *dp); - } - else - queue_push(bq, x); - } - if (i == split) - newsplit = bq->count - (end - start); - queue_deleten(bq, start, end - start); - return newsplit; -} - -#ifdef CPLXDEBUG -static void -print_depblocks(Pool *pool, Queue *bq, int start) -{ - int i; - - for (i = start; i < bq->count; i++) - { - if (bq->elements[i] == pool->nsolvables) - { - Id *dp = pool->whatprovidesdata + bq->elements[++i]; - printf(" ("); - while (*dp) - printf(" %s", pool_solvid2str(pool, *dp++)); - printf(" )"); - } - else if (bq->elements[i] > 0) - printf(" %s", pool_solvid2str(pool, bq->elements[i])); - else if (bq->elements[i] < 0) - printf(" -%s", pool_solvid2str(pool, -bq->elements[i])); - else - printf(" ||"); - } - printf("\n"); -} -#endif - -/* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */ -static int -invert_depblocks(Pool *pool, Queue *bq, int start, int r) -{ - int i, j, end; - if (r == 0 || r == 1) - return r ? 0 : 1; - expand_simpledeps(pool, bq, start, 0); - end = bq->count; - for (i = j = start; i < end; i++) - { - if (bq->elements[i]) - { - bq->elements[i] = -bq->elements[i]; - continue; - } - /* end of block reached, reverse */ - if (i - 1 > j) - { - int k; - for (k = i - 1; j < k; j++, k--) - { - Id t = bq->elements[j]; - bq->elements[j] = bq->elements[k]; - bq->elements[k] = t; - } - } - j = i + 1; - } - return -1; -} - -/* - * returns: - * 0: no blocks - * 1: matches all - * -1: at least one block - */ -static int -normalize_dep(Pool *pool, Id dep, Queue *bq, int flags) -{ - int bqcnt = bq->count; - int bqcnt2; - int todnf = flags & CPLXDEPS_TODNF ? 1 : 0; - Id p, dp; - -#ifdef CPLXDEBUG - printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf); -#endif - if (pool_is_complex_dep(pool, dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND) - { - int rdflags = rd->flags; - Id name = rd->name; - Id evr = rd->evr; - int r, mode; - - if (rdflags == REL_COND) - { - /* check for relly complex ELSE case */ - if (ISRELDEP(evr)) - { - Reldep *rd2 = GETRELDEP(pool, evr); - if (rd2->flags == REL_ELSE) - { - int r2; - /* really complex case */ - if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_1) - { - /* A OR ~B */ - rdflags = REL_COND; - evr = rd2->name; - } - else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_2) - { - /* C OR B */ - rdflags = REL_OR; - name = rd2->evr; - evr = rd2->name; - } - else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_1) - { - /* A AND B */ - rdflags = REL_AND; - evr = rd2->name; - } - else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_2) - { - /* A AND C */ - rdflags = REL_AND; - evr = rd2->evr; - } - else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_3) - { - /* C AND ~B */ - rdflags = REL_ELSE; - name = rd2->evr; - evr = rd2->name; - } - else if (!todnf) - { - /* we want AND: A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */ - r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_1); - if (r == 0 && (flags & CPLXDEPS_DONTFIX) == 0) - return 0; - r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_2); - if (r2 == 0 && (flags & CPLXDEPS_DONTFIX) == 0) - { - queue_truncate(bq, bqcnt); - return 0; - } - if (r == -1 || r2 == -1) - return -1; - return r == 1 || r2 == 1 ? 1 : 0; - } - else - { - int r2, r3; - /* we want OR: A IF (B ELSE C) -> (A AND B) OR (A AND C) OR (~B AND C) */ - r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_1); - if (r == 1) - return 1; - r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_2); - if (r2 == 1) - { - queue_truncate(bq, bqcnt); - return 1; - } - r3 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_3); - if (r3 == 1) - { - queue_truncate(bq, bqcnt); - return 1; - } - if (r == -1 || r2 == -1 || r3 == -1) - return -1; - return 0; - } - } - } - } - mode = rdflags == REL_AND || rdflags == REL_ELSE ? 0 : 1; - - /* get blocks of first argument */ - r = normalize_dep(pool, name, bq, flags); - if (r == 0) - { - if (rdflags == REL_ELSE) - return 0; - if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0) - return 0; - if (rdflags == REL_COND) - { - r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX); - return invert_depblocks(pool, bq, bqcnt, r); /* invert block for COND */ - } - return normalize_dep(pool, evr, bq, flags); - } - if (r == 1) - { - if (rdflags == REL_ELSE) - { - r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX); - return invert_depblocks(pool, bq, bqcnt, r); /* invert block for ELSE */ - } - if (rdflags == REL_OR || rdflags == REL_COND) - return 1; - return normalize_dep(pool, evr, bq, flags); - } - - /* get blocks of second argument */ - bqcnt2 = bq->count; - /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */ - r = normalize_dep(pool, evr, bq, rdflags == REL_COND || rdflags == REL_ELSE ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags); - if (rdflags == REL_COND || rdflags == REL_ELSE) - r = invert_depblocks(pool, bq, bqcnt2, r); /* invert 2nd block */ - if (r == 0) - { - if (rdflags == REL_OR) - return -1; - if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0) - return -1; - queue_truncate(bq, bqcnt); - return 0; - } - if (r == 1) - { - if (rdflags == REL_COND || rdflags == REL_OR) - { - queue_truncate(bq, bqcnt); - return 1; - } - return -1; - } - if (mode == todnf) - { - /* simple case: just join em. nothing more to do here. */ -#ifdef CPLXDEBUG - printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count); -#endif - return -1; - } - else - { - /* complex case: mix em */ - int i, j, bqcnt3; -#ifdef CPLXDEBUG - printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count); -#endif - bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2); - bqcnt3 = bq->count; - for (i = bqcnt; i < bqcnt2; i++) - { - for (j = bqcnt2; j < bqcnt3; j++) - { - int a, b; - int bqcnt4 = bq->count; - int k = i; - - /* mix i block with j block, both blocks are sorted */ - while (bq->elements[k] && bq->elements[j]) - { - if (bq->elements[k] < bq->elements[j]) - queue_push(bq, bq->elements[k++]); - else - { - if (bq->elements[k] == bq->elements[j]) - k++; - queue_push(bq, bq->elements[j++]); - } - } - while (bq->elements[j]) - queue_push(bq, bq->elements[j++]); - while (bq->elements[k]) - queue_push(bq, bq->elements[k++]); - - /* block is finished, check for A + -A */ - for (a = bqcnt4, b = bq->count - 1; a < b; ) - { - if (-bq->elements[a] == bq->elements[b]) - break; - if (-bq->elements[a] > bq->elements[b]) - a++; - else - b--; - } - if (a < b) - queue_truncate(bq, bqcnt4); /* ignore this block */ - else - queue_push(bq, 0); /* finish block */ - } - /* advance to next block */ - while (bq->elements[i]) - i++; - } - i = -1; - if (bqcnt3 == bq->count) /* ignored all blocks? */ - i = todnf ? 0 : 1; - queue_deleten(bq, bqcnt, bqcnt3 - bqcnt); - return i; - } - } - } - - /* fallback case: just use package list */ - dp = pool_whatprovides(pool, dep); - if (dp <= 2 || !pool->whatprovidesdata[dp]) - return dp == 2 ? 1 : 0; - if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE) - return 1; - bqcnt = bq->count; - if ((flags & CPLXDEPS_NAME) != 0) - { - while ((p = pool->whatprovidesdata[dp++]) != 0) - { - if (!pool_match_nevr(pool, pool->solvables + p, dep)) - continue; - queue_push(bq, p); - if (todnf) - queue_push(bq, 0); - } - } - else if (todnf) - { - while ((p = pool->whatprovidesdata[dp++]) != 0) - queue_push2(bq, p, 0); - } - else - queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */ - if (bq->count == bqcnt) - return 0; /* no provider */ - if (!todnf) - queue_push(bq, 0); /* finish block */ - return -1; -} - -int -pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags) -{ - int i, bqcnt = bq->count; - - i = normalize_dep(pool, dep, bq, flags); - if ((flags & CPLXDEPS_EXPAND) != 0) - { - if (i != 0 && i != 1) - expand_simpledeps(pool, bq, bqcnt, 0); - } - if ((flags & CPLXDEPS_INVERT) != 0) - i = invert_depblocks(pool, bq, bqcnt, i); -#ifdef CPLXDEBUG - if (i == 0) - printf("NONE\n"); - else if (i == 1) - printf("ALL\n"); - else - print_depblocks(pool, bq, bqcnt); -#endif - return i; -} - -void -pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg) -{ - while (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND) - break; - pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg); - dep = rd->evr; - if (rd->flags == REL_COND) - { - neg = !neg; - if (ISRELDEP(dep)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg); - dep = rd2->name; - } - } - } - } - if (!neg) - { - Id p, pp; - FOR_PROVIDES(p, pp, dep) - if (!MAPTST(m, p)) - queue_push(q, p); - } -} - -#endif /* ENABLE_COMPLEX_DEPS */ - diff --git a/libsolv-0.6.15/src/problems.h b/libsolv-0.6.15/src/problems.h deleted file mode 100644 index e5b2279..0000000 --- a/libsolv-0.6.15/src/problems.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2007-2009, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * problems.h - * - */ - -#ifndef LIBSOLV_PROBLEMS_H -#define LIBSOLV_PROBLEMS_H - -#include "rules.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -struct _Solver; - -#define SOLVER_SOLUTION_JOB (0) -#define SOLVER_SOLUTION_DISTUPGRADE (-1) -#define SOLVER_SOLUTION_INFARCH (-2) -#define SOLVER_SOLUTION_BEST (-3) -#define SOLVER_SOLUTION_POOLJOB (-4) - -void solver_disableproblem(struct _Solver *solv, Id v); -void solver_enableproblem(struct _Solver *solv, Id v); -int solver_prepare_solutions(struct _Solver *solv); - -unsigned int solver_problem_count(struct _Solver *solv); -Id solver_next_problem(struct _Solver *solv, Id problem); -unsigned int solver_solution_count(struct _Solver *solv, Id problem); -Id solver_next_solution(struct _Solver *solv, Id problem, Id solution); -unsigned int solver_solutionelement_count(struct _Solver *solv, Id problem, Id solution); -Id solver_solutionelement_internalid(struct _Solver *solv, Id problem, Id solution); -Id solver_solutionelement_extrajobflags(struct _Solver *solv, Id problem, Id solution); -Id solver_next_solutionelement(struct _Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp); - -void solver_take_solutionelement(struct _Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job); -void solver_take_solution(struct _Solver *solv, Id problem, Id solution, Queue *job); - -Id solver_findproblemrule(struct _Solver *solv, Id problem); -void solver_findallproblemrules(struct _Solver *solv, Id problem, Queue *rules); - -extern const char *solver_problemruleinfo2str(struct _Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep); -extern const char *solver_problem2str(struct _Solver *solv, Id problem); -extern const char *solver_solutionelement2str(struct _Solver *solv, Id p, Id rp); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libsolv-0.6.15/src/repo_write.h b/libsolv-0.6.15/src/repo_write.h deleted file mode 100644 index 763147e..0000000 --- a/libsolv-0.6.15/src/repo_write.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2007, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * repo_write.h - * - */ - -#ifndef REPO_WRITE_H -#define REPO_WRITE_H - -#include - -#include "repo.h" -#include "queue.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern int repo_write(Repo *repo, FILE *fp); -extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq); - -extern int repodata_write(Repodata *data , FILE *fp); -extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq); - -extern int repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libsolv-0.6.15/src/selection.c b/libsolv-0.6.15/src/selection.c deleted file mode 100644 index 8856436..0000000 --- a/libsolv-0.6.15/src/selection.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * Copyright (c) 2012, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * selection.c - * - */ - -#define _GNU_SOURCE -#include -#include - -#include -#include -#include - -#include "selection.h" -#include "solver.h" -#include "evr.h" - - -static int -str2archid(Pool *pool, const char *arch) -{ - Id id; - if (!*arch) - return 0; - id = pool_str2id(pool, arch, 0); - if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) - return id; - if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id])) - return 0; - return id; -} - -static void -selection_prune(Pool *pool, Queue *selection) -{ - int i, j; - Id p, pp; - for (i = j = 0; i < selection->count; i += 2) - { - Id select = selection->elements[i] & SOLVER_SELECTMASK; - p = 0; - if (select == SOLVER_SOLVABLE_ALL) - p = 1; - else if (select == SOLVER_SOLVABLE_REPO) - { - Solvable *s; - Repo *repo = pool_id2repo(pool, selection->elements[i + 1]); - if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - break; - } - else - { - FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1]) - break; - } - if (!p) - continue; - selection->elements[j] = selection->elements[i]; - selection->elements[j + 1] = selection->elements[i + 1]; - j += 2; - } - queue_truncate(selection, j); -} - - -static int -selection_solvables_sortcmp(const void *ap, const void *bp, void *dp) -{ - return *(const Id *)ap - *(const Id *)bp; -} - -void -selection_solvables(Pool *pool, Queue *selection, Queue *pkgs) -{ - int i, j; - Id p, pp, lastid; - queue_empty(pkgs); - for (i = 0; i < selection->count; i += 2) - { - Id select = selection->elements[i] & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE_ALL) - { - FOR_POOL_SOLVABLES(p) - queue_push(pkgs, p); - } - if (select == SOLVER_SOLVABLE_REPO) - { - Solvable *s; - Repo *repo = pool_id2repo(pool, selection->elements[i + 1]); - if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - queue_push(pkgs, p); - } - else - { - FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1]) - queue_push(pkgs, p); - } - } - if (pkgs->count < 2) - return; - /* sort and unify */ - solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL); - lastid = pkgs->elements[0]; - for (i = j = 1; i < pkgs->count; i++) - if (pkgs->elements[i] != lastid) - pkgs->elements[j++] = lastid = pkgs->elements[i]; - queue_truncate(pkgs, j); -} - -static void -selection_flatten(Pool *pool, Queue *selection) -{ - Queue q; - int i; - if (selection->count <= 2) - return; - for (i = 0; i < selection->count; i += 2) - if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL) - { - selection->elements[0] = selection->elements[i]; - selection->elements[1] = selection->elements[i + 1]; - queue_truncate(selection, 2); - return; - } - queue_init(&q); - selection_solvables(pool, selection, &q); - if (!q.count) - { - queue_empty(selection); - return; - } - queue_truncate(selection, 2); - if (q.count > 1) - { - selection->elements[0] = SOLVER_SOLVABLE_ONE_OF; - selection->elements[1] = pool_queuetowhatprovides(pool, &q); - } - else - { - selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; - selection->elements[1] = q.elements[0]; - } -} - -static void -selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr) -{ - int i; - - for (i = 0; i < selection->count; i += 2) - { - Id select = selection->elements[i] & SOLVER_SELECTMASK; - Id id = selection->elements[i + 1]; - if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF) - { - /* done by selection_addsrc, currently implies SELECTION_NAME */ - Queue q; - Id p, pp; - Id rel = 0, relname = 0; - int miss = 0; - - queue_init(&q); - FOR_JOB_SELECT(p, pp, select, id) - { - Solvable *s = pool->solvables + p; - if (!rel || s->name != relname) - { - relname = s->name; - rel = pool_rel2id(pool, relname, relevr, relflags, 1); - } - if (pool_match_nevr(pool, s, rel)) - queue_push(&q, p); - else - miss = 1; - } - if (miss) - { - if (q.count == 1) - { - selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; - selection->elements[i + 1] = q.elements[0]; - } - else - { - selection->elements[i] = SOLVER_SOLVABLE_ONE_OF; - selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q); - } - } - queue_free(&q); - } - else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) - { - /* don't stack src reldeps */ - if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC) - id = rd->name; - } - selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1); - } - else - continue; /* actually internal error */ - if (relflags == REL_ARCH) - selection->elements[i] |= SOLVER_SETARCH; - if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES) - { - if (pool->disttype == DISTTYPE_DEB) - selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */ - else - { - const char *rel = strrchr(pool_id2str(pool, relevr), '-'); - selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV; - } - } - } - selection_prune(pool, selection); -} - -static void -selection_filter_installed(Pool *pool, Queue *selection) -{ - Queue q; - int i, j; - - if (!pool->installed) - queue_empty(selection); - queue_init(&q); - for (i = j = 0; i < selection->count; i += 2) - { - Id select = selection->elements[i] & SOLVER_SELECTMASK; - Id id = selection->elements[i + 1]; - if (select == SOLVER_SOLVABLE_ALL) - { - select = SOLVER_SOLVABLE_REPO; - id = pool->installed->repoid; - } - else if (select == SOLVER_SOLVABLE_REPO) - { - if (id != pool->installed->repoid) - select = 0; - } - else - { - int bad = 0; - Id p, pp; - queue_empty(&q); - FOR_JOB_SELECT(p, pp, select, id) - { - if (pool->solvables[p].repo != pool->installed) - bad = 1; - else - queue_push(&q, p); - } - if (bad || !q.count) - { - if (!q.count) - select = 0; - else if (q.count == 1) - { - select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; - id = q.elements[0]; - } - else - { - select = SOLVER_SOLVABLE_ONE_OF; - id = pool_queuetowhatprovides(pool, &q); - } - } - } - if (select) - { - selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO; - selection->elements[j++] = id; - } - } - queue_truncate(selection, j); - queue_free(&q); -} - -static void -selection_addsrc(Pool *pool, Queue *selection, int flags) -{ - Queue q; - Id p, name; - int i, havesrc; - - if ((flags & SELECTION_INSTALLED_ONLY) != 0) - return; /* sources can't be installed */ - queue_init(&q); - for (i = 0; i < selection->count; i += 2) - { - if (selection->elements[i] != SOLVER_SOLVABLE_NAME) - continue; - name = selection->elements[i + 1]; - havesrc = 0; - queue_empty(&q); - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - if (s->name != name) - continue; - if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) - { - if (pool_disabled_solvable(pool, s)) - continue; - havesrc = 1; - } - else if (s->repo != pool->installed && !pool_installable(pool, s)) - continue; - queue_push(&q, p); - } - if (!havesrc || !q.count) - continue; - if (q.count == 1) - { - selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; - selection->elements[i + 1] = q.elements[0]; - } - else - { - selection->elements[i] = SOLVER_SOLVABLE_ONE_OF; - selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q); - } - } - queue_free(&q); -} - -static inline const char * -skipkind(const char *n) -{ - const char *s; - for (s = n; *s >= 'a' && *s <= 'z'; s++) - ; - if (*s == ':' && s != n) - return s + 1; - return n; -} - -static inline void -queue_pushunique2(Queue *q, Id id1, Id id2) -{ - int i; - for (i = 0; i < q->count; i += 2) - if (q->elements[i] == id1 && q->elements[i + 1] == id2) - return; - queue_push2(q, id1, id2); -} - -static int -selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags) -{ - Id p, pp; - int match = 0; - - FOR_PROVIDES(p, pp, id) - { - Solvable *s = pool->solvables + p; - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) - continue; - match = 1; - if (s->name == id && (flags & SELECTION_NAME) != 0) - { - if ((flags & SELECTION_SOURCE_ONLY) != 0) - id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); - queue_push2(selection, SOLVER_SOLVABLE_NAME, id); - if ((flags & SELECTION_WITH_SOURCE) != 0) - selection_addsrc(pool, selection, flags); - return SELECTION_NAME; - } - } - if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0) - { - /* src rpms don't have provides, so we must check every solvable */ - FOR_POOL_SOLVABLES(p) /* slow path */ - { - Solvable *s = pool->solvables + p; - if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)) - { - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) - continue; /* just in case... src rpms can't be installed */ - if (pool_disabled_solvable(pool, s)) - continue; - if ((flags & SELECTION_SOURCE_ONLY) != 0) - id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); - queue_push2(selection, SOLVER_SOLVABLE_NAME, id); - if ((flags & SELECTION_WITH_SOURCE) != 0) - selection_addsrc(pool, selection, flags); - return SELECTION_NAME; - } - } - } - if (match && (flags & SELECTION_PROVIDES) != 0) - { - queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); - return SELECTION_PROVIDES; - } - return 0; -} - -static int -selection_depglob(Pool *pool, Queue *selection, const char *name, int flags) -{ - Id id, p, pp; - int match = 0; - int doglob = 0; - int nocase = 0; - int globflags = 0; - - if ((flags & SELECTION_SOURCE_ONLY) != 0) - { - flags &= ~SELECTION_PROVIDES; /* sources don't provide anything */ - flags &= ~SELECTION_WITH_SOURCE; - } - - if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES))) - return 0; - - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed) - return 0; - - nocase = flags & SELECTION_NOCASE; - if (!nocase && !(flags & SELECTION_SKIP_KIND)) - { - id = pool_str2id(pool, name, 0); - if (id) - { - /* the id is know, do the fast id matching using the whatprovides lookup */ - int ret = selection_depglob_id(pool, selection, id, flags); - if (ret) - return ret; - } - } - - if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0) - doglob = 1; - - if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob) - return 0; /* all done above in depglob_id */ - - if (doglob && nocase) - globflags = FNM_CASEFOLD; - - if ((flags & SELECTION_NAME) != 0) - { - /* looks like a name glob. hard work. */ - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - const char *n; - if (s->repo != pool->installed && !pool_installable(pool, s)) - { - if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)) - continue; - if (pool_disabled_solvable(pool, s)) - continue; - } - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) - continue; - id = s->name; - n = pool_id2str(pool, id); - if (flags & SELECTION_SKIP_KIND) - n = skipkind(n); - if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0) - { - if ((flags & SELECTION_SOURCE_ONLY) != 0) - id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); - queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id); - match = 1; - } - } - if (match) - { - if ((flags & SELECTION_WITH_SOURCE) != 0) - selection_addsrc(pool, selection, flags); - return SELECTION_NAME; - } - } - - if ((flags & SELECTION_PROVIDES)) - { - /* looks like a dep glob. really hard work. */ - for (id = 1; id < pool->ss.nstrings; id++) - { - const char *n; - if (!pool->whatprovides[id] || pool->whatprovides[id] == 1) - continue; - n = pool_id2str(pool, id); - if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0) - { - if ((flags & SELECTION_INSTALLED_ONLY) != 0) - { - FOR_PROVIDES(p, pp, id) - if (pool->solvables[p].repo == pool->installed) - break; - if (!p) - continue; - } - queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); - match = 1; - } - } - if (match) - return SELECTION_PROVIDES; - } - return 0; -} - -static int -selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags) -{ - int ret; - const char *r; - Id archid; - - if ((ret = selection_depglob(pool, selection, name, flags)) != 0) - return ret; - if (!(flags & SELECTION_DOTARCH)) - return 0; - /* check if there is an .arch suffix */ - if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - char *rname = solv_strdup(name); - rname[r - name] = 0; - if (archid == ARCH_SRC || archid == ARCH_NOSRC) - flags |= SELECTION_SOURCE_ONLY; - if ((ret = selection_depglob(pool, selection, rname, flags)) != 0) - { - selection_filter_rel(pool, selection, REL_ARCH, archid); - solv_free(rname); - return ret | SELECTION_DOTARCH; - } - solv_free(rname); - } - return 0; -} - -static int -selection_filelist(Pool *pool, Queue *selection, const char *name, int flags) -{ - Dataiterator di; - Queue q; - int type; - - /* all files in the file list start with a '/' */ - if (*name != '/') - { - if (!(flags & SELECTION_GLOB)) - return 0; - if (*name != '*' && *name != '[' && *name != '?') - return 0; - } - type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB; - if ((flags & SELECTION_NOCASE) != 0) - type |= SEARCH_NOCASE; - queue_init(&q); - dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST); - while (dataiterator_step(&di)) - { - Solvable *s = pool->solvables + di.solvid; - if (!s->repo) - continue; - if (s->repo != pool->installed && !pool_installable(pool, s)) - { - if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)) - continue; - if (pool_disabled_solvable(pool, s)) - continue; - } - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) - continue; - queue_push(&q, di.solvid); - dataiterator_skip_solvable(&di); - } - dataiterator_free(&di); - if (!q.count) - return 0; - if (q.count > 1) - queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q)); - else - queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]); - queue_free(&q); - return SELECTION_FILELIST; -} - -static char * -splitrel(char *rname, char *r, int *rflagsp) -{ - int nend = r - rname; - int rflags = 0; - if (nend && *r == '=' && r[-1] == '!') - { - nend--; - r++; - rflags = REL_LT|REL_GT; - } - for (; *r; r++) - { - if (*r == '<') - rflags |= REL_LT; - else if (*r == '=') - rflags |= REL_EQ; - else if (*r == '>') - rflags |= REL_GT; - else - break; - } - while (*r && (*r == ' ' || *r == '\t')) - r++; - while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t')) - nend--; - if (!*rname || !*r) - return 0; - *rflagsp = rflags; - rname[nend] = 0; - return r; -} - -static int -selection_rel(Pool *pool, Queue *selection, const char *name, int flags) -{ - int ret, rflags = 0; - char *r, *rname; - - /* relation case, support: - * depglob rel - * depglob.arch rel - */ - rname = solv_strdup(name); - if ((r = strpbrk(rname, "<=>")) != 0) - { - if ((r = splitrel(rname, r, &rflags)) == 0) - { - solv_free(rname); - return 0; - } - } - if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0) - { - if (rflags) - selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1)); - solv_free(rname); - return ret | SELECTION_REL; - } - solv_free(rname); - return 0; -} - -#if defined(MULTI_SEMANTICS) -# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE) -#elif defined(DEBIAN) -# define EVRCMP_DEPCMP EVRCMP_COMPARE -#else -# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE -#endif - -/* magic epoch promotion code, works only for SELECTION_NAME selections */ -static void -selection_filter_evr(Pool *pool, Queue *selection, char *evr) -{ - int i, j; - Queue q; - Id qbuf[10]; - - queue_init(&q); - queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf)); - for (i = j = 0; i < selection->count; i += 2) - { - Id select = selection->elements[i] & SOLVER_SELECTMASK; - Id id = selection->elements[i + 1]; - Id p, pp; - const char *lastepoch = 0; - int lastepochlen = 0; - - queue_empty(&q); - FOR_JOB_SELECT(p, pp, select, id) - { - Solvable *s = pool->solvables + p; - const char *sevr = pool_id2str(pool, s->evr); - const char *sp; - for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++) - ; - if (*sp != ':') - sp = sevr; - /* compare vr part */ - if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0) - { - int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP); - if (r == -1 || r == 1) - continue; /* solvable does not match vr */ - } - queue_push(&q, p); - if (sp > sevr) - { - while (sevr < sp && *sevr == '0') /* normalize epoch */ - sevr++; - } - if (!lastepoch) - { - lastepoch = sevr; - lastepochlen = sp - sevr; - } - else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0) - lastepochlen = -1; /* multiple different epochs */ - } - if (!lastepoch || lastepochlen == 0) - id = pool_str2id(pool, evr, 1); /* no match at all or zero epoch */ - else if (lastepochlen >= 0) - { - /* found exactly one epoch, simply prepend */ - char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2); - strncpy(evrx, lastepoch, lastepochlen + 1); - strcpy(evrx + lastepochlen + 1, evr); - id = pool_str2id(pool, evrx, 1); - solv_free(evrx); - } - else - { - /* multiple epochs in multiple solvables, convert to list of solvables */ - selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF; - selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q); - j += 2; - continue; - } - queue_empty(&q); - queue_push2(&q, selection->elements[i], selection->elements[i + 1]); - selection_filter_rel(pool, &q, REL_EQ, id); - if (!q.count) - continue; /* oops, no match */ - selection->elements[j] = q.elements[0]; - selection->elements[j + 1] = q.elements[1]; - j += 2; - } - queue_truncate(selection, j); - queue_free(&q); -} - -/* match the "canonical" name of the package */ -static int -selection_canon(Pool *pool, Queue *selection, const char *name, int flags) -{ - char *rname, *r, *r2; - Id archid = 0; - int ret; - - /* - * nameglob-version - * nameglob-version.arch - * nameglob-version-release - * nameglob-version-release.arch - */ - flags |= SELECTION_NAME; - flags &= ~SELECTION_PROVIDES; - - if (pool->disttype == DISTTYPE_DEB) - { - if ((r = strchr(name, '_')) == 0) - return 0; - rname = solv_strdup(name); /* so we can modify it */ - r = rname + (r - name); - *r++ = 0; - if ((ret = selection_depglob(pool, selection, rname, flags)) == 0) - { - solv_free(rname); - return 0; - } - /* is there a vaild arch? */ - if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - *r2 = 0; /* split off */ - selection_filter_rel(pool, selection, REL_ARCH, archid); - } - selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1)); - solv_free(rname); - return ret | SELECTION_CANON; - } - - if (pool->disttype == DISTTYPE_HAIKU) - { - if ((r = strchr(name, '-')) == 0) - return 0; - rname = solv_strdup(name); /* so we can modify it */ - r = rname + (r - name); - *r++ = 0; - if ((ret = selection_depglob(pool, selection, rname, flags)) == 0) - { - solv_free(rname); - return 0; - } - /* is there a vaild arch? */ - if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - *r2 = 0; /* split off */ - selection_filter_rel(pool, selection, REL_ARCH, archid); - } - selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1)); - solv_free(rname); - return ret | SELECTION_CANON; - } - - if ((r = strrchr(name, '-')) == 0) - return 0; - rname = solv_strdup(name); /* so we can modify it */ - r = rname + (r - name); - *r = 0; - - /* split off potential arch part from version */ - if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0) - *r2 = 0; /* found valid arch, split it off */ - if (archid == ARCH_SRC || archid == ARCH_NOSRC) - flags |= SELECTION_SOURCE_ONLY; - - /* try with just the version */ - if ((ret = selection_depglob(pool, selection, rname, flags)) == 0) - { - /* no luck, try with version-release */ - if ((r2 = strrchr(rname, '-')) == 0) - { - solv_free(rname); - return 0; - } - *r = '-'; - *r2 = 0; - r = r2; - if ((ret = selection_depglob(pool, selection, rname, flags)) == 0) - { - solv_free(rname); - return 0; - } - } - if (archid) - selection_filter_rel(pool, selection, REL_ARCH, archid); - selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */ - solv_free(rname); - return ret | SELECTION_CANON; -} - -int -selection_make(Pool *pool, Queue *selection, const char *name, int flags) -{ - int ret = 0; - - queue_empty(selection); - if ((flags & SELECTION_FILELIST) != 0) - ret = selection_filelist(pool, selection, name, flags); - if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0) - ret = selection_rel(pool, selection, name, flags); - if (!ret) - ret = selection_depglob_arch(pool, selection, name, flags); - if (!ret && (flags & SELECTION_CANON) != 0) - ret = selection_canon(pool, selection, name, flags); - if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0) - selection_filter_installed(pool, selection); - if (ret && !selection->count) - ret = 0; /* no match -> always return zero */ - if (ret && (flags & SELECTION_FLAT) != 0) - selection_flatten(pool, selection); - return ret; -} - -static int -matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags) -{ - if (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH) - { - if (matchdep(pool, rd->name, rname, rflags, revr, flags)) - return 1; - if (matchdep(pool, rd->evr, rname, rflags, revr, flags)) - return 1; - return 0; - } - if (rd->flags == REL_ARCH) - return matchdep(pool, rd->name, rname, rflags, revr, flags); - if (!matchdep(pool, rd->name, rname, rflags, revr, flags)) - return 0; - if (rflags) - { - /* XXX: need pool_match_flags_evr here */ - if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id)) - return 0; - } - return 1; - } - if (flags & SELECTION_GLOB) - { - int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0; - return fnmatch(rname, pool_id2str(pool, id), globflags) == 0 ? 1 : 0; - } - if (flags & SELECTION_NOCASE) - return strcasecmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0; - return strcmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0; -} - -/* - * select against the dependencies in keyname - * like SELECTION_REL and SELECTION_PROVIDES, but with the - * deps in keyname instead of provides. - */ -int -selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker) -{ - char *rname, *r; - int rflags = 0; - Id p; - Queue q; - - queue_empty(selection); - rname = solv_strdup(name); - if ((r = strpbrk(rname, "<=>")) != 0) - { - if ((r = splitrel(rname, r, &rflags)) == 0) - { - solv_free(rname); - return 0; - } - } - if ((flags & SELECTION_GLOB) != 0 && !strpbrk(name, "[*?") != 0) - flags &= ~SELECTION_GLOB; - - queue_init(&q); - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - int i; - - if (s->repo != pool->installed && !pool_installable(pool, s)) - { - if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)) - continue; - if (pool_disabled_solvable(pool, s)) - continue; - } - if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) - continue; - if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE)) - continue; - queue_empty(&q); - repo_lookup_deparray(s->repo, p, keyname, &q, marker); - for (i = 0; i < q.count; i++) - { - Id id = q.elements[i]; - if (matchdep(pool, id, rname, rflags, r, flags)) - break; - } - if (i < q.count) - queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p); - } - queue_free(&q); - solv_free(rname); - if (!selection->count) - return 0; - if ((flags & SELECTION_FLAT) != 0) - selection_flatten(pool, selection); - return SELECTION_PROVIDES; -} - -static inline int -pool_is_kind(Pool *pool, Id name, Id kind) -{ - const char *n; - if (!kind) - return 1; - n = pool_id2str(pool, name); - if (kind != 1) - { - const char *kn = pool_id2str(pool, kind); - int knl = strlen(kn); - return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0; - } - else - { - if (*n == ':') - return 1; - while(*n >= 'a' && *n <= 'z') - n++; - return *n == ':' ? 0 : 1; - } -} - -void -selection_filter(Pool *pool, Queue *sel1, Queue *sel2) -{ - int i, j, miss; - Id p, pp, q1filled = 0; - Queue q1; - Map m2; - Id setflags = 0; - - if (!sel1->count || !sel2->count) - { - queue_empty(sel1); - return; - } - if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL) - { - /* XXX: not 100% correct, but very useful */ - p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK); /* job & jobflags */ - queue_free(sel1); - queue_init_clone(sel1, sel2); - for (i = 0; i < sel1->count; i += 2) - sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ; - return; - } - queue_init(&q1); - map_init(&m2, pool->nsolvables); - for (i = 0; i < sel2->count; i += 2) - { - Id select = sel2->elements[i] & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE_ALL) - { - queue_free(&q1); - map_free(&m2); - return; - } - if (select == SOLVER_SOLVABLE_REPO) - { - Solvable *s; - Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]); - if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - map_set(&m2, p); - } - else - { - if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1])) - { - Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]); - if (rd->flags == REL_ARCH && rd->name == 0) - { - /* special arch filter */ - if (!q1filled++) - selection_solvables(pool, sel1, &q1); - for (j = 0; j < q1.count; j++) - { - Id p = q1.elements[j]; - Solvable *s = pool->solvables + p; - if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC)) - map_set(&m2, p); - } - continue; - } - else if (rd->flags == REL_KIND && rd->name == 0) - { - /* special kind filter */ - if (!q1filled++) - selection_solvables(pool, sel1, &q1); - for (j = 0; j < q1.count; j++) - { - Id p = q1.elements[j]; - Solvable *s = pool->solvables + p; - if (pool_is_kind(pool, s->name, rd->evr)) - map_set(&m2, p); - } - continue; - } - } - FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1]) - map_set(&m2, p); - } - } - if (sel2->count == 2) /* XXX: AND all setmasks instead? */ - setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET; - for (i = j = 0; i < sel1->count; i += 2) - { - Id select = sel1->elements[i] & SOLVER_SELECTMASK; - queue_empty(&q1); - miss = 0; - if (select == SOLVER_SOLVABLE_ALL) - { - FOR_POOL_SOLVABLES(p) - { - if (map_tst(&m2, p)) - queue_push(&q1, p); - else - miss = 1; - } - } - else if (select == SOLVER_SOLVABLE_REPO) - { - Solvable *s; - Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]); - if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - { - if (map_tst(&m2, p)) - queue_push(&q1, p); - else - miss = 1; - } - } - else - { - FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1]) - { - if (map_tst(&m2, p)) - queue_pushunique(&q1, p); - else - miss = 1; - } - } - if (!q1.count) - continue; - if (!miss) - { - sel1->elements[j] = sel1->elements[i] | setflags; - sel1->elements[j + 1] = sel1->elements[i + 1]; - } - else if (q1.count > 1) - { - sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags; - sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1); - } - else - { - sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags; - sel1->elements[j + 1] = q1.elements[0]; - } - j += 2; - } - queue_truncate(sel1, j); - queue_free(&q1); - map_free(&m2); -} - -void -selection_add(Pool *pool, Queue *sel1, Queue *sel2) -{ - int i; - for (i = 0; i < sel2->count; i++) - queue_push(sel1, sel2->elements[i]); -} - -const char * -pool_selection2str(Pool *pool, Queue *selection, Id flagmask) -{ - char *s; - const char *s2; - int i; - s = pool_tmpjoin(pool, 0, 0, 0); - for (i = 0; i < selection->count; i += 2) - { - Id how = selection->elements[i]; - if (*s) - s = pool_tmpappend(pool, s, " + ", 0); - s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]); - s = pool_tmpappend(pool, s, s2, 0); - pool_freetmpspace(pool, s2); - how &= flagmask & SOLVER_SETMASK; - if (how) - { - int o = strlen(s); - s = pool_tmpappend(pool, s, " ", 0); - if (how & SOLVER_SETEV) - s = pool_tmpappend(pool, s, ",setev", 0); - if (how & SOLVER_SETEVR) - s = pool_tmpappend(pool, s, ",setevr", 0); - if (how & SOLVER_SETARCH) - s = pool_tmpappend(pool, s, ",setarch", 0); - if (how & SOLVER_SETVENDOR) - s = pool_tmpappend(pool, s, ",setvendor", 0); - if (how & SOLVER_SETREPO) - s = pool_tmpappend(pool, s, ",setrepo", 0); - if (how & SOLVER_NOAUTOSET) - s = pool_tmpappend(pool, s, ",noautoset", 0); - if (s[o + 1] != ',') - s = pool_tmpappend(pool, s, ",?", 0); - s[o + 1] = '['; - s = pool_tmpappend(pool, s, "]", 0); - } - } - return s; -} - diff --git a/libsolv-0.6.15/src/selection.h b/libsolv-0.6.15/src/selection.h deleted file mode 100644 index fc2b15d..0000000 --- a/libsolv-0.6.15/src/selection.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * selection.h - * - */ - -#ifndef LIBSOLV_SELECTION_H -#define LIBSOLV_SELECTION_H - -#include "pool.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SELECTION_NAME (1 << 0) -#define SELECTION_PROVIDES (1 << 1) -#define SELECTION_FILELIST (1 << 2) -#define SELECTION_CANON (1 << 3) -#define SELECTION_DOTARCH (1 << 4) -#define SELECTION_REL (1 << 5) - -#define SELECTION_INSTALLED_ONLY (1 << 8) -#define SELECTION_GLOB (1 << 9) -#define SELECTION_FLAT (1 << 10) -#define SELECTION_NOCASE (1 << 11) -#define SELECTION_SOURCE_ONLY (1 << 12) -#define SELECTION_WITH_SOURCE (1 << 13) -#define SELECTION_SKIP_KIND (1 << 14) - -extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags); -extern int selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker); - -extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2); -extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2); -extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs); - -extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libsolv-0.6.15/src/solver_private.h b/libsolv-0.6.15/src/solver_private.h deleted file mode 100644 index fe80881..0000000 --- a/libsolv-0.6.15/src/solver_private.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2011, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * solver_private.h - private functions - * - */ - -#ifndef LIBSOLV_SOLVER_PRIVATE_H -#define LIBSOLV_SOLVER_PRIVATE_H - -extern void solver_run_sat(Solver *solv, int disablerules, int doweak); -extern void solver_reset(Solver *solv); - -extern int solver_splitprovides(Solver *solv, Id dep, Map *m); - -static inline int -solver_dep_fulfilled(Solver *solv, Id dep) -{ - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags == REL_COND) - { - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - if (solver_dep_fulfilled(solv, rd2->name)) - return solver_dep_fulfilled(solv, rd->name); - return solver_dep_fulfilled(solv, rd2->evr); - } - } - if (solver_dep_fulfilled(solv, rd->name)) - return 1; - return !solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_AND) - { - if (!solver_dep_fulfilled(solv, rd->name)) - return 0; - return solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_OR) - { - if (solver_dep_fulfilled(solv, rd->name)) - return 1; - return solver_dep_fulfilled(solv, rd->evr); - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return solver_splitprovides(solv, rd->evr, 0); - } - FOR_PROVIDES(p, pp, dep) - { - if (solv->decisionmap[p] > 0) - return 1; - } - return 0; -} - -static inline int -solver_is_supplementing(Solver *solv, Solvable *s) -{ - Id sup, *supp; - if (!s->supplements) - return 0; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (solver_dep_fulfilled(solv, sup)) - return 1; - return 0; -} - -static inline int -solver_is_enhancing(Solver *solv, Solvable *s) -{ - Id enh, *enhp; - if (!s->enhances) - return 0; - enhp = s->repo->idarraydata + s->enhances; - while ((enh = *enhp++) != 0) - if (solver_dep_fulfilled(solv, enh)) - return 1; - return 0; -} - -#endif /* LIBSOLV_SOLVER_PRIVATE_H */ diff --git a/libsolv-0.6.15/src/solvversion.h.in b/libsolv-0.6.15/src/solvversion.h.in deleted file mode 100644 index 268219c..0000000 --- a/libsolv-0.6.15/src/solvversion.h.in +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2007, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -/* - * solvversion.h - * - */ - -#ifndef LIBSOLV_SOLVVERSION_H -#define LIBSOLV_SOLVVERSION_H - -#define LIBSOLV_VERSION_STRING "@VERSION@" -#define LIBSOLV_VERSION_MAJOR @LIBSOLV_MAJOR@ -#define LIBSOLV_VERSION_MINOR @LIBSOLV_MINOR@ -#define LIBSOLV_VERSION_PATCH @LIBSOLV_PATCH@ -#define LIBSOLV_VERSION (LIBSOLV_VERSION_MAJOR * 10000 + LIBSOLV_VERSION_MINOR * 100 + LIBSOLV_VERSION_PATCH) - -extern const char solv_version[]; -extern int solv_version_major; -extern int solv_version_minor; -extern int solv_version_patch; - -#endif diff --git a/libsolv-0.6.15/tools/common_write.c b/libsolv-0.6.15/tools/common_write.c deleted file mode 100644 index 6de8a69..0000000 --- a/libsolv-0.6.15/tools/common_write.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2007, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -#include -#include -#include -#include -#include -#include - -#include "pool.h" -#include "repo.h" -#include "repo_write.h" -#include "common_write.h" - -#define LIBSOLV_TOOLVERSION "1.0" - -static Id verticals[] = { - SOLVABLE_AUTHORS, - SOLVABLE_DESCRIPTION, - SOLVABLE_MESSAGEDEL, - SOLVABLE_MESSAGEINS, - SOLVABLE_EULA, - SOLVABLE_DISKUSAGE, - SOLVABLE_FILELIST, - SOLVABLE_CHANGELOG_AUTHOR, - SOLVABLE_CHANGELOG_TEXT, - 0 -}; - -static char *languagetags[] = { - "solvable:summary:", - "solvable:description:", - "solvable:messageins:", - "solvable:messagedel:", - "solvable:eula:", - 0 -}; - -static int test_separate = 0; - -struct keyfilter_data { - char **languages; - int nlanguages; - int haveaddedfileprovides; - int haveexternal; -}; - -static int -keyfilter_solv(Repo *data, Repokey *key, void *kfdata) -{ - struct keyfilter_data *kd = kfdata; - int i; - const char *keyname; - - if (test_separate && key->storage != KEY_STORAGE_SOLVABLE) - return KEY_STORAGE_DROPPED; - if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES) - return KEY_STORAGE_DROPPED; - if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL) - return KEY_STORAGE_DROPPED; - for (i = 0; verticals[i]; i++) - if (key->name == verticals[i]) - return KEY_STORAGE_VERTICAL_OFFSET; - keyname = pool_id2str(data->pool, key->name); - for (i = 0; languagetags[i] != 0; i++) - if (!strncmp(keyname, languagetags[i], strlen(languagetags[i]))) - return KEY_STORAGE_VERTICAL_OFFSET; - return KEY_STORAGE_INCORE; -} - -static int -keyfilter_attr(Repo *data, Repokey *key, void *kfdata) -{ - int i; - const char *keyname; - if (key->storage == KEY_STORAGE_SOLVABLE) - return KEY_STORAGE_DROPPED; - /* those must only be in the main solv file */ - if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_TOOLVERSION) - return KEY_STORAGE_DROPPED; - for (i = 0; verticals[i]; i++) - if (key->name == verticals[i]) - return KEY_STORAGE_VERTICAL_OFFSET; - keyname = pool_id2str(data->pool, key->name); - for (i = 0; languagetags[i] != 0; i++) - if (!strncmp(keyname, languagetags[i], strlen(languagetags[i]))) - return KEY_STORAGE_VERTICAL_OFFSET; - return KEY_STORAGE_INCORE; -} - -static int -keyfilter_language(Repo *repo, Repokey *key, void *kfdata) -{ - Pool *pool = repo->pool; - const char *name, *p; - char *lang = kfdata; - int i; - - name = pool_id2str(repo->pool, key->name); - p = strrchr(name, ':'); - if (!p || strcmp(p + 1, lang) != 0) - return KEY_STORAGE_DROPPED; - for (i = 0; verticals[i]; i++) - { - const char *vname = pool_id2str(pool, verticals[i]); - if (!strncmp(name, vname, p - name) && vname[p - name] == 0) - return KEY_STORAGE_VERTICAL_OFFSET; - } - return KEY_STORAGE_INCORE; -} - -static int -keyfilter_DU(Repo *repo, Repokey *key, void *kfdata) -{ - int i; - if (key->name != SOLVABLE_DISKUSAGE) - return KEY_STORAGE_DROPPED; - for (i = 0; verticals[i]; i++) - if (key->name == verticals[i]) - return KEY_STORAGE_VERTICAL_OFFSET; - return KEY_STORAGE_INCORE; -} - -static int -keyfilter_FL(Repo *repo, Repokey *key, void *kfdata) -{ - int i; - if (key->name != SOLVABLE_FILELIST) - return KEY_STORAGE_DROPPED; - for (i = 0; verticals[i]; i++) - if (key->name == verticals[i]) - return KEY_STORAGE_VERTICAL_OFFSET; - return KEY_STORAGE_INCORE; -} - -static int -keyfilter_other(Repo *repo, Repokey *key, void *kfdata) -{ - const char *name, *p; - struct keyfilter_data *kd = kfdata; - int i; - - if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES) - return KEY_STORAGE_DROPPED; - if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL) - return KEY_STORAGE_DROPPED; - - if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE) - return KEY_STORAGE_DROPPED; - - name = pool_id2str(repo->pool, key->name); - p = strrchr(name, ':'); - if (p) - { - for (i = 0; i < kd->nlanguages; i++) - if (!strcmp(p + 1, kd->languages[i])) - return KEY_STORAGE_DROPPED; - } - for (i = 0; verticals[i]; i++) - if (key->name == verticals[i]) - return KEY_STORAGE_VERTICAL_OFFSET; - return KEY_STORAGE_INCORE; -} - -/* - * Write to stdout - * If is given, write attributes to - * If is given, split attributes - */ - -#define REPODATAFILE_BLOCK 15 - -static void -write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location) -{ - Id h; - Queue keyq; - - queue_init(&keyq); - if (repo_write_filtered(repo, fp, keyfilter, kfdata, &keyq) != 0) - { - fprintf(stderr, "repo_write failed\n"); - exit(1); - } - h = repodata_new_handle(info); - if (keyq.count) - repodata_set_idarray(info, h, REPOSITORY_KEYS, &keyq); - queue_free(&keyq); - repodata_set_str(info, h, REPOSITORY_LOCATION, location); - repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h); -} - -void -tool_write(Repo *repo, const char *basename, const char *attrname) -{ - Repodata *data; - Repodata *info = 0; - Repokey *key; - char **languages = 0; - int nlanguages = 0; - int i, j, k, l; - struct keyfilter_data kd; - Queue addedfileprovides; - - memset(&kd, 0, sizeof(kd)); - info = repo_add_repodata(repo, 0); - repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION); - queue_init(&addedfileprovides); - pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0); - if (addedfileprovides.count) - { - kd.haveaddedfileprovides = 1; - repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides); - } - queue_free(&addedfileprovides); - - pool_freeidhashes(repo->pool); /* free some mem */ - - if (basename) - { - char fn[4096]; - FILE *fp; - int has_DU = 0; - int has_FL = 0; - - /* find languages and other info */ - FOR_REPODATAS(repo, i, data) - { - for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++) - { - const char *keyname = pool_id2str(repo->pool, key->name); - if (key->name == SOLVABLE_DISKUSAGE) - has_DU = 1; - if (key->name == SOLVABLE_FILELIST) - has_FL = 1; - for (k = 0; languagetags[k] != 0; k++) - if (!strncmp(keyname, languagetags[k], strlen(languagetags[k]))) - break; - if (!languagetags[k]) - continue; - l = strlen(languagetags[k]); - if (strlen(keyname + l) > 5) - continue; - for (k = 0; k < nlanguages; k++) - if (!strcmp(languages[k], keyname + l)) - break; - if (k < nlanguages) - continue; - languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *)); - languages[nlanguages++] = strdup(keyname + l); - } - } - /* write language subfiles */ - for (i = 0; i < nlanguages; i++) - { - sprintf(fn, "%s.%s.solv", basename, languages[i]); - if (!(fp = fopen(fn, "w"))) - { - perror(fn); - exit(1); - } - write_info(repo, fp, keyfilter_language, languages[i], info, fn); - fclose(fp); - kd.haveexternal = 1; - } - /* write DU subfile */ - if (has_DU) - { - sprintf(fn, "%s.DU.solv", basename); - if (!(fp = fopen(fn, "w"))) - { - perror(fn); - exit(1); - } - write_info(repo, fp, keyfilter_DU, 0, info, fn); - fclose(fp); - kd.haveexternal = 1; - } - /* write filelist */ - if (has_FL) - { - sprintf(fn, "%s.FL.solv", basename); - if (!(fp = fopen(fn, "w"))) - { - perror(fn); - exit(1); - } - write_info(repo, fp, keyfilter_FL, 0, info, fn); - fclose(fp); - kd.haveexternal = 1; - } - /* write everything else */ - sprintf(fn, "%s.solv", basename); - if (!(fp = fopen(fn, "w"))) - { - perror(fn); - exit(1); - } - kd.languages = languages; - kd.nlanguages = nlanguages; - repodata_internalize(info); - if (repo_write_filtered(repo, fp, keyfilter_other, &kd, 0) != 0) - { - fprintf(stderr, "repo_write failed\n"); - exit(1); - } - if (fclose(fp) != 0) - { - perror("fclose"); - exit(1); - } - for (i = 0; i < nlanguages; i++) - free(languages[i]); - solv_free(languages); - repodata_free(info); - } - if (attrname) - { - FILE *fp; - test_separate = 1; - fp = fopen(attrname, "w"); - write_info(repo, fp, keyfilter_attr, 0, info, attrname); - fclose(fp); - kd.haveexternal = 1; - } - repodata_internalize(info); - if (repo_write_filtered(repo, stdout, keyfilter_solv, &kd, 0) != 0) - { - fprintf(stderr, "repo_write failed\n"); - exit(1); - } - repodata_free(info); -} diff --git a/libsolv-0.6.15/tools/patchcheck.c b/libsolv-0.6.15/tools/patchcheck.c deleted file mode 100644 index 6a5c3f7..0000000 --- a/libsolv-0.6.15/tools/patchcheck.c +++ /dev/null @@ -1,642 +0,0 @@ -/* vim: sw=2 et - */ - -/* - * Copyright (c) 2009, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include - -#include "pool.h" -#include "evr.h" -#include "poolarch.h" -#include "repo_solv.h" -#ifdef ENABLE_SUSEREPO -#include "repo_susetags.h" -#endif -#ifdef ENABLE_RPMMD -#include "repo_updateinfoxml.h" -#include "repo_rpmmd.h" -#endif -#include "solver.h" -#include "solverdebug.h" - -#include "solv_xfopen.h" - -void -showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys) -{ - Pool *pool = solv->pool; - Queue rids, rinfo; - Id problem = 0; - int jj; - int rerun = 0; - - queue_init(&rids); - queue_init(&rinfo); - printf("can't install %s:\n", pool_solvable2str(pool, s)); - while ((problem = solver_next_problem(solv, problem)) != 0) - { - solver_findallproblemrules(solv, problem, &rids); - for (jj = 0; jj < rids.count; jj++) - { - Id probr = rids.elements[jj]; - int k, l; - - queue_empty(&rinfo); - solver_allruleinfos(solv, probr, &rinfo); - for (k = 0; k < rinfo.count; k += 4) - { - Id dep, source, target; - source = rinfo.elements[k + 1]; - target = rinfo.elements[k + 2]; - dep = rinfo.elements[k + 3]; - switch (rinfo.elements[k]) - { - case SOLVER_RULE_DISTUPGRADE: - break; - case SOLVER_RULE_INFARCH: - printf(" %s has inferior architecture\n", pool_solvid2str(pool, source)); - break; - case SOLVER_RULE_UPDATE: - printf(" update rule for %s\n", pool_solvid2str(pool, source)); - if (badguys) - queue_pushunique(badguys, source); - if (!cand) - break; - /* only drop update problem packages from cand so that we see all problems of this patch */ - for (l = 0; l < cand->count; l++) - if (cand->elements[l] == source || cand->elements[l] == -source) - break; - if (l == cand->count) - break; - if (!rerun) - { - for (l = 0; l < cand->count; l++) - if (cand->elements[l] < 0) - cand->elements[l] = -cand->elements[l]; - rerun = 1; - } - for (l = 0; l < cand->count; l++) - if (cand->elements[l] == source) - { - cand->elements[l] = -source; - } - break; - case SOLVER_RULE_JOB: - case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM: - case SOLVER_RULE_JOB_UNKNOWN_PACKAGE: - case SOLVER_RULE_JOB_UNSUPPORTED: - break; - case SOLVER_RULE_RPM: - printf(" some dependency problem\n"); - break; - case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP: - printf(" nothing provides requested %s\n", pool_dep2str(pool, dep)); - break; - case SOLVER_RULE_RPM_NOT_INSTALLABLE: - printf(" package %s is not installable\n", pool_solvid2str(pool, source)); - break; - case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP: - printf(" nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, source)); - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (!ISRELDEP(rd->name)) - { - Id rp, rpp; - FOR_PROVIDES(rp, rpp, rd->name) - printf(" (we have %s)\n", pool_solvid2str(pool, rp)); - } - } - break; - case SOLVER_RULE_RPM_SAME_NAME: - printf(" cannot install both %s and %s\n", pool_solvid2str(pool, source), pool_solvid2str(pool, target)); - break; - case SOLVER_RULE_RPM_PACKAGE_CONFLICT: - printf(" package %s conflicts with %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target)); - break; - case SOLVER_RULE_RPM_PACKAGE_OBSOLETES: - printf(" package %s obsoletes %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target)); - break; - case SOLVER_RULE_RPM_PACKAGE_REQUIRES: - printf(" package %s requires %s, but none of the providers can be installed\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep)); - break; - case SOLVER_RULE_RPM_SELF_CONFLICT: - printf(" package %s conflicts with %s provided by itself\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep)); - break; - } - } - } - } - queue_free(&rids); - queue_free(&rinfo); -} - -void -toinst(Solver *solv, Repo *repo, Repo *instrepo) -{ - Pool *pool = solv->pool; - Queue q; - int k; - Id p; - - queue_init(&q); - solver_get_decisionqueue(solv, &q); - for (k = 0; k < q.count; k++) - { - p = q.elements[k]; - if (p < 0 || p == SYSTEMSOLVABLE) - continue; - - /* printf(" toinstall %s\n", pool_solvid2str(pool, p));*/ - /* oh my! */ - pool->solvables[p].repo = instrepo; - } - queue_free(&q); -} - -void -dump_instrepo(Repo *instrepo, Pool *pool) -{ - Solvable *s; - Id p; - - printf("instrepo..\n"); - FOR_REPO_SOLVABLES(instrepo, p, s) - printf(" %s\n", pool_solvable2str(pool, s)); - printf("done.\n"); -} - -void -frominst(Solver *solv, Repo *repo, Repo *instrepo) -{ - Pool *pool = solv->pool; - int k; - - for (k = 1; k < pool->nsolvables; k++) - if (pool->solvables[k].repo == instrepo) - pool->solvables[k].repo = repo; -} - -void -usage(char** argv) -{ - - printf("%s: [--install-available] [repos] [--updaterepos] [repos]...\n" - "\t --install-available: installation repository is available during update\n" - "\t repos: repository ending in\n" - "\t\tpackages, packages.gz, primary.xml.gz, updateinfo.xml.gz or .solv\n", - argv[0]); - - exit(1); -} - -typedef struct { - int updatestart; - int shown; - int status; - int install_available; - Repo *repo; - Repo *instrepo; -} context_t; - -#define SHOW_PATCH(c) if (!(c)->shown++) printf("%s:\n", pool_solvable2str(pool, s)); -#define PERF_DEBUGGING 0 - -static Pool *pool; - -void -test_all_old_patches_included(context_t *c, Id pid) -{ - Id p, pp; - Id con, *conp; - Solvable *s = pool->solvables + pid; - /* Test 1: are all old patches included */ - FOR_PROVIDES(p, pp, s->name) - { - Solvable *s2 = pool->solvables + p; - Id con2, *conp2; - - if (!s2->conflicts) - continue; - if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0) - continue; - conp2 = s2->repo->idarraydata + s2->conflicts; - while ((con2 = *conp2++) != 0) - { - Reldep *rd2, *rd; - if (!ISRELDEP(con2)) - continue; - rd2 = GETRELDEP(pool, con2); - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - if (!ISRELDEP(con)) - continue; - rd = GETRELDEP(pool, con); - if (rd->name == rd2->name) - break; - } - if (!con) - { - SHOW_PATCH(c); - printf(" %s contained %s\n", pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name)); - } - else - { - if (pool_evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0) - { - SHOW_PATCH(c); - printf(" %s required newer version %s-%s of %s-%s\n", - pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name), pool_dep2str(pool, rd2->evr), - pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr)); - } - } - - } - } -} - -void -test_all_packages_installable(context_t *c, Id pid) -{ - Solver *solv; - Queue job; - Id p, pp; - Id con, *conp; - unsigned int now, solver_runs; - int i; - Solvable *s = pool->solvables + pid; - - queue_init(&job); - - now = solv_timems(0); - solver_runs = 0; - - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - FOR_PROVIDES(p, pp, con) - { - queue_empty(&job); - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK); - queue_push(&job, p); - - /* also set up some minimal system */ - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); - queue_push(&job, pool_str2id(pool, "rpm", 1)); - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); - queue_push(&job, pool_str2id(pool, "aaa_base", 1)); - - solv = solver_create(pool); - /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */ - ++solver_runs; - if (solver_solve(solv, &job)) - { - c->status = 1; - printf("error installing original package\n"); - showproblems(solv, s, 0, 0); - } - toinst(solv, c->repo, c->instrepo); - solver_free(solv); - -#if 0 - dump_instrepo(instrepo, pool); - -#endif - if (!c->install_available) - { - queue_empty(&job); - for (i = 1; i < c->updatestart; i++) - { - if (pool->solvables[i].repo != c->repo || i == pid) - continue; - queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE); - queue_push(&job, i); - } - } - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE); - queue_push(&job, pid); - solv = solver_create(pool); - /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */ - ++solver_runs; - if (solver_solve(solv, &job)) - { - c->status = 1; - showproblems(solv, s, 0, 0); - } - frominst(solv, c->repo, c->instrepo); - solver_free(solv); - } - } - - if (PERF_DEBUGGING) - printf(" test_all_packages_installable took %d ms in %d runs\n", solv_timems(now), solver_runs); -} - -void -test_can_upgrade_all_packages(context_t *c, Id pid) -{ - Solver *solv; - Id p; - Id con, *conp; - Queue job; - Queue cand; - Queue badguys; - int i, j; - unsigned int now, solver_runs; - Solvable *s = pool->solvables + pid; - - queue_init(&job); - queue_init(&cand); - queue_init(&badguys); - - now = solv_timems(0); - solver_runs = 0; - - /* Test 3: can we upgrade all packages? */ - for (p = 1; p < pool->nsolvables; p++) - { - Solvable *s = pool->solvables + p; - if (!s->repo) - continue; - if (strchr(pool_id2str(pool, s->name), ':')) - continue; /* only packages, please */ - if (!pool_installable(pool, s)) - continue; - queue_push(&cand, p); - } - while (cand.count) - { - solv = solver_create(pool); - queue_empty(&job); - for (i = 0; i < badguys.count; i++) - { - queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK); - queue_push(&job, badguys.elements[i]); - } - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK); - queue_push(&job, con); - } - for (i = 0; i < cand.count; i++) - { - p = cand.elements[i]; - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK); - queue_push(&job, p); - } - ++solver_runs; - solver_solve(solv, &job); -#if 0 - solver_printdecisions(solv); -#endif - /* put packages into installed repo and prune them from cand */ - toinst(solv, c->repo, c->instrepo); - for (i = 0; i < cand.count; i++) - { - p = cand.elements[i]; - if (p > 0 && solver_get_decisionlevel(solv, p) > 0) - cand.elements[i] = -p; /* drop candidate */ - } - solver_free(solv); - - /* now the interesting part: test patch */ - queue_empty(&job); - if (!c->install_available) - { - for (i = 1; i < c->updatestart; i++) - { - if (pool->solvables[i].repo != c->repo || i == pid) - continue; - queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE); - queue_push(&job, i); - } - } - queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE); - queue_push(&job, pid); - solv = solver_create(pool); - solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); - ++solver_runs; - if (solver_solve(solv, &job)) - { - c->status = 1; - showproblems(solv, s, &cand, &badguys); - } - frominst(solv, c->repo, c->instrepo); - solver_free(solv); - /* now drop all negative elements from cand */ - for (i = j = 0; i < cand.count; i++) - { - if (cand.elements[i] < 0) - continue; - cand.elements[j++] = cand.elements[i]; - } - if (i == j) - break; /* no progress */ - cand.count = j; - } - if (PERF_DEBUGGING) - printf(" test_can_upgrade_all_packages took %d ms in %d runs\n", solv_timems(now), solver_runs); -} - -void -test_no_ga_package_fulfills_dependency(context_t *c, Id pid) -{ - Id con, *conp; - Solvable *s = pool->solvables + pid; - - /* Test 4: no GA package fulfills patch dependency */ - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - Reldep *rd; - Id rp, rpp; - - if (!ISRELDEP(con)) - continue; - rd = GETRELDEP(pool, con); - FOR_PROVIDES(rp, rpp, rd->name) - { - Solvable *s2 = pool_id2solvable(pool, rp); - if (rp < c->updatestart - && pool_evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0 - && pool_match_nevr_rel(pool, s2, rd->name) - ) - { - SHOW_PATCH(c); - printf(" conflict %s < %s satisfied by non-updated package %s\n", - pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr), pool_solvable2str(pool, s2)); - break; - } - } - } -} - -int -main(int argc, char **argv) -{ - char *arch, *mypatch; - const char *pname; - int l, r; - FILE *fp; - int i; - Id pid, p, pp; - int tests = 0; - context_t c; - static const char* langs[] = {"en"}; - - c.install_available = 0; - c.updatestart = 0; - c.status = 0; - - if (argc <= 3) - usage(argv); - - arch = argv[1]; - pool = pool_create(); - pool_setarch(pool, arch); - pool_set_languages(pool, langs, 1); - -#if 0 - pool_setdebuglevel(pool, 2); -#endif - - mypatch = argv[2]; - - c.repo = repo_create(pool, 0); - c.instrepo = repo_create(pool, 0); - for (i = 3; i < argc; i++) - { - if (!strcmp(argv[i], "--updaterepos")) - { - c.updatestart = pool->nsolvables; - continue; - } - - if (!strcmp(argv[i], "--install-available")) - { - c.install_available = 1; - continue; - } - - l = strlen(argv[i]); - if (!strcmp(argv[i], "-")) - fp = stdin; - else if ((fp = solv_xfopen(argv[i], 0)) == 0) - { - perror(argv[i]); - exit(1); - } - r = 0; - if (0) - { - } -#ifdef ENABLE_SUSEREPO - else if (l >= 8 && !strcmp(argv[i] + l - 8, "packages")) - { - r = repo_add_susetags(c.repo, fp, 0, 0, 0); - } - else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz")) - { - r = repo_add_susetags(c.repo, fp, 0, 0, 0); - } -#endif -#ifdef ENABLE_RPMMD - else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz")) - { - r = repo_add_rpmmd(c.repo, fp, 0, 0); - } - else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz")) - { - r = repo_add_updateinfoxml(c.repo, fp, 0); - } -#endif - else - r = repo_add_solv(c.repo, fp, 0); - if (r) - { - fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool)); - exit(1); - } - if (fp != stdin) - fclose(fp); - } - - pool_addfileprovides(pool); - - /* bad hack ahead: clone repo */ - c.instrepo->idarraydata = c.repo->idarraydata; - c.instrepo->idarraysize = c.repo->idarraysize; - c.instrepo->start = c.repo->start; - c.instrepo->end = c.repo->end; - c.instrepo->nsolvables = c.repo->nsolvables; /* sic! */ - pool_set_installed(pool, c.instrepo); - pool_createwhatprovides(pool); - - for (pid = 1; pid < pool->nsolvables; pid++) - { - Solvable *s; - c.shown = 0; - s = pool->solvables + pid; - if (!s->repo) - continue; - if (!pool_installable(pool, s)) - continue; - pname = pool_id2str(pool, s->name); - if (strncmp(pname, "patch:", 6) != 0) - continue; - - if (*mypatch) - { - if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0) - continue; - if (strcmp(mypatch, pname + 6) != 0) - { - l = strlen(pname + 6); - if (mypatch[l] != '-') - continue; - if (strcmp(mypatch + l + 1, pool_id2str(pool, s->evr)) != 0) - continue; - } - } - else - { - FOR_PROVIDES(p, pp, s->name) - { - Solvable *s2 = pool->solvables + p; - if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0) - break; - } - if (p) { - /* printf("found a newer one for %s\n", pname+6); */ - continue; /* found a newer one */ - } - } - tests++; - if (!s->conflicts) - continue; - -#if 0 - printf("testing patch %s-%s\n", pname + 6, pool_id2str(pool, s->evr)); -#endif - - test_all_old_patches_included(&c, pid); - test_all_packages_installable(&c, pid); - test_can_upgrade_all_packages(&c, pid); - test_no_ga_package_fulfills_dependency(&c, pid); - } - - exit(c.status); -} diff --git a/libsolv-0.6.15/tools/rpmmd2solv.c b/libsolv-0.6.15/tools/rpmmd2solv.c deleted file mode 100644 index d4fe2ff..0000000 --- a/libsolv-0.6.15/tools/rpmmd2solv.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2007, Novell Inc. - * - * This program is licensed under the BSD license, read LICENSE.BSD - * for further information - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pool.h" -#include "repo.h" -#include "repo_rpmmd.h" -#ifdef SUSE -#include "repo_autopattern.h" -#endif -#include "common_write.h" -#include "solv_xfopen.h" - - -static void -usage(int status) -{ - fprintf(stderr, "\nUsage:\n" - "rpmmd2solv [-a][-h][-n ][-l ]\n" - " reads 'primary' from a 'rpmmd' repository from and writes a .solv file to \n" - " -h : print help & exit\n" - " -n : save attributes as .attr\n" - " -l : parse localization data for \n" - ); - exit(status); -} - -int -main(int argc, char **argv) -{ - int c, flags = 0; - const char *attrname = 0; - const char *basefile = 0; - const char *dir = 0; - const char *locale = 0; -#ifdef SUSE - int add_auto = 0; -#endif - - Pool *pool = pool_create(); - Repo *repo = repo_create(pool, ""); - - while ((c = getopt (argc, argv, "hn:b:d:l:X")) >= 0) - { - switch(c) - { - case 'h': - usage(0); - break; - case 'n': - attrname = optarg; - break; - case 'b': - basefile = optarg; - break; - case 'd': - dir = optarg; - break; - case 'l': - locale = optarg; - break; - case 'X': -#ifdef SUSE - add_auto = 1; -#endif - break; - default: - usage(1); - break; - } - } - if (dir) - { - FILE *fp; - int l; - char *fnp; - l = strlen(dir) + 128; - fnp = solv_malloc(l+1); - snprintf(fnp, l, "%s/primary.xml.gz", dir); - if (!(fp = solv_xfopen(fnp, 0))) - { - perror(fnp); - exit(1); - } - if (repo_add_rpmmd(repo, fp, 0, flags)) - { - fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool)); - exit(1); - } - fclose(fp); - snprintf(fnp, l, "%s/diskusagedata.xml.gz", dir); - if ((fp = solv_xfopen(fnp, 0))) - { - if (repo_add_rpmmd(repo, fp, 0, flags)) - { - fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool)); - exit(1); - } - fclose(fp); - } - if (locale) - { - if (snprintf(fnp, l, "%s/translation-%s.xml.gz", dir, locale) >= l) - { - fprintf(stderr, "-l parameter too long\n"); - exit(1); - } - while (!(fp = solv_xfopen(fnp, 0))) - { - fprintf(stderr, "not opened %s\n", fnp); - if (strlen(locale) > 2) - { - if (snprintf(fnp, l, "%s/translation-%.2s.xml.gz", dir, locale) >= l) - { - fprintf(stderr, "-l parameter too long\n"); - exit(1); - } - if ((fp = solv_xfopen(fnp, 0))) - break; - } - perror(fnp); - exit(1); - } - fprintf(stderr, "opened %s\n", fnp); - if (repo_add_rpmmd(repo, fp, 0, flags)) - { - fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool)); - exit(1); - } - fclose(fp); - } - solv_free(fnp); - } - else - { - if (repo_add_rpmmd(repo, stdin, 0, flags)) - { - fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool)); - exit(1); - } - } -#ifdef SUSE - if (add_auto) - repo_add_autopattern(repo, 0); -#endif - tool_write(repo, basefile, attrname); - pool_free(pool); - exit(0); -} diff --git a/libsolv-0.6.15/.emacs-dirvars b/libsolv-0.7.2/.emacs-dirvars similarity index 100% rename from libsolv-0.6.15/.emacs-dirvars rename to libsolv-0.7.2/.emacs-dirvars diff --git a/libsolv-0.6.15/.gitignore b/libsolv-0.7.2/.gitignore similarity index 100% rename from libsolv-0.6.15/.gitignore rename to libsolv-0.7.2/.gitignore diff --git a/libsolv-0.6.15/.travis.yml b/libsolv-0.7.2/.travis.yml similarity index 100% rename from libsolv-0.6.15/.travis.yml rename to libsolv-0.7.2/.travis.yml diff --git a/libsolv-0.6.15/CMakeLists.txt b/libsolv-0.7.2/CMakeLists.txt similarity index 72% rename from libsolv-0.6.15/CMakeLists.txt rename to libsolv-0.7.2/CMakeLists.txt index fd1426b..1deef57 100644 --- a/libsolv-0.6.15/CMakeLists.txt +++ b/libsolv-0.7.2/CMakeLists.txt @@ -13,8 +13,11 @@ OPTION (ENABLE_TCL "Build the Tcl bindings?" OFF) OPTION (USE_VENDORDIRS "Install the bindings in vendor directories?" OFF) OPTION (ENABLE_RPMDB "Build with rpm database support?" OFF) +OPTION (ENABLE_RPMPKG "Build with rpm package support?" OFF) OPTION (ENABLE_PUBKEY "Build with pubkey support?" OFF) OPTION (ENABLE_RPMDB_BYRPMHEADER "Build with rpmdb Header support?" OFF) +OPTION (ENABLE_RPMDB_LIBRPM "Use librpm to access the rpm database?" OFF) +OPTION (ENABLE_RPMPKG_LIBRPM "Use librpm to access rpm header information?" OFF) OPTION (ENABLE_RPMMD "Build with rpmmd repository support?" OFF) OPTION (ENABLE_SUSEREPO "Build with suse repository support?" OFF) OPTION (ENABLE_COMPS "Build with fedora comps support?" OFF) @@ -30,14 +33,10 @@ OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OF OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF) OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF) - -#IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4) -#ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4) - -IF (COMMAND cmake_policy) - # escape preprocessor, see -DVERSION below - CMAKE_POLICY (SET CMP0005 OLD) -ENDIF (COMMAND cmake_policy) +OPTION (ENABLE_ZSTD_COMPRESSION "Build with zstd compression support?" OFF) +OPTION (ENABLE_ZCHUNK_COMPRESSION "Build with zchunk compression support?" OFF) +OPTION (WITH_SYSTEM_ZCHUNK "Use system zchunk library?" OFF) +OPTION (WITH_LIBXML2 "Build with libxml2 instead of libexpat?" OFF) # Library IF (DEFINED LIB) @@ -57,12 +56,17 @@ else (DEFINED INCLUDE) ENDIF (DEFINED INCLUDE) MESSAGE (STATUS "Header files will be installed in ${INCLUDE_INSTALL_DIR}") SET (BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") -SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man") -IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man") - SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man") -ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man") +IF (NOT MAN_INSTALL_DIR) +SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man") +IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man") + SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man") +ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man" AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man") +ENDIF (NOT MAN_INSTALL_DIR) MESSAGE(STATUS "Man pages will be installed in ${MAN_INSTALL_DIR}") +IF (NOT PKGCONFIG_INSTALL_DIR) + SET (PKGCONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/pkgconfig) +ENDIF (NOT PKGCONFIG_INSTALL_DIR) #################################################################### # CONFIGURATION # #################################################################### @@ -147,19 +151,47 @@ IF (${have_system} STRGREATER xx) MESSAGE (FATAL_ERROR "Can only compile for one system type.") ENDIF (${have_system} STRGREATER xx) -IF (ENABLE_ARCHREPO) +SET (ENABLE_ZLIB_COMPRESSION ON) +IF (ENABLE_ARCHREPO OR ENABLE_DEBIAN) SET (ENABLE_LZMA_COMPRESSION ON) -ENDIF (ENABLE_ARCHREPO) - +ENDIF (ENABLE_ARCHREPO OR ENABLE_DEBIAN) + +IF (WITH_SYSTEM_ZCHUNK) +SET (ENABLE_ZCHUNK_COMPRESSION ON) +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(ZCHUNK zck REQUIRED) +ENDIF (WITH_SYSTEM_ZCHUNK) + +IF (ENABLE_ZCHUNK_COMPRESSION) +SET (ENABLE_ZSTD_COMPRESSION ON) +ENDIF (ENABLE_ZCHUNK_COMPRESSION) + +IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) +IF (WITH_LIBXML2 ) +FIND_PACKAGE (LibXml2 REQUIRED) +INCLUDE_DIRECTORIES (${LIBXML2_INCLUDE_DIR}) +ELSE(WITH_LIBXML2 ) FIND_PACKAGE (EXPAT REQUIRED) +INCLUDE_DIRECTORIES (${EXPAT_INCLUDE_DIRS}) +ENDIF (WITH_LIBXML2 ) +ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) + +IF (ENABLE_ZLIB_COMPRESSION) FIND_PACKAGE (ZLIB REQUIRED) +ENDIF (ENABLE_ZLIB_COMPRESSION) + IF (ENABLE_LZMA_COMPRESSION) FIND_PACKAGE (LZMA REQUIRED) ENDIF (ENABLE_LZMA_COMPRESSION) + IF (ENABLE_BZIP2_COMPRESSION) FIND_PACKAGE (BZip2 REQUIRED) ENDIF (ENABLE_BZIP2_COMPRESSION) +IF (ENABLE_ZSTD_COMPRESSION) +FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd) +ENDIF (ENABLE_ZSTD_COMPRESSION) + IF (RPM5) MESSAGE (STATUS "Enabling RPM 5 support") ADD_DEFINITIONS (-DRPM5) @@ -172,11 +204,14 @@ ENDIF (RPM5) IF (MULTI_SEMANTICS) MESSAGE (STATUS "Enabling multi dist support") -ADD_DEFINITIONS (-DMULTI_SEMANTICS) ENDIF (MULTI_SEMANTICS) -INCLUDE (CheckIncludeFile) IF (ENABLE_RPMDB) +SET (ENABLE_RPMPKG ON) +ENDIF (ENABLE_RPMDB) + +INCLUDE (CheckIncludeFile) +IF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb) IF (NOT RPMDB_LIBRARY) @@ -197,15 +232,20 @@ IF (ENABLE_RPMDB) # check if rpm contains a bundled berkeley db CHECK_INCLUDE_FILE(rpm/db.h HAVE_RPM_DB_H) - IF (NOT HAVE_RPM_DB_H) - FIND_LIBRARY (DB_LIBRARY NAMES db) - IF (DB_LIBRARY) - SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY}) - ENDIF (DB_LIBRARY) - ENDIF (NOT HAVE_RPM_DB_H) + IF (NOT ENABLE_RPMDB_LIBRPM) + IF (NOT HAVE_RPM_DB_H) + FIND_LIBRARY (DB_LIBRARY NAMES db) + IF (DB_LIBRARY) + SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY}) + ENDIF (DB_LIBRARY) + IF (DB_INCLUDE_DIR) + INCLUDE_DIRECTORIES (${DB_INCLUDE_DIR}) + ENDIF (DB_INCLUDE_DIR) + ENDIF (NOT HAVE_RPM_DB_H) + ENDIF (NOT ENABLE_RPMDB_LIBRPM) INCLUDE (CheckLibraryExists) CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS) -ENDIF (ENABLE_RPMDB) +ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) IF (ENABLE_PUBKEY) SET (ENABLE_PGPVRFY ON) @@ -237,14 +277,36 @@ ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2) # should create config.h with #cmakedefine instead... FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN - HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS - ENABLE_RPMDB ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER ENABLE_SUSEREPO ENABLE_COMPS + HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS WITH_LIBXML2 ) + IF(${VAR}) + ADD_DEFINITIONS (-D${VAR}=1) + SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR}) + ENDIF (${VAR}) +ENDFOREACH (VAR) + +FOREACH (VAR + ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS) + IF(${VAR}) + ADD_DEFINITIONS (-D${VAR}=1) + SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR}) + STRING(REPLACE ENABLE_ "" VARX ${VAR}) + SET (LIBSOLV_FEATURE_${VARX} 1) + ENDIF (${VAR}) +ENDFOREACH (VAR) + +FOREACH (VAR + ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD + ENABLE_RPMPKG_LIBRPM ENABLE_RPMDB_LIBRPM ENABLE_RPMDB_BYRPMHEADER + ENABLE_SUSEREPO ENABLE_COMPS ENABLE_TESTCASE_HELIXREPO ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU - ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA - ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS) + ENABLE_ZLIB_COMPRESSION ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION + ENABLE_ZSTD_COMPRESSION ENABLE_ZCHUNK_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA + WITH_SYSTEM_ZCHUNK) IF(${VAR}) ADD_DEFINITIONS (-D${VAR}=1) SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR}) + STRING(REPLACE ENABLE_ "" VARX ${VAR}) + SET (LIBSOLVEXT_FEATURE_${VARX} 1) ENDIF (${VAR}) ENDFOREACH (VAR) @@ -252,7 +314,6 @@ SET (PACKAGE "libsolv") SET (VERSION "${LIBSOLV_MAJOR}.${LIBSOLV_MINOR}.${LIBSOLV_PATCH}") ADD_DEFINITIONS (-D_FILE_OFFSET_BITS=64) -ADD_DEFINITIONS (-DVERSION=\\\"${VERSION}\\\") CONFIGURE_FILE (src/solvversion.h.in src/solvversion.h) SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Package dependency solver library") @@ -323,13 +384,31 @@ set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3") set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O3") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g3 -O0") -SET (SYSTEM_LIBRARIES ${EXPAT_LIBRARY} ${ZLIB_LIBRARY}) +# set system libraries +SET (SYSTEM_LIBRARIES "") +IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) +IF (WITH_LIBXML2 ) +SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LIBXML2_LIBRARIES}) +ELSE (WITH_LIBXML2 ) +SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${EXPAT_LIBRARY}) +ENDIF (WITH_LIBXML2 ) + +ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) +IF (ENABLE_ZLIB_COMPRESSION) +SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZLIB_LIBRARY}) +ENDIF (ENABLE_ZLIB_COMPRESSION) IF (ENABLE_LZMA_COMPRESSION) SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LZMA_LIBRARY}) ENDIF (ENABLE_LZMA_COMPRESSION) IF (ENABLE_BZIP2_COMPRESSION) SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${BZIP2_LIBRARIES}) ENDIF (ENABLE_BZIP2_COMPRESSION) +IF (ENABLE_ZSTD_COMPRESSION) +SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZSTD_LIBRARY}) +ENDIF (ENABLE_ZSTD_COMPRESSION) +IF (WITH_SYSTEM_ZCHUNK) +SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZCHUNK_LIBRARIES}) +ENDIF (WITH_SYSTEM_ZCHUNK) IF (ENABLE_RPMDB) SET (SYSTEM_LIBRARIES ${RPMDB_LIBRARY} ${SYSTEM_LIBRARIES}) ENDIF (ENABLE_RPMDB) @@ -361,9 +440,11 @@ MACRO (SPECFILE) ENDMACRO (SPECFILE) MACRO (PCFILE) - MESSAGE (STATUS "Writing pkg-config file...") + MESSAGE (STATUS "Writing pkg-config files...") CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/libsolv.pc.in ${CMAKE_BINARY_DIR}/libsolv.pc @ONLY) - INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolv.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig ) + INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolv.pc DESTINATION ${PKGCONFIG_INSTALL_DIR} ) + CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/libsolvext.pc.in ${CMAKE_BINARY_DIR}/libsolvext.pc @ONLY) + INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolvext.pc DESTINATION ${PKGCONFIG_INSTALL_DIR} ) ENDMACRO (PCFILE) SPECFILE () diff --git a/libsolv-0.6.15/CREDITS b/libsolv-0.7.2/CREDITS similarity index 100% rename from libsolv-0.6.15/CREDITS rename to libsolv-0.7.2/CREDITS diff --git a/libsolv-0.6.15/INSTALL b/libsolv-0.7.2/INSTALL similarity index 100% rename from libsolv-0.6.15/INSTALL rename to libsolv-0.7.2/INSTALL diff --git a/libsolv-0.6.15/LICENSE.BSD b/libsolv-0.7.2/LICENSE.BSD similarity index 100% rename from libsolv-0.6.15/LICENSE.BSD rename to libsolv-0.7.2/LICENSE.BSD diff --git a/libsolv-0.7.2/NEWS b/libsolv-0.7.2/NEWS new file mode 100644 index 0000000..812a923 --- /dev/null +++ b/libsolv-0.7.2/NEWS @@ -0,0 +1,183 @@ + +This file contains the major changes between +libsolv versions: + +Version 0.7.2 +- bug fixes: + * do not autouninstall packages because of forcebest updates +- new features: + * support rpm's new '^' version separator + * support set/get_considered_list in bindings + * new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag + +Version 0.7.1 +- fix nasty off-by-one error in repo_write + +Version 0.7.0 +- soname bump to "1" +- incompatible API changes: + * bindings: Selection.flags is now an attribute + * repodata_lookup_num now works like the other lookup_num functions +- new functions: + * selection_make_matchsolvable + * selection_make_matchsolvablelist + * pool_whatmatchessolvable + * repodata_search_arrayelement + * repodata_lookup_kv_uninternalized + * repodata_search_uninternalized + * repodata_translate_dir +- new repowriter interface to write solv files allowing better + control over what gets written +- support for filtered file lists with a custom filter +- dropped support of (since a long time unused) REPOKEY_TYPE_U32 + +Version 0.6.35 +- new configuration options: + * ENABLE_ZSTD_COMPRESSION: support zstd compression + * ENABLE_ZCHUNK_COMPRESSION: support zchunk compression +- new features: + * new repodata_set_kv() function + * new pool_solvable2id() inline function + * bindings: new str2dir, dir2str, add_dirstr repodata methods +- other changes + * new repo2solv tool replacing the old shell script + +Version 0.6.34 +- new features: + * also look at suggests for package ordering + +Version 0.6.33 +- new features: + * new Selection.clone() method in the bindings + * new pool.parserpmrichdep() method in the bindings + +Version 0.6.32 +- fixed bug that could make fileconflict detection very slow + in some cases + +Version 0.6.31 +- new configuration options: + * ENABLE_RPMDB_LIBRPM: use librpm to read the package + database + * ENABLE_RPMPKG_LIBRPM: use librpm to access information + from package headers +- new features: + * new pool_set_whatprovides function to manually change + the whatprovides data + * new selection_subtract function to remove packages of + one selection from another selection + * new selection flags SELECTION_FILTER, + SELECTION_WITH_DISABLED and SELECTION_WITH_BADARCH + * new map_invertall function to invert a bitmap + * new map_clr_at function to clear some bits + +Version 0.6.30 +- new features: + * many fixes and extenstions for cleandeps, e.g. + cleandeps now works for "update all packages" + * support debian packages with xz compressed control.tar + * always create dup rules for "distupgrade" jobs + * use recommends also for ordering packages + +Version 0.6.29 +- new features: + * support for REL_WITHOUT and REL_UNLESS dependencies + * solver_get_recommendations available in bindings + +Version 0.6.28 +- new features: + * new pool_best_solvables() function + +Version 0.6.27 +- new features: + * allow building with libxml2 instead of libexpat + * better handing of "forcebest with uninstall" + * speed improvements for "name = md5sum" dependencies + +Version 0.6.26 +- export solvable_matchesdep function, as we now + use it in the bindings + +Version 0.6.25 +- new features: + * new SOLVER_FLAG_STRONG_RECOMMENDS flag + * new SOLVER_FLAG_INSTALL_ALSO_UPDATES flag + * new matchesdep() method in bindings + * SOLVABLE_NAME selects nevr matching for + pool_whatmatchesdep and solvable_matchesdep + +Version 0.6.24 +- new features: + * new SOLVER_FLAG_FOCUS_BEST flag + +Version 0.6.22, 0.6.23 +- bug fix releases, no new features + +Version 0.6.21 +- new features: + * SOLVER_FAVOR and SOLVER_DISFAVOR job types +- new functions: + * selection_make_matchdepid + * pool_whatcontainsdep + * pool_parserpmrichdep + +Version 0.6.20 +- new features: + * filter Requires(pre,post) for installed packages + +Version 0.6.13: +- new features: + * SOLVER_ALLOWUNINSTALL job type + * ordercycle introspection +- new functions: + * transaction_order_get_cycle + * transaction_order_get_cycleids + +Version 0.6.12: +- new features: + * tcl bindings +- new functions: + * solv_chksum_cmp + +Version 0.6.11: +- new functions: + * pool_ids2whatprovides + +Version 0.6.9: +- new features: + * much improved package choosing code + * new testcase dependency format + * alternatives introspection +- new functions: + * pool_deb_get_autoinstalled + * solver_alternative2str + * solver_alternatives_count + * solver_get_alternative + * solver_rule2pkgrule + * testcase_dep2str + +Version 0.6.5: +- new features: + * support yum style obsolete handling + +Version 0.6.1: +- API change: + repodata_stringify() now returns the string +- new features: + * add BREAK_ORPHANS and KEEP_ORPHANS solver flags + +Version 0.6.0: +- ABI change: cleaned up and reordered knownid.h +- added support for sha224/sha384/sha512 +- API change in the bindings: + * dropped solvid arg from most Dataiterator + constructors + * changed Datamatch results from methods to + attributes + * automatically delete the pool if the owner + object is freed (use the disown method to + get the old behavior). +- new functions: + * pool_add_userinstalled_jobs + * solver_get_userinstalled + diff --git a/libsolv-0.6.15/README b/libsolv-0.7.2/README similarity index 71% rename from libsolv-0.6.15/README rename to libsolv-0.7.2/README index 243486a..0242459 100644 --- a/libsolv-0.6.15/README +++ b/libsolv-0.7.2/README @@ -1,10 +1,13 @@ +Libsolv +======= + This is libsolv, a free package dependency solver using a satisfiability algorithm. -This code is based on two major, but independent, blocks: +The code is based on two major, but independent, blocks: - 1. Using a dictionary approach to store and retrieve package - and dependency information. + 1. Using a dictionary approach to store and retrieve package and + dependency information in a fast and space efficient manner. 2. Using satisfiability, a well known and researched topic, for resolving package dependencies. @@ -16,12 +19,14 @@ problems. It also takes advantage of the repository storage to minimize memory usage. Supported package formats: + - rpm/rpm5 - deb - arch linux - haiku Supported repository formats: + - rpmmd (primary, filelists, comps, deltainfo/presto, updateinfo) - susetags, suse product formats - mandriva/mageia (synthesis, info, files) @@ -29,13 +34,16 @@ Supported repository formats: - red carpet helix format - haiku +Build instructions +================== + Requires: cmake 2.4.x -mkdir build -cd build -cmake .. -make + mkdir build + cd build + cmake .. + make -To create a package: -make srcpackage -see package/ +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.7.2/TODO_1.0 b/libsolv-0.7.2/TODO_1.0 new file mode 100644 index 0000000..d77df67 --- /dev/null +++ b/libsolv-0.7.2/TODO_1.0 @@ -0,0 +1,18 @@ + +- implement package priority (for things like Debian's pin feature) + +- merge SUSETAGS_FILE_* and REPOSITORY_REPOMD_* keys into REPOSITORY_RESOURCE + +- re-order key ids + +- deal with DIRSTR entries having dirid 0 (for source rpms) + +- drop patchcheck + +- make FAVOR handling deal with versions + +- write more manpages + +IDEAS: + +drop SEARCH_FILES and add SEARCH_BASENAME instead? diff --git a/libsolv-0.6.15/VERSION.cmake b/libsolv-0.7.2/VERSION.cmake similarity index 93% rename from libsolv-0.6.15/VERSION.cmake rename to libsolv-0.7.2/VERSION.cmake index 7ba4cb6..507716c 100644 --- a/libsolv-0.6.15/VERSION.cmake +++ b/libsolv-0.7.2/VERSION.cmake @@ -44,10 +44,10 @@ # set COMPATMINOR to MINOR. (binary incompatible change) # -SET(LIBSOLV_SOVERSION "0") -SET(LIBSOLVEXT_SOVERSION "0") +SET(LIBSOLV_SOVERSION "1") +SET(LIBSOLVEXT_SOVERSION "1") SET(LIBSOLV_MAJOR "0") -SET(LIBSOLV_MINOR "6") -SET(LIBSOLV_PATCH "15") +SET(LIBSOLV_MINOR "7") +SET(LIBSOLV_PATCH "2") diff --git a/libsolv-0.6.15/bindings/CMakeLists.txt b/libsolv-0.7.2/bindings/CMakeLists.txt similarity index 85% rename from libsolv-0.6.15/bindings/CMakeLists.txt rename to libsolv-0.7.2/bindings/CMakeLists.txt index 34b0784..737cee4 100644 --- a/libsolv-0.6.15/bindings/CMakeLists.txt +++ b/libsolv-0.7.2/bindings/CMakeLists.txt @@ -8,6 +8,9 @@ SET (SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/solv.i") IF (ENABLE_PYTHON) ADD_SUBDIRECTORY (python) ENDIF (ENABLE_PYTHON) +IF (ENABLE_PYTHON3) + ADD_SUBDIRECTORY (python3) +ENDIF (ENABLE_PYTHON3) IF (ENABLE_PERL) ADD_SUBDIRECTORY (perl) ENDIF (ENABLE_PERL) diff --git a/libsolv-0.6.15/bindings/perl/CMakeLists.txt b/libsolv-0.7.2/bindings/perl/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/bindings/perl/CMakeLists.txt rename to libsolv-0.7.2/bindings/perl/CMakeLists.txt diff --git a/libsolv-0.6.15/bindings/python/CMakeLists.txt b/libsolv-0.7.2/bindings/python/CMakeLists.txt similarity index 63% rename from libsolv-0.6.15/bindings/python/CMakeLists.txt rename to libsolv-0.7.2/bindings/python/CMakeLists.txt index 73f2dca..64ef528 100644 --- a/libsolv-0.6.15/bindings/python/CMakeLists.txt +++ b/libsolv-0.7.2/bindings/python/CMakeLists.txt @@ -1,7 +1,18 @@ -#SET (PythonLibs_FIND_VERSION 3) +IF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION) + # if we build both for python2 and python3, make this the python2 build. + # see comment in the python3 CMakeLists.txt file + SET (PythonLibs_FIND_VERSION 2) + SET (PythonLibs_FIND_VERSION_MAJOR 2) +ENDIF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION) + +FIND_PACKAGE (PythonLibs REQUIRED) +IF(PYTHONLIBS_VERSION_STRING MATCHES "^([0-9.]+)") + SET(python_version "${CMAKE_MATCH_1}") +ELSE() + MESSAGE(FATAL_ERROR "PythonLibs version format unknown '${PYTHONLIBS_VERSION_STRING}'") +ENDIF() +FIND_PACKAGE (PythonInterp ${python_version} REQUIRED) -FIND_PACKAGE (PythonLibs) -FIND_PACKAGE (PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON_INSTALL_DIR) IF (NOT DEFINED PYTHON_VERSION_MAJOR) @@ -10,9 +21,11 @@ ENDIF (NOT DEFINED PYTHON_VERSION_MAJOR) IF (${PYTHON_VERSION_MAJOR} GREATER 2) SET (SWIG_PY_FLAGS -DPYTHON3=1) ENDIF (${PYTHON_VERSION_MAJOR} GREATER 2) +SET (SWIG_PY_FLAGS ${SWIG_PY_FLAGS} -DSWIG_PYTHON_LEGACY_BOOL=1) MESSAGE (STATUS "Python executable: ${PYTHON_EXECUTABLE}") MESSAGE (STATUS "Python installation dir: ${PYTHON_INSTALL_DIR}") +MESSAGE (STATUS "Python include path: ${PYTHON_INCLUDE_PATH}") ADD_CUSTOM_COMMAND ( OUTPUT solv_python.c diff --git a/libsolv-0.7.2/bindings/python3/CMakeLists.txt b/libsolv-0.7.2/bindings/python3/CMakeLists.txt new file mode 100644 index 0000000..28e8e00 --- /dev/null +++ b/libsolv-0.7.2/bindings/python3/CMakeLists.txt @@ -0,0 +1,38 @@ +# +# used for building both python2 and python3 bindings +# do not use if you want to build just one flavor, use the +# standard python bindings file in that case. +# +# we cannot use FIND_PACKAGE PythonLibs here, as this would +# clash with the python variables. +# +IF (NOT DEFINED PYTHON3_EXECUTABLE) +SET (PYTHON3_EXECUTABLE "/usr/bin/python3") +ENDIF (NOT DEFINED PYTHON3_EXECUTABLE) + +EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON3_INSTALL_DIR) +EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_inc())" OUTPUT_VARIABLE PYTHON3_INCLUDE_DIR) + +SET (SWIG_PY3_FLAGS -DPYTHON3=1) +SET (SWIG_PY3_FLAGS ${SWIG_PY3_FLAGS} -DSWIG_PYTHON_LEGACY_BOOL=1) + +MESSAGE (STATUS "Python3 executable: ${PYTHON3_EXECUTABLE}") +MESSAGE (STATUS "Python3 installation dir: ${PYTHON3_INSTALL_DIR}") +MESSAGE (STATUS "Python3 include path: ${PYTHON3_INCLUDE_DIR}") + +ADD_CUSTOM_COMMAND ( + OUTPUT solv_python.c + COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python ${SWIG_PY3_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_python.c ${CMAKE_SOURCE_DIR}/bindings/solv.i + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i +) + +ADD_DEFINITIONS(-Wno-unused) +INCLUDE_DIRECTORIES (${PYTHON3_INCLUDE_DIR}) + +ADD_LIBRARY (bindings_python3 SHARED solv_python.c) +SET_TARGET_PROPERTIES (bindings_python3 PROPERTIES PREFIX "" OUTPUT_NAME "_solv") +TARGET_LINK_LIBRARIES (bindings_python3 libsolvext libsolv ${SYSTEM_LIBRARIES}) + +INSTALL (TARGETS bindings_python3 LIBRARY DESTINATION ${PYTHON3_INSTALL_DIR}) +INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON3_INSTALL_DIR}) diff --git a/libsolv-0.6.15/bindings/ruby/CMakeLists.txt b/libsolv-0.7.2/bindings/ruby/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/bindings/ruby/CMakeLists.txt rename to libsolv-0.7.2/bindings/ruby/CMakeLists.txt diff --git a/libsolv-0.6.15/bindings/solv.i b/libsolv-0.7.2/bindings/solv.i similarity index 89% rename from libsolv-0.6.15/bindings/solv.i rename to libsolv-0.7.2/bindings/solv.i index 823deda..93a97db 100644 --- a/libsolv-0.6.15/bindings/solv.i +++ b/libsolv-0.7.2/bindings/solv.i @@ -88,23 +88,6 @@ typedef struct { } #if defined(SWIGPYTHON) -%typemap(in) Queue { - /* Check if is a list */ - if (PyList_Check($input)) { - int size = PyList_Size($input); - int i = 0; - for (i = 0; i < size; i++) { - PyObject *o = PyList_GetItem($input,i); - int v; - int e = SWIG_AsVal_int(o, &v); - if (!SWIG_IsOK(e)) - SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers"); - queue_push(&$1, v); - } - } else { - SWIG_exception_fail(SWIG_TypeError, "list must contain only integers"); - } -} %typemap(out) Queue { int i; @@ -115,7 +98,7 @@ typedef struct { $result = o; } -%define Queue2Array(type, step, con) %{ +%define Queue2Array(type, step, con) %{ { int i; int cnt = $1.count / step; Id *idp = $1.elements; @@ -131,30 +114,47 @@ typedef struct { } queue_free(&$1); $result = o; +} %} - %enddef -#endif /* SWIGPYTHON */ - -#if defined(SWIGPERL) -%typemap(in) Queue { - AV *av; +%define Array2Queue(asval_meth,typestr) %{ { int i, size; - if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) - SWIG_croak("Argument $argnum is not an array reference."); - av = (AV*)SvRV($input); - size = av_len(av); - for (i = 0; i <= size; i++) { - SV **sv = av_fetch(av, i, 0); + if (!PyList_Check($input)) + SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list"); + size = PyList_Size($input); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input,i); int v; - int e = SWIG_AsVal_int(*sv, &v); - if (!SWIG_IsOK(e)) { - SWIG_croak("list must contain only integers"); - } + int e = asval_meth(o, &v); + if (!SWIG_IsOK(e)) + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only" typestr); queue_push(&$1, v); } } +%} +%enddef + +%define ObjArray2Queue(type, obj2queue) %{ { + int i, size; + if (!PyList_Check($input)) + SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list"); + size = PyList_Size($input); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input,i); + type obj; + int e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0); + if (!SWIG_IsOK(e)) + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`); + obj2queue; + } +} +%} +%enddef + +#endif /* SWIGPYTHON */ + +#if defined(SWIGPERL) /* AV *o = newAV(); * av_push(o, SvREFCNT_inc(SWIG_From_int($1.elements[i]))); * $result = newRV_noinc((SV*)o); argvi++; @@ -170,7 +170,7 @@ typedef struct { $result = 0; } -%define Queue2Array(type, step, con) %{ +%define Queue2Array(type, step, con) %{ { int i; int cnt = $1.count / step; Id *idp = $1.elements; @@ -188,28 +188,52 @@ typedef struct { } queue_free(&$1); $result = 0; +} %} %enddef -#endif /* SWIGPERL */ - - -#if defined(SWIGRUBY) -%typemap(in) Queue { - int size, i; - VALUE *o, ary; - ary = rb_Array($input); - size = RARRAY_LEN(ary); - i = 0; - o = RARRAY_PTR(ary); - for (i = 0; i < size; i++, o++) { +%define Array2Queue(asval_meth,typestr) %{ { + AV *av; + int i, size; + if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) + SWIG_croak("argument $argnum is not an array reference."); + av = (AV*)SvRV($input); + size = av_len(av); + for (i = 0; i <= size; i++) { + SV **sv = av_fetch(av, i, 0); int v; - int e = SWIG_AsVal_int(*o, &v); + int e = asval_meth(*sv, &v); if (!SWIG_IsOK(e)) - SWIG_exception_fail(SWIG_TypeError, "list must contain only integers"); + SWIG_croak("array in argument $argnum must contain only " typestr); queue_push(&$1, v); } } +%} +%enddef + +%define ObjArray2Queue(type, obj2queue) %{ { + AV *av; + int i, size; + if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) + SWIG_croak("argument $argnum is not an array reference."); + av = (AV*)SvRV($input); + size = av_len(av); + for (i = 0; i <= size; i++) { + SV **sv = av_fetch(av, i, 0); + type obj; + int e = SWIG_ConvertPtr(*sv, (void **)&obj, $descriptor(type), 0 | 0); + if (!SWIG_IsOK(e)) + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`); + obj2queue; + } +} +%} +%enddef + +#endif /* SWIGPERL */ + + +#if defined(SWIGRUBY) %typemap(out) Queue { int i; VALUE o = rb_ary_new2($1.count); @@ -218,13 +242,8 @@ typedef struct { queue_free(&$1); $result = o; } -%typemap(arginit) Queue { - queue_init(&$1); -} -%typemap(freearg) Queue { - queue_free(&$1); -} -%define Queue2Array(type, step, con) %{ + +%define Queue2Array(type, step, con) %{ { int i; int cnt = $1.count / step; Id *idp = $1.elements; @@ -240,32 +259,49 @@ typedef struct { } queue_free(&$1); $result = o; +} %} %enddef -#endif /* SWIGRUBY */ - -#if defined(SWIGTCL) -%typemap(in) Queue { - /* Check if is a list */ - int size = 0; - int i = 0; - - if (TCL_OK != Tcl_ListObjLength(interp, $input, &size)) - SWIG_exception_fail(SWIG_TypeError, "argument is not a list"); - for (i = 0; i < size; i++) { - Tcl_Obj *o = NULL; - int e, v; - - if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o)) - SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member"); - e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v); +%define Array2Queue(asval_meth,typestr) %{ { + int size, i; + VALUE *o, ary; + ary = rb_Array($input); + size = RARRAY_LEN(ary); + i = 0; + o = RARRAY_PTR(ary); + for (i = 0; i < size; i++, o++) { + int v; + int e = asval_meth(*o, &v); if (!SWIG_IsOK(e)) - SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers"); + SWIG_exception_fail(SWIG_TypeError, "list in argument $argnum must contain only " typestr); queue_push(&$1, v); } } +%} +%enddef +%define ObjArray2Queue(type, obj2queue) %{ { + int size, i; + VALUE *o, ary; + ary = rb_Array($input); + size = RARRAY_LEN(ary); + i = 0; + o = RARRAY_PTR(ary); + for (i = 0; i < size; i++, o++) { + type obj; + int e = SWIG_ConvertPtr(*o, (void **)&obj, $descriptor(type), 0 | 0); + if (!SWIG_IsOK(e)) + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`); + obj2queue; + } +} +%} +%enddef + +#endif /* SWIGRUBY */ + +#if defined(SWIGTCL) %typemap(out) Queue { Tcl_Obj *objvx[$1.count]; int i; @@ -297,40 +333,61 @@ typedef struct { } queue_free(&$1); Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx)); - } + } %} - %enddef -%typemap(in) Queue solvejobs { - /* Check if is a list */ +%define Array2Queue(asval_meth,typestr) %{ { int size = 0; int i = 0; + if (TCL_OK != Tcl_ListObjLength(interp, $input, &size)) + SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list"); + for (i = 0; i < size; i++) { + Tcl_Obj *o = NULL; + int e, v; + + if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o)) + SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member"); + e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v); + if (!SWIG_IsOK(e)) + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only " typestr); + queue_push(&$1, v); + } +} +%} +%enddef +%define ObjArray2Queue(type, obj2queue) %{ { + int size = 0; + int i = 0; if (TCL_OK != Tcl_ListObjLength(interp, $input, &size)) - SWIG_exception_fail(SWIG_TypeError, "argument is not a list"); + SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list"); for (i = 0; i < size; i++) { Tcl_Obj *o = NULL; - void *jp; - Job *j; + type obj; int e; - if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o)) SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member"); - e = SWIG_ConvertPtr(o, &jp ,SWIGTYPE_p_Job, 0 | 0 ); + e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0); if (!SWIG_IsOK(e)) - SWIG_exception_fail(SWIG_ArgError(e), "list member is not a Job"); - j = (Job *)jp; - queue_push2(&$1, j->how, j->what); + SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`); + obj2queue; } } +%} +%enddef #endif /* SWIGTCL */ +%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers") +%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what)) + + #if defined(SWIGPERL) -/* work around a swig bug */ +/* work around a swig bug for swig versions < 2.0.5 */ +#if SWIG_VERSION < 0x020005 %{ #undef SWIG_CALLXS #ifdef PERL_OBJECT @@ -343,6 +400,7 @@ typedef struct { # endif #endif %} +#endif %define perliter(class) @@ -634,7 +692,7 @@ typedef int bool; #include "selection.h" #include "repo_write.h" -#ifdef ENABLE_RPMDB +#if defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG) #include "repo_rpmdb.h" #endif #ifdef ENABLE_PUBKEY @@ -663,6 +721,9 @@ typedef int bool; #ifdef SUSE #include "repo_autopattern.h" #endif +#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG)) +#include "pool_parserpmrichdep.h" +#endif #include "solv_xfopen.h" #include "testcase.h" @@ -932,15 +993,24 @@ typedef int Id; %constant int REL_EQ; %constant int REL_GT; %constant int REL_LT; -%constant int REL_ARCH; %constant int REL_AND; %constant int REL_OR; %constant int REL_WITH; +%constant int REL_NAMESPACE; +%constant int REL_ARCH; +%constant int REL_FILECONFLICT; %constant int REL_COND; +%constant int REL_COMPAT; +%constant int REL_KIND; +%constant int REL_MULTIARCH; %constant int REL_ELSE; +%constant int REL_ERROR; +%constant int REL_WITHOUT; +%constant int REL_UNLESS; typedef struct { Pool* const pool; + int const flags; } Selection; typedef struct { @@ -1172,6 +1242,8 @@ typedef struct { static const Id SOLVER_DROP_ORPHANED = SOLVER_DROP_ORPHANED; static const Id SOLVER_USERINSTALLED = SOLVER_USERINSTALLED; static const Id SOLVER_ALLOWUNINSTALL = SOLVER_ALLOWUNINSTALL; + static const Id SOLVER_FAVOR = SOLVER_FAVOR; + static const Id SOLVER_DISFAVOR = SOLVER_DISFAVOR; static const Id SOLVER_JOBMASK = SOLVER_JOBMASK; static const Id SOLVER_WEAK = SOLVER_WEAK; static const Id SOLVER_ESSENTIAL = SOLVER_ESSENTIAL; @@ -1249,8 +1321,18 @@ typedef struct { static const Id SELECTION_GLOB = SELECTION_GLOB; static const Id SELECTION_FLAT = SELECTION_FLAT; static const Id SELECTION_NOCASE = SELECTION_NOCASE; + static const Id SELECTION_SKIP_KIND = SELECTION_SKIP_KIND; + static const Id SELECTION_MATCH_DEPSTR = SELECTION_MATCH_DEPSTR; static const Id SELECTION_SOURCE_ONLY = SELECTION_SOURCE_ONLY; static const Id SELECTION_WITH_SOURCE = SELECTION_WITH_SOURCE; + static const Id SELECTION_WITH_DISABLED = SELECTION_WITH_DISABLED; + static const Id SELECTION_WITH_BADARCH = SELECTION_WITH_BADARCH; + static const Id SELECTION_WITH_ALL = SELECTION_WITH_ALL; + static const Id SELECTION_ADD = SELECTION_ADD; + static const Id SELECTION_SUBTRACT = SELECTION_SUBTRACT; + static const Id SELECTION_FILTER = SELECTION_FILTER; + static const Id SELECTION_FILTER_KEEP_IFEMPTY = SELECTION_FILTER_KEEP_IFEMPTY; + static const Id SELECTION_FILTER_SWAPPED = SELECTION_FILTER_SWAPPED; Selection(Pool *pool) { Selection *s; @@ -1263,15 +1345,19 @@ typedef struct { queue_free(&$self->q); solv_free($self); } - int flags() { - return $self->flags; - } #ifdef SWIGRUBY %rename("isempty?") isempty; #endif bool isempty() { return $self->q.count == 0; } + %newobject clone; + Selection *clone(int flags = 0) { + Selection *s = new_Selection($self->pool); + queue_init_clone(&s->q, &$self->q); + s->flags = $self->flags; + return s; + } void filter(Selection *lsel) { if ($self->pool != lsel->pool) queue_empty(&$self->q); @@ -1288,6 +1374,27 @@ typedef struct { void add_raw(Id how, Id what) { queue_push2(&$self->q, how, what); } + void subtract(Selection *lsel) { + if ($self->pool == lsel->pool) + selection_subtract($self->pool, &$self->q, &lsel->q); + } + + void select(const char *name, int flags) { + if ((flags & SELECTION_MODEBITS) == 0) + flags |= SELECTION_FILTER | SELECTION_WITH_ALL; + $self->flags = selection_make($self->pool, &$self->q, name, flags); + } + void matchdeps(const char *name, int flags, Id keyname, Id marker = -1) { + if ((flags & SELECTION_MODEBITS) == 0) + flags |= SELECTION_FILTER | SELECTION_WITH_ALL; + $self->flags = selection_make_matchdeps($self->pool, &$self->q, name, flags, keyname, marker); + } + void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) { + if ((flags & SELECTION_MODEBITS) == 0) + flags |= SELECTION_FILTER | SELECTION_WITH_ALL; + $self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker); + } + %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1])); %newobject jobs; Queue jobs(int flags) { @@ -1468,11 +1575,18 @@ typedef struct { static const int POOL_FLAG_NOINSTALLEDOBSOLETES = POOL_FLAG_NOINSTALLEDOBSOLETES; static const int POOL_FLAG_HAVEDISTEPOCH = POOL_FLAG_HAVEDISTEPOCH; static const int POOL_FLAG_NOOBSOLETESMULTIVERSION = POOL_FLAG_NOOBSOLETESMULTIVERSION; + static const int DISTTYPE_RPM = DISTTYPE_RPM; + static const int DISTTYPE_DEB = DISTTYPE_DEB; + static const int DISTTYPE_ARCH = DISTTYPE_ARCH; + static const int DISTTYPE_HAIKU = DISTTYPE_HAIKU; Pool() { Pool *pool = pool_create(); return pool; } + int setdisttype(int disttype) { + return pool_setdisttype($self, disttype); + } void set_debuglevel(int level) { pool_setdebuglevel($self, level); } @@ -1670,6 +1784,13 @@ typedef struct { Id id = pool_str2id($self, str, create); return new_Dep($self, id); } +#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG)) + %newobject Dep; + Dep *parserpmrichdep(const char *str) { + Id id = pool_parserpmrichdep($self, str); + return new_Dep($self, id); + } +#endif const char *id2str(Id id) { return pool_id2str($self, id); } @@ -1829,6 +1950,16 @@ typedef struct { return pool_queuetowhatprovides($self, &q); } + void set_namespaceproviders(DepId ns, DepId evr, bool value=1) { + Id dep = pool_rel2id($self, ns, evr, REL_NAMESPACE, 1); + pool_set_whatprovides($self, dep, value ? 2 : 1); + } + + void flush_namespaceproviders(DepId ns, DepId evr) { + pool_flush_namespaceproviders($self, ns, evr); + } + + %typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); %newobject whatmatchesdep; Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) { @@ -1847,7 +1978,7 @@ typedef struct { return 0; if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) return 1; - if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id])) + if (pool->id2arch && pool_arch2score(pool, id) == 0) return 0; return 1; } @@ -1874,9 +2005,52 @@ typedef struct { return sel; } - void setpooljobs_helper(Queue jobs) { + %newobject matchdeps; + Selection *matchdeps(const char *name, int flags, Id keyname, Id marker = -1) { + Selection *sel = new_Selection($self); + sel->flags = selection_make_matchdeps($self, &sel->q, name, flags, keyname, marker); + return sel; + } + + %newobject matchdepid; + Selection *matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) { + Selection *sel = new_Selection($self); + sel->flags = selection_make_matchdepid($self, &sel->q, dep, flags, keyname, marker); + return sel; + } + + Queue get_considered_list() { + Queue q; + queue_init(&q); + int i; + for (i = 2; i < $self->nsolvables; i++) { + if (!$self->solvables[i].repo) + continue; + if (!$self->considered || MAPTST($self->considered, i)) + queue_push(&q, i); + } + return q; + } + + void set_considered_list(Queue q) { + int i; + Id p; + if (!$self->considered) { + $self->considered = solv_calloc(1, sizeof(Map)); + map_init($self->considered, $self->nsolvables); + } + map_empty($self->considered); + MAPSET($self->considered, 1); + for (i = 0; i < q.count; i++) { + p = q.elements[i]; + if (p > 0 && p < $self->nsolvables) + MAPSET($self->considered, p); + } + } + + void setpooljobs(Queue solvejobs) { queue_free(&$self->pooljobs); - queue_init_clone(&$self->pooljobs, &jobs); + queue_init_clone(&$self->pooljobs, &solvejobs); } %typemap(out) Queue getpooljobs Queue2Array(Job *, 2, new_Job(arg1, id, idp[1])); %newobject getpooljobs; @@ -1886,36 +2060,6 @@ typedef struct { return q; } -#if defined(SWIGPYTHON) - %pythoncode { - def setpooljobs(self, jobs): - j = [] - for job in jobs: j += [job.how, job.what] - self.setpooljobs_helper(j) - } -#endif -#if defined(SWIGPERL) - %perlcode { - sub solv::Solver::setpooljobs { - my ($self, $jobs) = @_; - my @j = map {($_->{'how'}, $_->{'what'})} @$jobs; - return $self->setpooljobs_helper(\@j); - } - } -#endif -#if defined(SWIGRUBY) -%init %{ -rb_eval_string( - "class Solv::Pool\n" - " def setpooljobs(jobs)\n" - " jl = []\n" - " jobs.each do |j| ; jl << j.how << j.what ; end\n" - " setpooljobs_helper(jl)\n" - " end\n" - "end\n" - ); -%} -#endif } %extend Repo { @@ -1981,6 +2125,8 @@ rb_eval_string( bool add_rpmdb_reffp(FILE *reffp, int flags = 0) { return repo_add_rpmdb_reffp($self, reffp, flags) == 0; } +#endif +#ifdef ENABLE_RPMPKG %newobject add_rpm; XSolvable *add_rpm(const char *name, int flags = 0) { return new_XSolvable($self->pool, repo_add_rpm($self, name, flags)); @@ -2177,6 +2323,34 @@ rb_eval_string( } #endif + Repo *createshadow(const char *name) { + Repo *repo = repo_create($self->pool, name); + if ($self->idarraysize) { + repo_reserve_ids(repo, 0, $self->idarraysize); + memcpy(repo->idarraydata, $self->idarraydata, sizeof(Id) * $self->idarraysize); + repo->idarraysize = $self->idarraysize; + } + repo->start = $self->start; + repo->end = $self->end; + repo->nsolvables = $self->nsolvables; + return repo; + } + + void moveshadow(Queue q) { + Pool *pool = $self->pool; + int i; + for (i = 0; i < q.count; i++) { + Solvable *s; + Id p = q.elements[i]; + if (p < $self->start || p >= $self->end) + continue; + s = pool->solvables + p; + if ($self->idarraysize != s->repo->idarraysize) + continue; + s->repo = $self; + } + } + #if defined(SWIGTCL) %rename("==") __eq__; #endif @@ -2189,6 +2363,11 @@ rb_eval_string( bool __ne__(Repo *repo) { return $self != repo; } +#if defined(SWIGPYTHON) + int __hash__() { + return $self->repoid; + } +#endif #if defined(SWIGPERL) || defined(SWIGTCL) %rename("str") __str__; #endif @@ -2559,7 +2738,6 @@ rb_eval_string( #ifdef SWIGPERL perliter(solv::Pool_repo_iterator) #endif - %newobject __next__; Repo *__next__() { Pool *pool = $self->pool; if ($self->id >= pool->nrepos) @@ -2575,7 +2753,7 @@ rb_eval_string( void each() { Repo *n; while ((n = Pool_repo_iterator___next__($self)) != 0) { - rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, SWIG_POINTER_OWN | 0)); + rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, 0 | 0)); } } #endif @@ -2708,6 +2886,11 @@ rb_eval_string( bool __ne__(Dep *s) { return !Dep___eq__($self, s); } +#if defined(SWIGPYTHON) + int __hash__() { + return $self->id; + } +#endif #if defined(SWIGPERL) || defined(SWIGTCL) %rename("str") __str__; #endif @@ -2775,6 +2958,9 @@ rb_eval_string( const char *lookup_location(unsigned int *OUTPUT) { return solvable_lookup_location($self->pool->solvables + $self->id, OUTPUT); } + const char *lookup_sourcepkg() { + return solvable_lookup_sourcepkg($self->pool->solvables + $self->id); + } %newobject Dataiterator; Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) { return new_Dataiterator($self->pool, 0, $self->id, key, match, flags); @@ -2942,6 +3128,12 @@ rb_eval_string( int evrcmp(XSolvable *s2) { return pool_evrcmp($self->pool, $self->pool->solvables[$self->id].evr, s2->pool->solvables[s2->id].evr, EVRCMP_COMPARE); } +#ifdef SWIGRUBY + %rename("matchesdep?") matchesdep; +#endif + bool matchesdep(Id keyname, DepId id, Id marker = -1) { + return solvable_matchesdep($self->pool->solvables + $self->id, keyname, id, marker); + } #if defined(SWIGTCL) %rename("==") __eq__; @@ -2955,6 +3147,11 @@ rb_eval_string( bool __ne__(XSolvable *s) { return !XSolvable___eq__($self, s); } +#if defined(SWIGPYTHON) + int __hash__() { + return $self->id; + } +#endif #if defined(SWIGPERL) || defined(SWIGTCL) %rename("str") __str__; #endif @@ -3254,6 +3451,9 @@ rb_eval_string( static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED; static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES; static const int SOLVER_FLAG_NEED_UPDATEPROVIDE = SOLVER_FLAG_NEED_UPDATEPROVIDE; + static const int SOLVER_FLAG_FOCUS_BEST = SOLVER_FLAG_FOCUS_BEST; + static const int SOLVER_FLAG_STRONG_RECOMMENDS = SOLVER_FLAG_STRONG_RECOMMENDS; + static const int SOLVER_FLAG_INSTALL_ALSO_UPDATES = SOLVER_FLAG_INSTALL_ALSO_UPDATES; static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED; static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE; @@ -3280,49 +3480,7 @@ rb_eval_string( int get_flag(int flag) { return solver_get_flag($self, flag); } -#if defined(SWIGPYTHON) - %pythoncode { - def solve(self, jobs): - j = [] - for job in jobs: j += [job.how, job.what] - return self.solve_helper(j) - } -#endif -#if defined(SWIGPERL) - %perlcode { - sub solv::Solver::solve { - my ($self, $jobs) = @_; - my @j = map {($_->{'how'}, $_->{'what'})} @$jobs; - return $self->solve_helper(\@j); - } - } -#endif -#if defined(SWIGRUBY) -%init %{ -rb_eval_string( - "class Solv::Solver\n" - " def solve(jobs)\n" - " jl = []\n" - " jobs.each do |j| ; jl << j.how << j.what ; end\n" - " solve_helper(jl)\n" - " end\n" - "end\n" - ); -%} -#endif - %typemap(out) Queue solve_helper Queue2Array(Problem *, 1, new_Problem(arg1, id)); - %newobject solve_helper; - Queue solve_helper(Queue jobs) { - Queue q; - int i, cnt; - queue_init(&q); - solver_solve($self, &jobs); - cnt = solver_problem_count($self); - for (i = 1; i <= cnt; i++) - queue_push(&q, i); - return q; - } -#if defined(SWIGTCL) + %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id)); %newobject solve; Queue solve(Queue solvejobs) { @@ -3335,7 +3493,6 @@ rb_eval_string( queue_push(&q, i); return q; } -#endif %newobject transaction; Transaction *transaction() { @@ -3424,6 +3581,38 @@ rb_eval_string( bool write_testcase(const char *dir) { return testcase_write($self, dir, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0); } + + Queue raw_decisions(int filter=0) { + Queue q; + queue_init(&q); + solver_get_decisionqueue($self, &q); + if (filter) { + int i, j; + for (i = j = 0; i < q.count; i++) + if ((filter > 0 && q.elements[i] > 1) || + (filter < 0 && q.elements[i] < 0)) + q.elements[j++] = q.elements[i]; + queue_truncate(&q, j); + } + return q; + } + + %typemap(out) Queue get_recommended Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject get_recommended; + Queue get_recommended(bool noselected=0) { + Queue q; + queue_init(&q); + solver_get_recommendations($self, &q, NULL, noselected); + return q; + } + %typemap(out) Queue get_suggested Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject get_suggested; + Queue get_suggested(bool noselected=0) { + Queue q; + queue_init(&q); + solver_get_recommendations($self, NULL, &q, noselected); + return q; + } } %extend Transaction { @@ -3548,7 +3737,7 @@ rb_eval_string( int steptype(XSolvable *s, int mode) { return transaction_type($self, s->id, mode); } - int calc_installsizechange() { + long long calc_installsizechange() { return transaction_calc_installsizechange($self); } void order(int flags=0) { @@ -3629,6 +3818,11 @@ rb_eval_string( bool __ne__(XRule *xr) { return !XRule___eq__($self, xr); } +#if defined(SWIGPYTHON) + int __hash__() { + return $self->id; + } +#endif #if defined(SWIGPERL) || defined(SWIGTCL) %rename("repr") __repr__; #endif @@ -3686,9 +3880,15 @@ rb_eval_string( void set_id(Id solvid, Id keyname, DepId id) { repodata_set_id(repo_id2repodata($self->repo, $self->id), solvid, keyname, id); } + void set_num(Id solvid, Id keyname, unsigned long long num) { + repodata_set_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, num); + } void set_str(Id solvid, Id keyname, const char *str) { repodata_set_str(repo_id2repodata($self->repo, $self->id), solvid, keyname, str); } + void set_void(Id solvid, Id keyname) { + repodata_set_void(repo_id2repodata($self->repo, $self->id), solvid, keyname); + } void set_poolstr(Id solvid, Id keyname, const char *str) { repodata_set_poolstr(repo_id2repodata($self->repo, $self->id), solvid, keyname, str); } @@ -3703,9 +3903,27 @@ rb_eval_string( if (buf) repodata_set_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, solv_chksum_get_type(chksum), buf); } + void set_sourcepkg(Id solvid, const char *sourcepkg) { + repodata_set_sourcepkg(repo_id2repodata($self->repo, $self->id), solvid, sourcepkg); + } + void set_location(Id solvid, unsigned int mediano, const char *location) { + repodata_set_location(repo_id2repodata($self->repo, $self->id), solvid, mediano, 0, location); + } + void unset(Id solvid, Id keyname) { + repodata_unset(repo_id2repodata($self->repo, $self->id), solvid, keyname); + } const char *lookup_str(Id solvid, Id keyname) { return repodata_lookup_str(repo_id2repodata($self->repo, $self->id), solvid, keyname); } + Id lookup_id(Id solvid, Id keyname) { + return repodata_lookup_id(repo_id2repodata($self->repo, $self->id), solvid, keyname); + } + unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) { + return repodata_lookup_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, notfound); + } + bool lookup_void(Id solvid, Id keyname) { + return repodata_lookup_void(repo_id2repodata($self->repo, $self->id), solvid, keyname); + } Queue lookup_idarray(Id solvid, Id keyname) { Queue r; queue_init(&r); @@ -3729,6 +3947,18 @@ rb_eval_string( bool write(FILE *fp) { return repodata_write(repo_id2repodata($self->repo, $self->id), fp) == 0; } + Id str2dir(const char *dir, bool create=1) { + Repodata *data = repo_id2repodata($self->repo, $self->id); + return repodata_str2dir(data, dir, create); + } + const char *dir2str(Id did, const char *suf = 0) { + Repodata *data = repo_id2repodata($self->repo, $self->id); + return repodata_dir2str(data, did, suf); + } + void add_dirstr(Id solvid, Id keyname, Id dir, const char *str) { + Repodata *data = repo_id2repodata($self->repo, $self->id); + repodata_add_dirstr(data, solvid, keyname, dir, str); + } bool add_solv(FILE *fp, int flags = 0) { Repodata *data = repo_id2repodata($self->repo, $self->id); int r, oldstate = data->state; @@ -3754,6 +3984,11 @@ rb_eval_string( bool __ne__(XRepodata *xr) { return !XRepodata___eq__($self, xr); } +#if defined(SWIGPYTHON) + int __hash__() { + return $self->id; + } +#endif #if defined(SWIGPERL) || defined(SWIGTCL) %rename("repr") __repr__; #endif diff --git a/libsolv-0.6.15/bindings/tcl/CMakeLists.txt b/libsolv-0.7.2/bindings/tcl/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/bindings/tcl/CMakeLists.txt rename to libsolv-0.7.2/bindings/tcl/CMakeLists.txt diff --git a/libsolv-0.6.15/bindings/tcl/solv.tm.in b/libsolv-0.7.2/bindings/tcl/solv.tm.in similarity index 100% rename from libsolv-0.6.15/bindings/tcl/solv.tm.in rename to libsolv-0.7.2/bindings/tcl/solv.tm.in diff --git a/libsolv-0.6.15/cmake/modules/FindCheck.cmake b/libsolv-0.7.2/cmake/modules/FindCheck.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindCheck.cmake rename to libsolv-0.7.2/cmake/modules/FindCheck.cmake diff --git a/libsolv-0.6.15/cmake/modules/FindEXPAT.cmake b/libsolv-0.7.2/cmake/modules/FindEXPAT.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindEXPAT.cmake rename to libsolv-0.7.2/cmake/modules/FindEXPAT.cmake diff --git a/libsolv-0.6.15/cmake/modules/FindLZMA.cmake b/libsolv-0.7.2/cmake/modules/FindLZMA.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindLZMA.cmake rename to libsolv-0.7.2/cmake/modules/FindLZMA.cmake diff --git a/libsolv-0.6.15/cmake/modules/FindLibSolv.cmake b/libsolv-0.7.2/cmake/modules/FindLibSolv.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindLibSolv.cmake rename to libsolv-0.7.2/cmake/modules/FindLibSolv.cmake diff --git a/libsolv-0.6.15/cmake/modules/FindPackageHandleStandardArgs.cmake b/libsolv-0.7.2/cmake/modules/FindPackageHandleStandardArgs.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindPackageHandleStandardArgs.cmake rename to libsolv-0.7.2/cmake/modules/FindPackageHandleStandardArgs.cmake diff --git a/libsolv-0.6.15/cmake/modules/FindRuby.cmake b/libsolv-0.7.2/cmake/modules/FindRuby.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/FindRuby.cmake rename to libsolv-0.7.2/cmake/modules/FindRuby.cmake diff --git a/libsolv-0.6.15/cmake/modules/_CMakeParseArguments.cmake b/libsolv-0.7.2/cmake/modules/_CMakeParseArguments.cmake similarity index 100% rename from libsolv-0.6.15/cmake/modules/_CMakeParseArguments.cmake rename to libsolv-0.7.2/cmake/modules/_CMakeParseArguments.cmake diff --git a/libsolv-0.6.15/doc/CMakeLists.txt b/libsolv-0.7.2/doc/CMakeLists.txt similarity index 83% rename from libsolv-0.6.15/doc/CMakeLists.txt rename to libsolv-0.7.2/doc/CMakeLists.txt index 13e086c..66011b4 100644 --- a/libsolv-0.6.15/doc/CMakeLists.txt +++ b/libsolv-0.7.2/doc/CMakeLists.txt @@ -4,7 +4,7 @@ SET (libsolv_MANPAGES3 libsolv-pool.3) SET (libsolv_MANPAGES1 - mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1) + mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 repo2solv.1 solv.1) IF (ENABLE_RPMDB) SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} rpmdb2solv.1 rpms2solv.1) @@ -42,6 +42,10 @@ IF (ENABLE_APPDATA) SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} appdata2solv.1) ENDIF (ENABLE_APPDATA) +# prepend gen directory +STRING(REGEX REPLACE "([^;]+)" "gen/\\1" libsolv_MANPAGES1 "${libsolv_MANPAGES1}") +STRING(REGEX REPLACE "([^;]+)" "gen/\\1" libsolv_MANPAGES3 "${libsolv_MANPAGES3}") + INSTALL(FILES ${libsolv_MANPAGES3} DESTINATION "${MAN_INSTALL_DIR}/man3") diff --git a/libsolv-0.6.15/doc/Makefile.gen b/libsolv-0.7.2/doc/Makefile.gen similarity index 76% rename from libsolv-0.6.15/doc/Makefile.gen rename to libsolv-0.7.2/doc/Makefile.gen index 84a1095..e9f1b69 100644 --- a/libsolv-0.6.15/doc/Makefile.gen +++ b/libsolv-0.7.2/doc/Makefile.gen @@ -1,4 +1,6 @@ +VPATH = gen + man: man3 man1 man3: libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libsolv-pool.3 @@ -6,17 +8,17 @@ man3: libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libso man1: mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 rpmdb2solv.1 rpms2solv.1 \ rpmmd2solv.1 repomdxml2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1 \ helix2solv.1 susetags2solv.1 comps2solv.1 deb2solv.1 mdk2solv.1 \ - archpkgs2solv.1 archrepo2solv.1 appdata2solv.1 + archpkgs2solv.1 archrepo2solv.1 appdata2solv.1 repo2solv.1 solv.1 html: libsolv.html libsolv-bindings.html libsolv-constantids.html libsolv-history.html libsolv-pool.html .SUFFIXES: .html .3 .1 .txt .txt.1: - a2x -f manpage $< + a2x -f manpage -D gen $< .txt.3: - a2x -f manpage $< + a2x -f manpage -D gen $< .txt.html: - a2x -f xhtml $< + a2x -f xhtml -D gen $< diff --git a/libsolv-0.6.15/doc/appdata2solv.txt b/libsolv-0.7.2/doc/appdata2solv.txt similarity index 96% rename from libsolv-0.6.15/doc/appdata2solv.txt rename to libsolv-0.7.2/doc/appdata2solv.txt index 3ccb4b5..c31311a 100644 --- a/libsolv-0.6.15/doc/appdata2solv.txt +++ b/libsolv-0.7.2/doc/appdata2solv.txt @@ -37,3 +37,7 @@ mergesolv(1) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/archpkgs2solv.txt b/libsolv-0.7.2/doc/archpkgs2solv.txt similarity index 96% rename from libsolv-0.6.15/doc/archpkgs2solv.txt rename to libsolv-0.7.2/doc/archpkgs2solv.txt index 2a17066..4ce3155 100644 --- a/libsolv-0.6.15/doc/archpkgs2solv.txt +++ b/libsolv-0.7.2/doc/archpkgs2solv.txt @@ -33,3 +33,7 @@ pacman(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/archrepo2solv.txt b/libsolv-0.7.2/doc/archrepo2solv.txt similarity index 95% rename from libsolv-0.6.15/doc/archrepo2solv.txt rename to libsolv-0.7.2/doc/archrepo2solv.txt index 3f5b138..1a7791c 100644 --- a/libsolv-0.6.15/doc/archrepo2solv.txt +++ b/libsolv-0.7.2/doc/archrepo2solv.txt @@ -29,3 +29,7 @@ pacman(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/comps2solv.txt b/libsolv-0.7.2/doc/comps2solv.txt similarity index 94% rename from libsolv-0.6.15/doc/comps2solv.txt rename to libsolv-0.7.2/doc/comps2solv.txt index 23e304e..8d98708 100644 --- a/libsolv-0.6.15/doc/comps2solv.txt +++ b/libsolv-0.7.2/doc/comps2solv.txt @@ -27,3 +27,7 @@ mergesolv(1), createrepo(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/deb2solv.txt b/libsolv-0.7.2/doc/deb2solv.txt similarity index 95% rename from libsolv-0.6.15/doc/deb2solv.txt rename to libsolv-0.7.2/doc/deb2solv.txt index 0907383..cb42ff7 100644 --- a/libsolv-0.6.15/doc/deb2solv.txt +++ b/libsolv-0.7.2/doc/deb2solv.txt @@ -33,3 +33,7 @@ deb(5), dpkg-deb(1) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/deltainfoxml2solv.txt b/libsolv-0.7.2/doc/deltainfoxml2solv.txt similarity index 95% rename from libsolv-0.6.15/doc/deltainfoxml2solv.txt rename to libsolv-0.7.2/doc/deltainfoxml2solv.txt index f14a843..13c987d 100644 --- a/libsolv-0.6.15/doc/deltainfoxml2solv.txt +++ b/libsolv-0.7.2/doc/deltainfoxml2solv.txt @@ -27,3 +27,7 @@ mergesolv(1), createrepo(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/dumpsolv.txt b/libsolv-0.7.2/doc/dumpsolv.txt similarity index 93% rename from libsolv-0.6.15/doc/dumpsolv.txt rename to libsolv-0.7.2/doc/dumpsolv.txt index ec2d771..b09aa97 100644 --- a/libsolv-0.6.15/doc/dumpsolv.txt +++ b/libsolv-0.7.2/doc/dumpsolv.txt @@ -24,3 +24,7 @@ Write the contents in JSON format. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/filters/xcode.conf b/libsolv-0.7.2/doc/filters/xcode.conf similarity index 100% rename from libsolv-0.6.15/doc/filters/xcode.conf rename to libsolv-0.7.2/doc/filters/xcode.conf diff --git a/libsolv-0.6.15/doc/filters/xcode.pl b/libsolv-0.7.2/doc/filters/xcode.pl similarity index 100% rename from libsolv-0.6.15/doc/filters/xcode.pl rename to libsolv-0.7.2/doc/filters/xcode.pl diff --git a/libsolv-0.6.15/doc/appdata2solv.1 b/libsolv-0.7.2/doc/gen/appdata2solv.1 similarity index 92% rename from libsolv-0.6.15/doc/appdata2solv.1 rename to libsolv-0.7.2/doc/gen/appdata2solv.1 index b5fdf9f..4fe217d 100644 --- a/libsolv-0.6.15/doc/appdata2solv.1 +++ b/libsolv-0.7.2/doc/gen/appdata2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: appdata2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "APPDATA2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "APPDATA2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/archpkgs2solv.1 b/libsolv-0.7.2/doc/gen/archpkgs2solv.1 similarity index 92% rename from libsolv-0.6.15/doc/archpkgs2solv.1 rename to libsolv-0.7.2/doc/gen/archpkgs2solv.1 index 6052aee..bb47364 100644 --- a/libsolv-0.6.15/doc/archpkgs2solv.1 +++ b/libsolv-0.7.2/doc/gen/archpkgs2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: archpkgs2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "ARCHPKGS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "ARCHPKGS2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/archrepo2solv.1 b/libsolv-0.7.2/doc/gen/archrepo2solv.1 similarity index 91% rename from libsolv-0.6.15/doc/archrepo2solv.1 rename to libsolv-0.7.2/doc/gen/archrepo2solv.1 index 94f5c41..9d7c868 100644 --- a/libsolv-0.6.15/doc/archrepo2solv.1 +++ b/libsolv-0.7.2/doc/gen/archrepo2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: archrepo2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "ARCHREPO2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "ARCHREPO2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/comps2solv.1 b/libsolv-0.7.2/doc/gen/comps2solv.1 similarity index 91% rename from libsolv-0.6.15/doc/comps2solv.1 rename to libsolv-0.7.2/doc/gen/comps2solv.1 index c6f8d32..2be0bc9 100644 --- a/libsolv-0.6.15/doc/comps2solv.1 +++ b/libsolv-0.7.2/doc/gen/comps2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: comps2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "COMPS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "COMPS2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/deb2solv.1 b/libsolv-0.7.2/doc/gen/deb2solv.1 similarity index 92% rename from libsolv-0.6.15/doc/deb2solv.1 rename to libsolv-0.7.2/doc/gen/deb2solv.1 index 95f5091..7da3828 100644 --- a/libsolv-0.6.15/doc/deb2solv.1 +++ b/libsolv-0.7.2/doc/gen/deb2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: deb2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "DEB2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "DEB2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/deltainfoxml2solv.1 b/libsolv-0.7.2/doc/gen/deltainfoxml2solv.1 similarity index 91% rename from libsolv-0.6.15/doc/deltainfoxml2solv.1 rename to libsolv-0.7.2/doc/gen/deltainfoxml2solv.1 index 11cda74..0ef0bb4 100644 --- a/libsolv-0.6.15/doc/deltainfoxml2solv.1 +++ b/libsolv-0.7.2/doc/gen/deltainfoxml2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: deltainfoxml2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "DELTAINFOXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "DELTAINFOXML2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/dumpsolv.1 b/libsolv-0.7.2/doc/gen/dumpsolv.1 similarity index 91% rename from libsolv-0.6.15/doc/dumpsolv.1 rename to libsolv-0.7.2/doc/gen/dumpsolv.1 index cb6a136..eed45fe 100644 --- a/libsolv-0.6.15/doc/dumpsolv.1 +++ b/libsolv-0.7.2/doc/gen/dumpsolv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: dumpsolv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "DUMPSOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "DUMPSOLV" "1" "07/25/2017" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/helix2solv.1 b/libsolv-0.7.2/doc/gen/helix2solv.1 similarity index 90% rename from libsolv-0.6.15/doc/helix2solv.1 rename to libsolv-0.7.2/doc/gen/helix2solv.1 index 07d9497..1f37339 100644 --- a/libsolv-0.6.15/doc/helix2solv.1 +++ b/libsolv-0.7.2/doc/gen/helix2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: helix2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 12/14/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "HELIX2SOLV" "1" "12/14/2015" "libsolv" "LIBSOLV" +.TH "HELIX2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/installcheck.1 b/libsolv-0.7.2/doc/gen/installcheck.1 similarity index 92% rename from libsolv-0.6.15/doc/installcheck.1 rename to libsolv-0.7.2/doc/gen/installcheck.1 index 7ee3e4d..492bd80 100644 --- a/libsolv-0.6.15/doc/installcheck.1 +++ b/libsolv-0.7.2/doc/gen/installcheck.1 @@ -1,13 +1,13 @@ '\" t .\" Title: installcheck .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "INSTALLCHECK" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "INSTALLCHECK" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/libsolv-bindings.3 b/libsolv-0.7.2/doc/gen/libsolv-bindings.3 similarity index 89% rename from libsolv-0.6.15/doc/libsolv-bindings.3 rename to libsolv-0.7.2/doc/gen/libsolv-bindings.3 index 14bf96c..9f84c77 100644 --- a/libsolv-0.6.15/doc/libsolv-bindings.3 +++ b/libsolv-0.7.2/doc/gen/libsolv-bindings.3 @@ -1,13 +1,13 @@ '\" t .\" Title: Libsolv-Bindings .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 12/14/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 12/06/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV\-BINDINGS" "3" "12/14/2015" "libsolv" "LIBSOLV" +.TH "LIBSOLV\-BINDINGS" "3" "12/06/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -87,7 +87,7 @@ my \fI$iter\fR \fB=\fR \fI$pool\fR\fB\->solvables_iter()\fR; .sp As a downside of this approach, iterator objects cannot have attributes\&. .sp -If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the stack: +If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the perl stack: .sp .if n \{\ .RS 4 @@ -200,7 +200,7 @@ The bindings define stringification for many classes, some also have a \fIrepr\f .RE .\} .sp -Constants are attributes of the classes: +Constants are attributes of the corresponding classes: .sp .if n \{\ .RS 4 @@ -399,7 +399,7 @@ Swig implements all constants as numeric variables, constants belonging to a lib .RS 4 .\} .nf -\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR \fB1\fR +\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR \fB1\fR \fBputs [\fR\fI$solvable\fR \fBlookup_str\fR \fI$solv::SOLVABLE_SUMMARY\fR\fB]\fR .fi .if n \{\ @@ -441,7 +441,7 @@ Access the meta section of a repository or repodata area\&. This is like an extr .PP \fBSOLVID_POS\fR .RS 4 -Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you do not need this constant\&. +Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you most likely do not need this constant\&. .RE .sp Constant string Ids @@ -569,7 +569,7 @@ Promote the epoch of the providing dependency to the requesting dependency if it .PP \fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR .RS 4 -Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them recently\&. +Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them since rpm\-4\&.9\&.0\&. .RE .PP \fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR @@ -584,7 +584,7 @@ An implicit obsoletes is the internal mechanism to remove the old package on an .PP \fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR .RS 4 -Rpm\(cqs multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&. +Rpm\(cqs multilib implementation distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&. .RE .PP \fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR @@ -594,7 +594,7 @@ Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the sa .PP \fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR .RS 4 -New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package\&. +Since version 4\&.9\&.0 rpm considers the obsoletes of installed packages when checking for dependency conflicts, thus you may not install a package that is obsoleted by some other installed package unless you also erase the other package\&. .RE .PP \fBPOOL_FLAG_HAVEDISTEPOCH\fR @@ -604,7 +604,7 @@ Mandriva added a new field called distepoch that gets checked in version compari .PP \fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR .RS 4 -If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&. +If a package is installed in multiversion mode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&. .RE .PP \fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR @@ -684,7 +684,7 @@ my \fI$value\fR \fB=\fR \fI$pool\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR; .RE .\} .sp -Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solv package dependencies for some other system than yours\&. +Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solve package dependencies for some other system\&. .sp .if n \{\ .RS 4 @@ -830,7 +830,7 @@ Some package managers like rpm allow dependencies on files contained in other pa .RE .\} .sp -Create the internal \(lqwhatprovides\(rq hash over all of the provides of all packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&. +Create the internal \(lqwhatprovides\(rq hash over all of the provides of all installable packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&. .sp .if n \{\ .RS 4 @@ -881,6 +881,36 @@ my \fI$offset\fR \fB=\fR \fI$pool\fR\fB\->towhatprovides(\e\fR\fI@ids\fR\fB)\fR; .RS 4 .\} .nf +\fBvoid set_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB, bool\fR \fIvalue\fR \fB= 1)\fR +\fI$pool\fR\fB\->set_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB, 1)\fR; +\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fITrue\fR\fB)\fR +\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fItrue\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Manually set a namespace provides entry in the whatprovides index\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid flush_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB)\fR +\fI$pool\fR\fB\->flush_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB)\fR; +\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR +\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Flush the cache of all namespaceprovides matching the specified namespace dependency\&. You can use zero as a wildcard argument\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBbool isknownarch(DepId\fR \fIid\fR\fB)\fR my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->isknownarch(\fR\fI$id\fR\fB)\fR; \fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch(\fR\fIid\fR\fB)\fR @@ -920,7 +950,7 @@ my \fI$job\fR \fB=\fR \fI$pool\fR\fB\->Job(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\ .RE .\} .sp -Create a new Job object\&. Kind of low level, in most cases you would use a Selection or Dep job constructor instead\&. +Create a new Job object\&. Kind of low level, in most cases you would instead use a Selection or Dep job constructor\&. .sp .if n \{\ .RS 4 @@ -971,6 +1001,36 @@ Create a selection by matching packages against the specified string\&. See the .RS 4 .\} .nf +\fBSelection matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a selection by matching package dependencies against the specified string\&. This can be used if you want to match other dependency types than \(lqprovides\(rq\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSelection matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fIdep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a selection by matching package dependencies against the specified dependency\&. This may be faster than matchdeps and also works with complex dependencies\&. The downside is that you cannot use globs or case insensitive matching\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid setpooljobs(Jobs *\fR\fIjobs\fR\fB)\fR \fI$pool\fR\fB\->setpooljobs(\e\fR\fI@jobs\fR\fB)\fR; \fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR @@ -993,7 +1053,7 @@ Create a selection by matching packages against the specified string\&. See the .RE .\} .sp -Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled or must not be erased\&. +Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled, or which packages must not be erased\&. .sp .if n \{\ .RS 4 @@ -1251,7 +1311,7 @@ my \fI$id\fR \fB=\fR \fIpool\fR\fB\->rel2id(\fR\fI$nameid\fR\fB,\fR \fI$evrid\fR .RE .\} .sp -Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, the \fIflags\fR describing the relation, and a version part\&. The flags are: +Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, \fIflags\fR describing the relation, and a version part\&. The flags are: .sp .if n \{\ .RS 4 @@ -1345,7 +1405,7 @@ my \fI$reldep\fR \fB=\fR \fI$dep\fR\fB\->Rel(\fR\fI$flags\fR\fB,\fR \fI$evrdep\f .RE .\} .sp -Create a relational dependency from to string dependencies and a flags argument\&. See the pool\(cqs rel2id method for a description of the flags\&. +Create a relational dependency from the caller dependency, the flags, and a dependency describing the \(lqversion\(rq part\&. See the pool\(cqs rel2id method for a description of the flags\&. .sp .if n \{\ .RS 4 @@ -1420,7 +1480,7 @@ Same as calling the str() method\&. .RE .\} .sp -The dependencies are equal if they are part of the same pool and have the same ids\&. +Two dependencies are equal if they are part of the same pool and have the same ids\&. .SH "THE REPOSITORY CLASS" .sp A Repository describes a group of packages, normally coming from the same source\&. Repositories are created by the Pool\(cqs add_repo() method\&. @@ -1549,7 +1609,7 @@ Return a Datapos object of the repodata\(cqs metadata\&. You can use the lookup .PP \fBREPO_REUSE_REPODATA\fR .RS 4 -Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new one\&. +Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new area\&. .RE .PP \fBREPO_NO_INTERNALIZE\fR @@ -2070,9 +2130,9 @@ Add the contents of the mageia/mandriva repository metadata (the "synthesis\&.hd .\} .nf \fBbool add_mdk_info(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR -\fI$repo\fR\fB\->add_mdk(\fR\fI$fp\fR\fB)\fR; -\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR -\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR +\fI$repo\fR\fB\->add_mdk_info(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_mdk_info(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_mdk_info(\fR\fIfp\fR\fB)\fR .fi .if n \{\ .RE @@ -2332,8 +2392,8 @@ my \fI$string\fR \fB=\fR \fI$solvable\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\f .nf \fBId lookup_id(Id\fR \fIkeyname\fR\fB)\fR my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR; -\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR -\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR +\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR +\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR .fi .if n \{\ .RE @@ -2343,7 +2403,7 @@ my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR; .RS 4 .\} .nf -\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR +\fBunsigned long long lookup_num(Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR my \fI$num\fR \fB=\fR \fI$solvable\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR; \fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR \fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR @@ -2411,9 +2471,9 @@ Generic lookup methods\&. Retrieve data stored for the specific keyname\&. The l .\} .nf \fBconst char *lookup_location(unsigned int *\fR\fIOUTPUT\fR\fB)\fR; -my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR; -\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR -\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR +my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR; +\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR +\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR .fi .if n \{\ .RE @@ -2425,6 +2485,21 @@ Return a tuple containing the on\-media location and an optional media number fo .RS 4 .\} .nf +\fBconst char *lookup_sourcepkg()\fR; +my \fI$sourcepkg\fR \fB=\fR \fI$solvable\fR\fB\->lookup_sourcepkg()\fR; +\fIsourcepkg\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_sourcepkg()\fR +\fIsourcepkg\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_sourcepkg()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a sourcepkg name associated with solvable\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR my \fI$di\fR \fB=\fR \fI$solvable\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; \fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR @@ -2514,8 +2589,8 @@ Return true if the solvable is installed on the system\&. .nf \fBbool identical(Solvable *\fR\fIother\fR\fB)\fR \fI$solvable\fR\fB\->identical(\fR\fI$other\fR\fB)\fR -\fI$solvable\fR\fB\&.identical(\fR\fIother\fR\fB)\fR -\fI$solvable\fR\fB\&.identical?(\fR\fIother\fR\fB)\fR +\fIsolvable\fR\fB\&.identical(\fR\fIother\fR\fB)\fR +\fIsolvable\fR\fB\&.identical?(\fR\fIother\fR\fB)\fR .fi .if n \{\ .RE @@ -2528,9 +2603,9 @@ Return true if the two solvables are identical\&. .\} .nf \fBint evrcmp(Solvable *\fR\fIother\fR\fB)\fR -\fI$solvable\fR\fB\->evrcmp(\fR\fIother\fR\fB)\fR -\fI$solvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR -\fI$solvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR +\fI$solvable\fR\fB\->evrcmp(\fR\fI$other\fR\fB)\fR +\fIsolvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR +\fIsolvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR .fi .if n \{\ .RE @@ -2542,6 +2617,21 @@ Returns \-1 if the epoch/version/release of the solvable is less than the one fr .RS 4 .\} .nf +\fBint matchesdep(Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +\fI$solvable\fR\fB\->matchesdep(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR +\fIsolvable\fR\fB\&.matchesdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +\fIsolvable\fR\fB\&.matchesdep?(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the dependencies stored in keyname match the specified dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR my \fI$sel\fR \fB=\fR \fI$solvable\fR\fB\->Selection()\fR; \fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR @@ -2673,7 +2763,7 @@ Do a sub\-search in the array stored in keyname\&. .\} .nf \fBvoid skip_solvable()\fR; -\fI$di\fR\fB\->kip_solvable()\fR; +\fI$di\fR\fB\->skip_solvable()\fR; \fIdi\fR\fB\&.skip_solvable()\fR \fIdi\fR\fB\&.skip_solvable()\fR .fi @@ -2978,12 +3068,37 @@ Create the selection by matching the canonical representation of the package\&. .PP \fBSELECTION_DOTARCH\fR .RS 4 -Allow an \(lq\&.\(rq suffix when matching names or provides\&. +Allow an "\&." suffix when matching names or provides\&. .RE .PP \fBSELECTION_REL\fR .RS 4 -Allow the specification of a relation when matching names or provides, e\&.g\&. "name >= 1\&.2"\&. +Allow the specification of a relation when matching names or dependencies, e\&.g\&. "name >= 1\&.2"\&. +.RE +.PP +\fBSELECTION_GLOB\fR +.RS 4 +Allow glob matching for package names, package provides, and file names\&. +.RE +.PP +\fBSELECTION_NOCASE\fR +.RS 4 +Ignore case when matching package names, package provides, and file names\&. +.RE +.PP +\fBSELECTION_FLAT\fR +.RS 4 +Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&. +.RE +.PP +\fBSELECTION_SKIP_KIND\fR +.RS 4 +Remove a "packagekind:" prefix from the package names\&. +.RE +.PP +\fBSELECTION_MATCH_DEPSTR\fR +.RS 4 +When matching dependencies, do a string match on the result of dep2str instead of using the normal dependency intersect algorithm\&. .RE .PP \fBSELECTION_INSTALLED_ONLY\fR @@ -3001,19 +3116,34 @@ Limit the package search to source packages only\&. Extend the package search to also match source packages\&. The default is only to match binary packages\&. .RE .PP -\fBSELECTION_GLOB\fR +\fBSELECTION_WITH_DISABLED\fR .RS 4 -Allow glob matching for package names, package provides, and file names\&. +Extend the package search to also include disabled packages\&. .RE .PP -\fBSELECTION_NOCASE\fR +\fBSELECTION_WITH_BADARCH\fR .RS 4 -Ignore case when matching package names, package provides, and file names\&. +Extend the package search to also include packages that are not installable on the configured architecture\&. .RE .PP -\fBSELECTION_FLAT\fR +\fBSELECTION_WITH_ALL\fR .RS 4 -Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&. +Shortcut for selecting the three modifiers above\&. +.RE +.PP +\fBSELECTION_ADD\fR +.RS 4 +Add the result of the match to the current selection instead of replacing it\&. +.RE +.PP +\fBSELECTION_SUBTRACT\fR +.RS 4 +Remove the result of the match to the current selection instead of replacing it\&. +.RE +.PP +\fBSELECTION_FILTER\fR +.RS 4 +Intersect the result of the match to the current selection instead of replacing it\&. .RE .SS "ATTRIBUTES" .sp @@ -3031,28 +3161,28 @@ Return only one selection element describing the selected packages\&. The defaul .\} .sp Back pointer to pool\&. -.SS "METHODS" .sp .if n \{\ .RS 4 .\} .nf -\fBint flags()\fR; -my \fI$flags\fR \fB=\fR \fI$sel\fR\fB\->flags()\fR; -\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR -\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR +\fBint flags;\fR /* read only */ +\fI$sel\fR\fB\->{flags}\fR +\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR +\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR .fi .if n \{\ .RE .\} .sp -Return the result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&. +The result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&. +.SS "METHODS" .sp .if n \{\ .RS 4 .\} .nf -\fBbool isempty()\fR; +\fBbool isempty()\fR \fI$sel\fR\fB\->isempty()\fR \fIsel\fR\fB\&.isempty()\fR \fIsel\fR\fB\&.isempty?\fR @@ -3067,6 +3197,21 @@ Return true if the selection is empty, i\&.e\&. no package could be matched\&. .RS 4 .\} .nf +\fBSelection clone(int\fR \fIflags\fR \fB= 0)\fR +my \fI$cloned\fR \fB=\fR \fI$sel\fR\fB\->clone()\fR; +\fIcloned\fR \fB=\fR \fIsel\fR\fB\&.clone()\fR +\fIcloned\fR \fB=\fR \fIsel\fR\fB\&.clone()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a copy of a selection\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid filter(Selection *\fR\fIother\fR\fB)\fR \fI$sel\fR\fB\->filter(\fR\fI$other\fR\fB)\fR; \fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR @@ -3097,6 +3242,21 @@ Build the union of two selections\&. All packages of the other selection will be .RS 4 .\} .nf +\fBvoid subtract(Selection *\fR\fIother\fR\fB)\fR +\fI$sel\fR\fB\->subtract(\fR\fI$other\fR\fB)\fR; +\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR +\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Remove the packages of the other selection from the packages of the selection object\&. Does an in\-place modification\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid add_raw(Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR \fI$sel\fR\fB\->add_raw(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR; \fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR @@ -3106,7 +3266,7 @@ Build the union of two selections\&. All packages of the other selection will be .RE .\} .sp -Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&. +Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&. Note that the selection flags are no longer meaningful after the add_raw operation\&. .sp .if n \{\ .RS 4 @@ -3142,6 +3302,51 @@ Convert a selection into an array of Solvable objects\&. .RS 4 .\} .nf +\fBvoid select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR +\fI$sel\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR +\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Do a select operation and combine the result with the current selection\&. You can choose the desired combination method by using either the SELECTION_ADD, SELECTION_SUBTRACT, or SELECTION_FILTER flag\&. If none of the flags are used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +\fI$sel\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Do a matchdeps operation and combine the result with the current selection\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +\fI$sel\fR\fB\->matchdepid(\fR\fI$dep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Do a matchdepid operation and combine the result with the current selection\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fB\fR my \fI$str\fR \fB=\fR \fI$sel\fR\fB\->str\fR; \fIstr\fR \fB= str(\fR\fIsel\fR\fB)\fR @@ -3256,6 +3461,16 @@ The matching installed packages are considered to be installed by a user, thus n Allow the solver to deinstall the matching installed packages if they get into the way of resolving a dependency\&. This is like the SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages\&. .RE .PP +\fBSOLVER_FAVOR\fR +.RS 4 +Prefer the specified packages if the solver encounters an alternative\&. If a job contains multiple matching favor/disfavor elements, the last one takes precedence\&. +.RE +.PP +\fBSOLVER_DISFAVOR\fR +.RS 4 +Avoid the specified packages if the solver encounters an alternative\&. This can also be used to block recommended or supplemented packages from being installed\&. +.RE +.PP \fBSOLVER_JOBMASK\fR .RS 4 A mask containing all the above action bits\&. @@ -3519,6 +3734,11 @@ Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode\&. If multiple packages obsolete an installed package, the solver checks the provides of every such package and ignores all packages that do not provide the installed package name\&. Thus, you can have an official update candidate that provides the old name, and other packages that also obsolete the package but are not considered for updating\&. If you cannot use this feature, you can turn it off by setting this flag\&. .RE .PP +\fBSOLVER_FLAG_NEED_UPDATEPROVIDE\fR +.RS 4 +This is somewhat the opposite of SOLVER_FLAG_NO_UPDATEPROVIDE: Only packages that provide the installed package names are considered for updating\&. +.RE +.PP \fBSOLVER_FLAG_SPLITPROVIDES\fR .RS 4 Make the solver aware of special provides of the form \(lq:\(rq used in SUSE systems to support package splits\&. @@ -3561,7 +3781,27 @@ Ignore dependencies of orphaned packages that get in the way of resolving non\-o .PP \fBSOLVER_FLAG_FOCUS_INSTALLED\fR .RS 4 -Resolve installed packages before resolving the given job\&. Setting this flag means that the solver will prefer picking a package version that fits the other installed packages over updating installed packages\&. +Resolve installed packages before resolving the given jobs\&. Setting this flag means that the solver will prefer picking a package version that fits the other installed packages over updating installed packages\&. +.RE +.PP +\fBSOLVER_FLAG_FOCUS_BEST\fR +.RS 4 +First resolve the given jobs, then the dependencies of the resulting packages, then resolve all already installed packages\&. This will result in more packages being updated as when the flag is not used\&. +.RE +.PP +\fBSOLVER_FLAG_INSTALL_ALSO_UPDATES\fR +.RS 4 +Update the package if a job is already fulfilled by an installed package\&. +.RE +.PP +\fBSOLVER_FLAG_YUM_OBSOLETES\fR +.RS 4 +Turn on yum\-like package split handling\&. See the yum documentation for more details\&. +.RE +.PP +\fBSOLVER_FLAG_URPM_REORDER\fR +.RS 4 +Turn on urpm like package reordering for kernel packages\&. See the urpm documentation for more details\&. .RE .sp Basic rule types: @@ -3903,6 +4143,36 @@ my \fB(\fR\fI$reason\fR\fB,\fR \fI$rule\fR\fB) =\fR \fI$solver\fR\fB\->describe_ .\} .sp Return the reason why a specific solvable was installed or erased\&. For most of the reasons the rule that triggered the decision is also returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *get_recommended(bool\fR \fInoselected\fR\fB=0)\fR; +my \fI@solvables\fR \fB=\fR \fI$solver\fR\fB\->get_recommended()\fR; +\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_recommended()\fR +\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_recommended()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that are recommended by the solver run result\&. This includes solvables included in the result, set noselected if you want to filter those\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *get_suggested(bool\fR \fInoselected\fR\fB=0)\fR; +my \fI@solvables\fR \fB=\fR \fI$solver\fR\fB\->get_suggested()\fR; +\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_suggested()\fR +\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_suggested()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that are suggested by the solver run result\&. This includes solvables included in the result, set noselected if you want to filter those\&. .SH "THE PROBLEM CLASS" .sp Problems are the way of the solver to interact with the user\&. You can simply list all problems and terminate your program, but a better way is to present solutions to the user and let him pick the ones he likes\&. @@ -3960,8 +4230,8 @@ Return the rule that caused the problem\&. Of course in most situations there is .nf \fBRule *findallproblemrules(bool\fR \fIunfiltered\fR \fB= 0)\fR my \fI@probrules\fR \fB=\fR \fI$problem\fR\fB\->findallproblemrules()\fR; -\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrule()\fR -\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrule()\fR +\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrules()\fR +\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrules()\fR .fi .if n \{\ .RE @@ -4466,7 +4736,7 @@ my \fI$job\fR \fB=\fR \fI$solutionelement\fR\fB\->Job()\fR; .RE .\} .sp -Create a job that implements the solution element\&. Add this job to the array of jobs for all elements of type different to SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&. For the later two, a SOLVER_NOOB Job is created, you should replace the old job with the new one\&. +Create a job that implements the solution element\&. Add this job to the array of jobs for all elements of type different to SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&. For the latter two, a SOLVER_NOOB Job is created, you should replace the old job with the new one\&. .sp .if n \{\ .RS 4 @@ -4779,7 +5049,7 @@ For installed packages, returns all of the packages that replace us\&. For to be .RS 4 .\} .nf -\fBint calc_installsizechange()\fR; +\fBlong long calc_installsizechange()\fR; my \fI$change\fR \fB=\fR \fI$trans\fR\fB\->calc_installsizechange()\fR; \fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR \fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR @@ -5352,6 +5622,49 @@ Write the contents of the repodata area as solv file\&. .RS 4 .\} .nf +\fBId str2dir(const char *\fR\fIdir\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$did\fR \fB=\fR \fIdata\fR\fB\->str2dir(\fR\fI$dir\fR\fB)\fR; +\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR +\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *dir2str(Id\fR \fIdid\fR\fB, const char *\fR\fIsuffix\fR \fB= 0)\fR +\fI$dir\fR \fB=\fR \fIpool\fR\fB\->dir2str(\fR\fI$did\fR\fB)\fR; +\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR +\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convert a string (directory) into an Id and back\&. If the string is currently not in the pool and \fIcreate\fR is false, zero is returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_dirstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIdir\fR\fB, const char *\fR\fIstr\fR\fB)\fR +\fI$data\fR\fB\->add_dirstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$dir\fR\fB,\fR \fI$string\fR\fB)\fR +\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR +\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a file path consisting of a dirname Id and a basename string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR; \fI$data\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR; \fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR @@ -5391,7 +5704,7 @@ Create stub repodatas from the information stored in the repodata meta area\&. .RE .\} .sp -Extend the repodata so that it has the same size as the repo it belongs to\&. This method is only needed when switching to a just written repodata extension to make the repodata match the written extension (which is always of the size of the repo)\&. +Extend the repodata so that it has the same size as the repo it belongs to\&. This method is needed when setting up a new extension repodata so that it matches the repository size\&. It is also needed when switching to a just written repodata extension to make the repodata match the written extension (which is always of the size of the repo)\&. .sp .if n \{\ .RS 4 @@ -5426,6 +5739,45 @@ my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI .RS 4 .\} .nf +\fBconst char *lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR +my \fI$num\fR \fB=\fR \fI$data\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool lookup_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$bool\fR \fB=\fR \fI$data\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR my \fI@ids\fR \fB=\fR \fI$data\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; \fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR @@ -5455,6 +5807,19 @@ Lookup functions\&. Return the data element stored in the specified solvable\&. .RS 4 .\} .nf +\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR; +\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR; +\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR +\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid set_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR; \fI$data\fR\fB\->set_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR; \fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR @@ -5468,10 +5833,23 @@ Lookup functions\&. Return the data element stored in the specified solvable\&. .RS 4 .\} .nf -\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR; -\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR; -\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR -\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR +\fBvoid set_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInum\fR\fB)\fR; +\fI$data\fR\fB\->set_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$num\fR\fB)\fR; +\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR +\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR; +\fI$data\fR\fB\->set_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR .fi .if n \{\ .RE @@ -5507,6 +5885,32 @@ Lookup functions\&. Return the data element stored in the specified solvable\&. .RS 4 .\} .nf +\fBvoid set_sourcepkg(Id\fR \fIsolvid\fR\fB, const char *\fR\fIsourcepkg\fR\fB)\fR; +\fI$data\fR\fB\&.set_sourcepkg(\fR\fI$solvid\fR\fB,\fR \fI$sourcepkg\fR\fB)\fR; +\fIdata\fR\fB\&.set_sourcepkg(\fR\fIsolvid\fR\fB,\fR \fIsourcepkg\fR\fB)\fR +\fIdata\fR\fB\&.set_sourcepkg(\fR\fIsolvid\fR\fB,\fR \fIsourcepkg\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_location(Id\fR \fIsolvid\fR\fB, unsigned int\fR \fImediano\fR\fB, const char *\fR\fIlocation\fR\fB)\fR; +\fI$data\fR\fB\&.set_location(\fR\fI$solvid\fR\fB,\fR \fI$mediano\fR\fB,\fR \fI$location\fR\fB)\fR; +\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR +\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid add_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR; \fI$data\fR\fB\->add_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR; \fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR @@ -5542,6 +5946,19 @@ my \fI$handle\fR \fB=\fR \fI$data\fR\fB\->new_handle()\fR; .RE .\} .sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid unset(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR; +\fI$data\fR\fB\->unset(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp Data storage methods\&. Probably only useful to store data in the special SOLVID_META solvid that stores repodata meta information\&. Note that repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag), so be careful if you need to store ids\&. Arrays are created by calling the add function for every element\&. A flexarray is an array of sub\-structures, call new_handle to create a new structure, use the handle as solvid to fill the structure with data and call add_flexarray to put the structure in an array\&. .SH "THE DATAPOS CLASS" .sp @@ -5584,9 +6001,9 @@ Create a Dataiterator at the position of the datapos object\&. .\} .nf \fBconst char *lookup_deltalocation(unsigned int *\fR\fIOUTPUT\fR\fB)\fR; -my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR; -\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR -\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR +my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR; +\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR +\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR .fi .if n \{\ .RE diff --git a/libsolv-0.6.15/doc/libsolv-constantids.3 b/libsolv-0.7.2/doc/gen/libsolv-constantids.3 similarity index 99% rename from libsolv-0.6.15/doc/libsolv-constantids.3 rename to libsolv-0.7.2/doc/gen/libsolv-constantids.3 index 327150c..228dfdd 100644 --- a/libsolv-0.6.15/doc/libsolv-constantids.3 +++ b/libsolv-0.7.2/doc/gen/libsolv-constantids.3 @@ -1,13 +1,13 @@ '\" t .\" Title: Libsolv-Constantids .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 12/14/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV\-CONSTANTIDS" "3" "12/14/2015" "libsolv" "LIBSOLV" +.TH "LIBSOLV\-CONSTANTIDS" "3" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/libsolv-history.3 b/libsolv-0.7.2/doc/gen/libsolv-history.3 similarity index 97% rename from libsolv-0.6.15/doc/libsolv-history.3 rename to libsolv-0.7.2/doc/gen/libsolv-history.3 index 872cd4e..fc2d69b 100644 --- a/libsolv-0.6.15/doc/libsolv-history.3 +++ b/libsolv-0.7.2/doc/gen/libsolv-history.3 @@ -1,13 +1,13 @@ '\" t .\" Title: Libsolv-History .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV\-HISTORY" "3" "08/26/2015" "libsolv" "LIBSOLV" +.TH "LIBSOLV\-HISTORY" "3" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/libsolv-pool.3 b/libsolv-0.7.2/doc/gen/libsolv-pool.3 similarity index 92% rename from libsolv-0.6.15/doc/libsolv-pool.3 rename to libsolv-0.7.2/doc/gen/libsolv-pool.3 index 0929ba6..51dc1a4 100644 --- a/libsolv-0.6.15/doc/libsolv-pool.3 +++ b/libsolv-0.7.2/doc/gen/libsolv-pool.3 @@ -1,13 +1,13 @@ '\" t .\" Title: Libsolv-Pool .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 12/14/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 10/22/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV\-POOL" "3" "12/14/2015" "libsolv" "LIBSOLV" +.TH "LIBSOLV\-POOL" "3" "10/22/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -369,7 +369,7 @@ Make the addfileprovides method only add files from the standard locations (i\&. .RE .\} .sp -Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&. +Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&. Note that any pool_setarch and pool_setarchpolicy calls need to come after the pool_setdisttype call, as they make use of the noarch/any/all architecture id\&. .sp .if n \{\ .RS 4 @@ -608,10 +608,35 @@ An internal file conflict dependency used to represent file conflicts\&. See the A conditional dependency, the \(lqname\(rq sub\-dependency is only considered if the \(lqevr\(rq sub\-dependency is fulfilled\&. See the section about boolean dependencies about more information\&. .RE .PP +\fBREL_UNLESS\fR +.RS 4 +A conditional dependency, the \(lqname\(rq sub\-dependency is only considered if the \(lqevr\(rq sub\-dependency is not fulfilled\&. See the section about boolean dependencies about more information\&. +.RE +.PP \fBREL_COMPAT\fR .RS 4 A compat dependency used in Haiku to represent version ranges\&. The \(lqname\(rq part is the actual version, the \(lqevr\(rq part is the backwards compatibility version\&. .RE +.PP +\fBREL_KIND\fR +.RS 4 +A pseudo dependency that limits the solvables to a specific kind\&. The kind is expected to be a prefix of the solvable name, e\&.g\&. \(lqpatch:foo\(rq would be of kind \(lqpatch\(rq\&. \(lqREL_KIND\(rq is only supported in the selection functions\&. +.RE +.PP +\fBREL_MULTIARCH\fR +.RS 4 +A debian multiarch annotation\&. The most common value for the \(lqevr\(rq part is \(lqany\(rq\&. +.RE +.PP +\fBREL_ELSE\fR +.RS 4 +The else part of a \(lqREL_COND\(rq or \(lqREL_UNLESS\(rq dependency\&. See the section about boolean dependencies\&. +.RE +.PP +\fBREL_ERROR\fR +.RS 4 +An illegal dependency\&. This is useful to encode dependency parse errors\&. +.RE .SS "Functions" .sp .if n \{\ @@ -739,6 +764,18 @@ Convert a solvable Id into a pointer to the solvable data\&. Note that the point .RS 4 .\} .nf +\fBId pool_solvable2id(const Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert a pointer to the solvable data into a solvable Id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBconst char *pool_solvid2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR; .fi .if n \{\ @@ -931,6 +968,18 @@ Same as pool_addfileprovides, but the added Ids are returned in two Queues, \fIi .RS 4 .\} .nf +\fBvoid pool_set_whatprovides(\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, Id\fR \fIoffset\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Manually set an entry in the whatprovides index\&. You\(cqll never do this for package dependencies, as those entries are created by calling the pool_createwhatprovides() function\&. But this function is useful for namespace provides if you do not want to use a namespace callback to lazily set the provides\&. The offset argument is a offset in the whatprovides array, thus you can use \(lq1\(rq as a false value and \(lq2\(rq as true value\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf \fBvoid pool_flush_namespaceproviders(Pool *\fR\fIpool\fR\fB, Id\fR \fIns\fR\fB, Id\fR \fIevr\fR\fB)\fR; .fi .if n \{\ @@ -1241,7 +1290,7 @@ There can be multiple equivalence classes, the set of allowed vendor changes for You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_VENDORCHANGE flag\&. .SH "BOOLEAN DEPENDENCIES" .sp -Boolean Dependencies allow to build complex expressions from simple dependencies\&. While rpm does not support boolean expressions in dependencies and debian only allows an "OR" expression, libsolv allows arbitrary complex expressions\&. The following basic types are supported: +Boolean Dependencies allow to build complex expressions from simple dependencies\&. Note that depending on the package manager only a subset of those may be useful\&. For example, debian currently only allows an "OR" expression\&. .PP \fBREL_OR\fR .RS 4 @@ -1250,17 +1299,27 @@ The expression is true if either the first dependency or the second one is true\ .PP \fBREL_AND\fR .RS 4 -The expression is true if both dependencies are true\&. The packages fulfilling the dependencies may be different, i\&.e\&. \(lqSupplements: perl AND python\(rq is true if both a package providing perl and a package providing python are installed\&. The solver currently only supports REL_AND in Supplements/Enhances dependencies, in other types of dependencies it gets treated as REL_WITH\&. +The expression is true if both dependencies are true\&. The packages fulfilling the dependencies may be different, i\&.e\&. \(lqSupplements: perl REL_AND python\(rq is true if both a package providing perl and a package providing python are installed\&. .RE .PP \fBREL_WITH\fR .RS 4 -The expression is true if both dependencies are true and are fulfilled by the same package\&. Thus \(lqSupplements: perl AND python\(rq would only be true if a package is installed that provides both dependencies (some kind of multi\-language interpreter)\&. +The expression is true if both dependencies are true and are fulfilled by the same package\&. Thus \(lqSupplements: perl REL_WITH python\(rq would only be true if a package is installed that provides both dependencies (some kind of multi\-language interpreter)\&. .RE .PP \fBREL_COND\fR .RS 4 -The expression is true if the first dependency is true or the second dependency is false\&. Libsolv currently does not support this type of dependency in the solver code\&. +The expression is true if the first dependency is true or the second dependency is false\&. \(lqA REL_COND B\(rq is equivalent to \(lqA REL_OR (NOT B)\(rq (except that libsolv does not expose \(lqNOT\(rq)\&. +.RE +.PP +\fBREL_UNLESS\fR +.RS 4 +The expression is true if the first dependency is true and the second dependency is false\&. \(lqA REL_UNLESS B\(rq is equivalent to \(lqA REL_AND (NOT B)\(rq (except that libsolv does not expose \(lqNOT\(rq)\&. +.RE +.PP +\fBREL_ELSE\fR +.RS 4 +The \(lqelse\(rq part of a \(lqREL_COND\(rq or \(lqREL_UNLESS\(rq dependency\&. It has to be directly in the evr part of the condition, e\&.g\&. \(lqfoo REL_COND (bar REL_ELSE baz)\(rq\&. For \(lqREL_COND\(rq this is equivalent to writing \(lq(foo REL_COND bar) REL_AND (bar REL_OR baz)\(rq\&. For \(lqREL_UNLESS\(rq this is equivalent to writing \(lq(foo REL_UNLESS bar) REL_OR (bar REL_AND baz)\(rq\&. .RE .sp Each sub\-dependency of a boolean dependency can in turn be a boolean dependency, so you can chain them to create complex dependencies\&. diff --git a/libsolv-0.6.15/doc/libsolv.3 b/libsolv-0.7.2/doc/gen/libsolv.3 similarity index 95% rename from libsolv-0.6.15/doc/libsolv.3 rename to libsolv-0.7.2/doc/gen/libsolv.3 index 24ab788..a6ac359 100644 --- a/libsolv-0.6.15/doc/libsolv.3 +++ b/libsolv-0.7.2/doc/gen/libsolv.3 @@ -1,13 +1,13 @@ '\" t .\" Title: Libsolv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "LIBSOLV" "3" "08/26/2015" "libsolv" "LIBSOLV" +.TH "LIBSOLV" "3" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/mdk2solv.1 b/libsolv-0.7.2/doc/gen/mdk2solv.1 similarity index 91% rename from libsolv-0.6.15/doc/mdk2solv.1 rename to libsolv-0.7.2/doc/gen/mdk2solv.1 index 4400c9b..ac593f1 100644 --- a/libsolv-0.6.15/doc/mdk2solv.1 +++ b/libsolv-0.7.2/doc/gen/mdk2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: mdk2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "MDK2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "MDK2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/mergesolv.1 b/libsolv-0.7.2/doc/gen/mergesolv.1 similarity index 90% rename from libsolv-0.6.15/doc/mergesolv.1 rename to libsolv-0.7.2/doc/gen/mergesolv.1 index 3ff00e8..65fd756 100644 --- a/libsolv-0.6.15/doc/mergesolv.1 +++ b/libsolv-0.7.2/doc/gen/mergesolv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: mergesolv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "MERGESOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "MERGESOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.7.2/doc/gen/repo2solv.1 b/libsolv-0.7.2/doc/gen/repo2solv.1 new file mode 100644 index 0000000..0a8c3cf --- /dev/null +++ b/libsolv-0.7.2/doc/gen/repo2solv.1 @@ -0,0 +1,79 @@ +'\" t +.\" Title: repo2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 10/22/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "REPO2SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +repo2solv \- convert repository metadata into a solv file +.SH "SYNOPSIS" +.sp +\fBrepo2solv\fR [\fIOPTIONS\fR] \fIDIR\fR +.SH "DESCRIPTION" +.sp +The repo2solv tool converts repository metadata in the directory \fIDIR\fR into a solv file written to standard output\&. +.sp +Note that repo2solv does not verify signatures or checksum, it is expected that this is done by the tool that downloads the metadata\&. +.sp +If no metadata is detected, repo2solv assumes the "plaindir" format and generates the solv file from all rpm files it finds\&. +.PP +\fB\-o\fR \fIOUTFILE\fR +.RS 4 +Write the solv file to +\fIOUTFILE\fR +instead of stdout\&. +.RE +.PP +\fB\-R\fR +.RS 4 +Also recurse into subdirectories in "plaindir" mode\&. +.RE +.PP +\fB\-F\fR +.RS 4 +Put the complete filelist in the output\&. The default is to just include the "importent" parts of the file list, except for "plaindir" mode, which always includes all files\&. +.RE +.PP +\fB\-C\fR +.RS 4 +Add changelog entires to the output\&. +.RE +.PP +\fB\-A\fR +.RS 4 +Add appdata pseudo packages to the output\&. This is an experimental feature\&. +.RE +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "SEE ALSO" +.sp +dumpsolv(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/libsolv-0.6.15/doc/repomdxml2solv.1 b/libsolv-0.7.2/doc/gen/repomdxml2solv.1 similarity index 92% rename from libsolv-0.6.15/doc/repomdxml2solv.1 rename to libsolv-0.7.2/doc/gen/repomdxml2solv.1 index e14b974..5d459cc 100644 --- a/libsolv-0.6.15/doc/repomdxml2solv.1 +++ b/libsolv-0.7.2/doc/gen/repomdxml2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: repomdxml2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "REPOMDXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "REPOMDXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/rpmdb2solv.1 b/libsolv-0.7.2/doc/gen/rpmdb2solv.1 similarity index 94% rename from libsolv-0.6.15/doc/rpmdb2solv.1 rename to libsolv-0.7.2/doc/gen/rpmdb2solv.1 index 2b4b931..6f84a7f 100644 --- a/libsolv-0.6.15/doc/rpmdb2solv.1 +++ b/libsolv-0.7.2/doc/gen/rpmdb2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: rpmdb2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "RPMDB2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "RPMDB2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/rpmmd2solv.1 b/libsolv-0.7.2/doc/gen/rpmmd2solv.1 similarity index 91% rename from libsolv-0.6.15/doc/rpmmd2solv.1 rename to libsolv-0.7.2/doc/gen/rpmmd2solv.1 index 2d8e245..5149a1c 100644 --- a/libsolv-0.6.15/doc/rpmmd2solv.1 +++ b/libsolv-0.7.2/doc/gen/rpmmd2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: rpmmd2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "RPMMD2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "RPMMD2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/rpms2solv.1 b/libsolv-0.7.2/doc/gen/rpms2solv.1 similarity index 93% rename from libsolv-0.6.15/doc/rpms2solv.1 rename to libsolv-0.7.2/doc/gen/rpms2solv.1 index e67c6ef..75a89f3 100644 --- a/libsolv-0.6.15/doc/rpms2solv.1 +++ b/libsolv-0.7.2/doc/gen/rpms2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: rpms2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "RPMS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "RPMS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.7.2/doc/gen/solv.1 b/libsolv-0.7.2/doc/gen/solv.1 new file mode 100644 index 0000000..aae1c6d --- /dev/null +++ b/libsolv-0.7.2/doc/gen/solv.1 @@ -0,0 +1,102 @@ +'\" t +.\" Title: solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 10/22/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +solv \- example package manager based on libsolv +.SH "SYNOPSIS" +.sp +\fBsolv\fR install [OPTIONS] PKG\&... +.sp +\fBsolv\fR erase [OPTIONS] PKG\&... +.sp +\fBsolv\fR list [OPTIONS] PKG\&... +.sp +\fBsolv\fR info [OPTIONS] PKG\&... +.sp +\fBsolv\fR search [OPTIONS] STRING\&... +.sp +\fBsolv\fR verify [OPTIONS] PKG\&... +.sp +\fBsolv\fR update [OPTIONS] PKG\&... +.sp +\fBsolv\fR dist\-upgrade [OPTIONS] PKG\&... +.sp +\fBsolv\fR repolist [OPTIONS] +.SH "DESCRIPTION" +.sp +The solv tool demos some features of the libsolv library\&. It is not meant to replace a real package manager, for example it does not cache downloaded packages\&. +.PP +\fB\-\-root\fR \fIROOTDIR\fR +.RS 4 +Install packages using +\fIROOTDIR\fR +as root of the filesystem\&. This also means that the package database of +\fIROOTDIR\fR +will be used\&. +.RE +.PP +\fB\-\-clean\fR +.RS 4 +Also get rid of no longer needed packages when erasing, like libraries that have been used by the erased packages\&. +.RE +.PP +\fB\-\-best\fR +.RS 4 +Force usage of the best package (normally the one with the highest version) for install and update operations\&. +.RE +.PP +\fB\-\-testcase\fR +.RS 4 +Write a testcase after dependency solving\&. +.RE +.sp +The following options can be used to filter the packages\&. If the same option is used multiple times, the result is ORed together\&. +.PP +\fB\-i\fR +.RS 4 +Limit the packages to installed ones\&. +.RE +.PP +\fB\-r\fR \fIREPO\fR +.RS 4 +Limit the packages to the specified repository\&. +.RE +.PP +\fB\-\-arch\fR \fIARCHITECTURE\fR +.RS 4 +Limit the packages to the specified package architecture\&. +.RE +.PP +\fB\-\-type\fR \fITYPE\fR +.RS 4 +Limit the packages to the specified package type\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/libsolv-0.6.15/doc/susetags2solv.1 b/libsolv-0.7.2/doc/gen/susetags2solv.1 similarity index 92% rename from libsolv-0.6.15/doc/susetags2solv.1 rename to libsolv-0.7.2/doc/gen/susetags2solv.1 index 9b07094..8dd83d4 100644 --- a/libsolv-0.6.15/doc/susetags2solv.1 +++ b/libsolv-0.7.2/doc/gen/susetags2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: susetags2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "SUSETAGS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "SUSETAGS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/testsolv.1 b/libsolv-0.7.2/doc/gen/testsolv.1 similarity index 93% rename from libsolv-0.6.15/doc/testsolv.1 rename to libsolv-0.7.2/doc/gen/testsolv.1 index 0e71874..50254f7 100644 --- a/libsolv-0.6.15/doc/testsolv.1 +++ b/libsolv-0.7.2/doc/gen/testsolv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: testsolv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "TESTSOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "TESTSOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/updateinfoxml2solv.1 b/libsolv-0.7.2/doc/gen/updateinfoxml2solv.1 similarity index 90% rename from libsolv-0.6.15/doc/updateinfoxml2solv.1 rename to libsolv-0.7.2/doc/gen/updateinfoxml2solv.1 index 20ab3ad..aa60372 100644 --- a/libsolv-0.6.15/doc/updateinfoxml2solv.1 +++ b/libsolv-0.7.2/doc/gen/updateinfoxml2solv.1 @@ -1,13 +1,13 @@ '\" t .\" Title: updateinfoxml2solv .\" Author: [see the "Author" section] -.\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 08/26/2015 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 .\" Manual: LIBSOLV .\" Source: libsolv .\" Language: English .\" -.TH "UPDATEINFOXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV" +.TH "UPDATEINFOXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/libsolv-0.6.15/doc/helix2solv.txt b/libsolv-0.7.2/doc/helix2solv.txt similarity index 93% rename from libsolv-0.6.15/doc/helix2solv.txt rename to libsolv-0.7.2/doc/helix2solv.txt index f9b303f..40d523a 100644 --- a/libsolv-0.6.15/doc/helix2solv.txt +++ b/libsolv-0.7.2/doc/helix2solv.txt @@ -22,3 +22,7 @@ input and writes it in solv file format to standard output. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/installcheck.txt b/libsolv-0.7.2/doc/installcheck.txt similarity index 96% rename from libsolv-0.6.15/doc/installcheck.txt rename to libsolv-0.7.2/doc/installcheck.txt index 99eb279..5780772 100644 --- a/libsolv-0.6.15/doc/installcheck.txt +++ b/libsolv-0.7.2/doc/installcheck.txt @@ -27,3 +27,7 @@ file. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/libsolv-bindings.txt b/libsolv-0.7.2/doc/libsolv-bindings.txt similarity index 90% rename from libsolv-0.6.15/doc/libsolv-bindings.txt rename to libsolv-0.7.2/doc/libsolv-bindings.txt index 1ee699d..e458246 100644 --- a/libsolv-0.6.15/doc/libsolv-bindings.txt +++ b/libsolv-0.7.2/doc/libsolv-bindings.txt @@ -45,7 +45,7 @@ tied arrays so that it is possible to iterate with a for() statement: As a downside of this approach, iterator objects cannot have attributes. If an array needs to be passed to a method it is usually done by reference, -if a method returns an array it returns it on the stack: +if a method returns an array it returns it on the perl stack: my @problems = $solver->solve(\@jobs); @@ -93,7 +93,7 @@ __repr__ method to ease debugging. print dep print repr(repo) -Constants are attributes of the classes: +Constants are attributes of the corresponding classes: pool.set_flag(solv.Pool.POOL_FLAG_OBSOLETEUSESCOLORS, 1); @@ -167,7 +167,7 @@ a foreach style: libsolv's arrays are mapped to tcl's lists: - TCL set jobs [list $job1 $job2] + TCL set jobs [list $job1 $job2] TCL set problems [$solver solve $jobs] TCL puts "We have [llength $problems] problems..." @@ -183,7 +183,7 @@ Some objects also support a ``=='' method for equality tests, and a Swig implements all constants as numeric variables, constants belonging to a libsolv class are prefixed with the class name: - TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1 + TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1 TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY] @@ -218,10 +218,10 @@ like an extra Solvable that has the Id SOLVID_META. *SOLVID_POS*:: Use the data position stored inside of the pool instead of accessing some solvable by Id. The bindings have the Datapos objects as an -abstraction mechanism, so you do not need this constant. +abstraction mechanism, so you most likely do not need this constant. Constant string Ids - + *ID_NULL*:: Always zero @@ -300,7 +300,7 @@ in old rpm versions, modern systems should never need this. *POOL_FLAG_FORBIDSELFCONFLICTS*:: Disallow the installation of packages that conflict with themselves. Debian always allows self-conflicting packages, rpm used to forbid -them but switched to also allowing them recently. +them but switched to also allowing them since rpm-4.9.0. *POOL_FLAG_OBSOLETEUSESPROVIDES*:: Make obsolete type dependency match against provides instead of @@ -315,10 +315,10 @@ with the same name, rpm-5 switched to also removing packages providing the same name. *POOL_FLAG_OBSOLETEUSESCOLORS*:: -Rpm's multilib implementation (used in RedHat and Fedora) -distinguishes between 32bit and 64bit packages (the terminology -is that they have a different color). If obsoleteusescolors is -set, packages with different colors will not obsolete each other. +Rpm's multilib implementation distinguishes between 32bit and 64bit +packages (the terminology is that they have a different color). +If obsoleteusescolors is set, packages with different colors will +not obsolete each other. *POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*:: Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if @@ -328,9 +328,9 @@ false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled). *POOL_FLAG_NOINSTALLEDOBSOLETES*:: -New versions of rpm consider the obsoletes of installed packages -when checking for dependency, thus you may not install a package -that is obsoleted by some other installed package, unless you +Since version 4.9.0 rpm considers the obsoletes of installed packages +when checking for dependency conflicts, thus you may not install a +package that is obsoleted by some other installed package unless you also erase the other package. *POOL_FLAG_HAVEDISTEPOCH*:: @@ -339,7 +339,7 @@ version comparison if the epoch/version/release of two packages are the same. *POOL_FLAG_NOOBSOLETESMULTIVERSION*:: -If a package is installed in multiversionmode, rpm used to ignore +If a package is installed in multiversion mode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but @@ -393,7 +393,7 @@ value, the more output is generated. Set/get a pool specific flag. The flags define how the system works, e.g. how the package manager treats obsoletes. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if -you want to solv package dependencies for some other system than yours. +you want to solve package dependencies for some other system. void set_rootdir(const char *rootdir) $pool->set_rootdir(rootdir); @@ -475,7 +475,8 @@ repository is loaded and addfileprovides is called. pool.createwhatprovides() Create the internal ``whatprovides'' hash over all of the provides of all -packages. This method must be called before doing any lookups on provides. +installable packages. This method must be called before doing any lookups on +provides. It's encouraged to do it right after all repos are set up, usually right after the call to addfileprovides(). @@ -504,6 +505,21 @@ string. See the Dataiterator class for the allowed flags. create solver jobs working on a specific set of packages. See the Solver class for more information. + void set_namespaceproviders(DepId ns, DepId evr, bool value = 1) + $pool->set_namespaceproviders($ns, $evr, 1); + pool.set_namespaceproviders(ns, evr, True) + pool.set_namespaceproviders(ns, evr, true) + +Manually set a namespace provides entry in the whatprovides index. + + void flush_namespaceproviders(DepId ns, DepId evr) + $pool->flush_namespaceproviders($ns, $evr); + $pool.flush_namespaceproviders(ns, evr) + $pool.flush_namespaceproviders(ns, evr) + +Flush the cache of all namespaceprovides matching the specified namespace +dependency. You can use zero as a wildcard argument. + bool isknownarch(DepId id) my $bool = $pool->isknownarch($id); bool = pool.isknownarch(id) @@ -523,8 +539,8 @@ Create a new solver object. job = pool.Job(how, what) job = pool.Job(how, what) -Create a new Job object. Kind of low level, in most cases you would use a -Selection or Dep job constructor instead. +Create a new Job object. Kind of low level, in most cases you would +instead use a Selection or Dep job constructor. Selection Selection() my $sel = $pool->Selection(); @@ -551,6 +567,24 @@ Create a selection by matching packages against the specified string. See the Selection class for a list of flags and how to create solver jobs from a selection. + Selection matchdeps(const char *name, int flags, Id keyname, Id marker = -1) + my $sel = $pool->matchdeps($name, $flags, $keyname); + sel = pool.matchdeps(name, flags, keyname) + sel = pool.matchdeps(name, flags, keyname) + +Create a selection by matching package dependencies against the specified string. +This can be used if you want to match other dependency types than ``provides''. + + Selection matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) + my $sel = $pool->matchdepid(dep, $flags, $keyname); + sel = pool.matchdepid(dep, flags, keyname) + sel = pool.matchdepid(dep, flags, keyname) + +Create a selection by matching package dependencies against the specified +dependency. This may be faster than matchdeps and also works with complex +dependencies. The downside is that you cannot use globs or case insensitive +matching. + void setpooljobs(Jobs *jobs) $pool->setpooljobs(\@jobs); pool.setpooljobs(jobs) @@ -563,8 +597,8 @@ selection. Get/Set fixed jobs stored in the pool. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages -can be multiversion installed, which packages were userinstalled or must not be -erased. +can be multiversion installed, which packages were userinstalled, or which +packages must not be erased. void set_loadcallback(Callable *callback) $pool->setloadcallback(\&callbackfunction); @@ -700,7 +734,7 @@ pool and _create_ is false, zero is returned. id = pool.rel2id(nameid, evrid, flags) Create a ``relational'' dependency. Such dependencies consist of a name part, -the _flags_ describing the relation, and a version part. The flags are: +_flags_ describing the relation, and a version part. The flags are: $solv::REL_EQ | $solv::REL_GT | $solv::REL_LT solv.REL_EQ | solv.REL_GT | solv.REL_LT @@ -757,8 +791,9 @@ The id of this dependency. reldep = dep.Rel(flags, evrdep) reldep = dep.Rel(flags, evrdep) -Create a relational dependency from to string dependencies and a flags -argument. See the pool's rel2id method for a description of the flags. +Create a relational dependency from the caller dependency, the flags, +and a dependency describing the ``version'' part. +See the pool's rel2id method for a description of the flags. Selection Selection_name(int setflags = 0) my $sel = $dep->Selection_name(); @@ -796,7 +831,7 @@ Same as calling the str() method. if dep1 == dep2: if dep1 == dep2 -The dependencies are equal if they are part of the same pool and have the same +Two dependencies are equal if they are part of the same pool and have the same ids. @@ -875,7 +910,7 @@ timestamp. *REPO_REUSE_REPODATA*:: Reuse the last repository data area (``repodata'') instead of creating a -new one. +new area. *REPO_NO_INTERNALIZE*:: Do not internalize the added repository data. This is useful if @@ -1173,9 +1208,9 @@ Add the contents of the mageia/mandriva repository metadata (the "synthesis.hdlist" file) to the repository. bool add_mdk_info(FILE *fp, int flags = 0) - $repo->add_mdk($fp); - repo.add_mdk(fp) - repo.add_mdk(fp) + $repo->add_mdk_info($fp); + repo.add_mdk_info(fp) + repo.add_mdk_info(fp) Extend the packages from the synthesis file with the info.xml and files.xml data. Do not forget to specify *REPO_EXTEND_SOLVABLES*. @@ -1309,10 +1344,10 @@ a specific id and want to avoid the string compare overhead. Id lookup_id(Id keyname) my $id = $solvable->lookup_id($keyname); - id = solvable.lookup_id(solvid) - id = solvable.lookup_id(solvid) + id = solvable.lookup_id(keyname) + id = solvable.lookup_id(keyname) - unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) + unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) my $num = $solvable->lookup_num($keyname); num = solvable.lookup_num(keyname) num = solvable.lookup_num(keyname) @@ -1349,14 +1384,21 @@ array, use 1 to select the second part or 0 to retrieve all ids including the marker. const char *lookup_location(unsigned int *OUTPUT); - my ($location, $medianr) = $solvable->lookup_location(); - location, medianr = solvable.lookup_location() - location, medianr = solvable.lookup_location() + my ($location, $mediano) = $solvable->lookup_location(); + location, mediano = solvable.lookup_location() + location, mediano = solvable.lookup_location() Return a tuple containing the on-media location and an optional media number for multi-part repositories (e.g. repositories spawning multiple DVDs). + const char *lookup_sourcepkg(); + my $sourcepkg = $solvable->lookup_sourcepkg(); + sourcepkg = solvable.lookup_sourcepkg() + sourcepkg = solvable.lookup_sourcepkg() + +Return a sourcepkg name associated with solvable. + Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0) my $di = $solvable->Dataiterator($keyname, $match, $flags); di = solvable.Dataiterator(keyname, match, flags) @@ -1400,20 +1442,27 @@ Return true if the solvable is installed on the system. bool identical(Solvable *other) $solvable->identical($other) - $solvable.identical(other) - $solvable.identical?(other) + solvable.identical(other) + solvable.identical?(other) Return true if the two solvables are identical. int evrcmp(Solvable *other) - $solvable->evrcmp(other) - $solvable.evrcmp(other) - $solvable.evrcmp(other) + $solvable->evrcmp($other) + solvable.evrcmp(other) + solvable.evrcmp(other) Returns -1 if the epoch/version/release of the solvable is less than the one from the other solvable, 1 if it is greater, and 0 if they are equal. Note that "equal" does not mean that the evr is identical. + int matchesdep(Id keyname, DepId id, Id marker = -1) + $solvable->matchesdep($keyname, $dep) + solvable.matchesdep(keyname, dep) + solvable.matchesdep?(keyname, dep) + +Return true if the dependencies stored in keyname match the specified dependency. + Selection Selection(int setflags = 0) my $sel = $solvable->Selection(); sel = solvable.Selection() @@ -1496,7 +1545,7 @@ Allow the matching of checksum entries. Do a sub-search in the array stored in keyname. void skip_solvable(); - $di->kip_solvable(); + $di->skip_solvable(); di.skip_solvable() di.skip_solvable() @@ -1668,22 +1717,12 @@ of the package. This is normally a combination of the name, the version, and the architecture of a package. *SELECTION_DOTARCH*:: -Allow an ``.'' suffix when matching names or +Allow an "." suffix when matching names or provides. *SELECTION_REL*:: Allow the specification of a relation when matching names -or provides, e.g. "name >= 1.2". - -*SELECTION_INSTALLED_ONLY*:: -Limit the package search to installed packages. - -*SELECTION_SOURCE_ONLY*:: -Limit the package search to source packages only. - -*SELECTION_WITH_SOURCE*:: -Extend the package search to also match source packages. The default is -only to match binary packages. +or dependencies, e.g. "name >= 1.2". *SELECTION_GLOB*:: Allow glob matching for package names, package provides, and file names. @@ -1698,6 +1737,42 @@ Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package. +*SELECTION_SKIP_KIND*:: +Remove a "packagekind:" prefix from the package names. + +*SELECTION_MATCH_DEPSTR*:: +When matching dependencies, do a string match on the result of dep2str +instead of using the normal dependency intersect algorithm. + +*SELECTION_INSTALLED_ONLY*:: +Limit the package search to installed packages. + +*SELECTION_SOURCE_ONLY*:: +Limit the package search to source packages only. + +*SELECTION_WITH_SOURCE*:: +Extend the package search to also match source packages. The default is +only to match binary packages. + +*SELECTION_WITH_DISABLED*:: +Extend the package search to also include disabled packages. + +*SELECTION_WITH_BADARCH*:: +Extend the package search to also include packages that are not installable +on the configured architecture. + +*SELECTION_WITH_ALL*:: +Shortcut for selecting the three modifiers above. + +*SELECTION_ADD*:: +Add the result of the match to the current selection instead of replacing it. + +*SELECTION_SUBTRACT*:: +Remove the result of the match to the current selection instead of replacing it. + +*SELECTION_FILTER*:: +Intersect the result of the match to the current selection instead of replacing it. + === ATTRIBUTES === Pool *pool; /* read only */ @@ -1707,14 +1782,12 @@ globbed package. Back pointer to pool. -=== METHODS === - - int flags(); - my $flags = $sel->flags(); - flags = sel.flags() - flags = sel.flags() + int flags; /* read only */ + $sel->{flags} + flags = sel.flags + flags = sel.flags -Return the result flags of the selection. The flags are a subset +The result flags of the selection. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result. For example, if you create the selection with ``SELECTION_NAME | SELECTION_PROVIDES'', the resulting @@ -1722,13 +1795,22 @@ flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not. If there was no match at all, the flags will be zero. - bool isempty(); +=== METHODS === + + bool isempty() $sel->isempty() sel.isempty() sel.isempty? Return true if the selection is empty, i.e. no package could be matched. + Selection clone(int flags = 0) + my $cloned = $sel->clone(); + cloned = sel.clone() + cloned = sel.clone() + +Return a copy of a selection. + void filter(Selection *other) $sel->filter($other); sel.filter(other) @@ -1747,13 +1829,22 @@ be added to the set of packages of the selection object. Does an in-place modification. Note that the selection flags are no longer meaningful after the add operation. + void subtract(Selection *other) + $sel->subtract($other); + sel.subtract(other) + sel.subtract(other) + +Remove the packages of the other selection from the packages of the selection +object. Does an in-place modification. + void add_raw(Id how, Id what) $sel->add_raw($how, $what); sel.add_raw(how, what) sel.add_raw(how, what) Add a raw element to the selection. Check the Job class for information about -the how and what parameters. +the how and what parameters. Note that the selection flags are no longer meaningful +after the add_raw operation. Job *jobs(int action) my @jobs = $sel->jobs($action); @@ -1771,6 +1862,30 @@ erase). See the Job class for the action and action modifier constants. Convert a selection into an array of Solvable objects. + void select(const char *name, int flags) + $sel->select($name, $flags); + sel.select(name, flags) + sel.select(name, flags) + +Do a select operation and combine the result with the current selection. You +can choose the desired combination method by using either the SELECTION_ADD, +SELECTION_SUBTRACT, or SELECTION_FILTER flag. If none of the flags are +used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed. + + void matchdeps(const char *name, int flags, Id keyname, Id marker = -1) + $sel->matchdeps($name, $flags, $keyname); + sel.matchdeps(name, flags, keyname) + sel.matchdeps(name, flags, keyname) + +Do a matchdeps operation and combine the result with the current selection. + + void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) + $sel->matchdepid($dep, $flags, $keyname); + sel.matchdepid(dep, flags, keyname) + sel.matchdepid(dep, flags, keyname) + +Do a matchdepid operation and combine the result with the current selection. + my $str = $sel->str; str = str(sel) @@ -1878,6 +1993,16 @@ Allow the solver to deinstall the matching installed packages if they get into the way of resolving a dependency. This is like the SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages. +*SOLVER_FAVOR*:: +Prefer the specified packages if the solver encounters an alternative. If +a job contains multiple matching favor/disfavor elements, the last one takes +precedence. + +*SOLVER_DISFAVOR*:: +Avoid the specified packages if the solver encounters an alternative. This +can also be used to block recommended or supplemented packages from being +installed. + *SOLVER_JOBMASK*:: A mask containing all the above action bits. @@ -2069,7 +2194,7 @@ Allow the solver to downgrade packages without asking for confirmation Allow the solver to change the architecture of an installed package without asking for confirmation. Note that changes to/from noarch are always considered to be allowed. - + *SOLVER_FLAG_ALLOW_VENDORCHANGE*:: Allow the solver to change the vendor of an installed package without asking for confirmation. Each vendor is part of one or more @@ -2110,6 +2235,11 @@ packages that also obsolete the package but are not considered for updating. If you cannot use this feature, you can turn it off by setting this flag. +*SOLVER_FLAG_NEED_UPDATEPROVIDE*:: +This is somewhat the opposite of SOLVER_FLAG_NO_UPDATEPROVIDE: Only +packages that provide the installed package names are considered +for updating. + *SOLVER_FLAG_SPLITPROVIDES*:: Make the solver aware of special provides of the form ``:'' used in SUSE systems to support package @@ -2123,7 +2253,7 @@ Install recommended or supplemented packages even if they have no connection to the current transaction. You can use this feature to implement a simple way for the user to install new recommended packages that were not available in the past. - + *SOLVER_FLAG_NO_INFARCHCHECK*:: Turn off the inferior architecture checking that is normally done by the solver. Normally, the solver allows only the installation @@ -2152,11 +2282,31 @@ of resolving non-orphaned ones. Setting the flag might result in no longer working packages in case they are orphaned. *SOLVER_FLAG_FOCUS_INSTALLED*:: -Resolve installed packages before resolving the given job. +Resolve installed packages before resolving the given jobs. Setting this flag means that the solver will prefer picking a package version that fits the other installed packages over updating installed packages. +*SOLVER_FLAG_FOCUS_BEST*:: +First resolve the given jobs, then the dependencies of the +resulting packages, then resolve all already installed +packages. This will result in more packages being updated +as when the flag is not used. + +*SOLVER_FLAG_INSTALL_ALSO_UPDATES*:: +Update the package if a job is already fulfilled by an installed +package. + +*SOLVER_FLAG_YUM_OBSOLETES*:: +Turn on yum-like package split handling. See the yum documentation +for more details. + +*SOLVER_FLAG_URPM_REORDER*:: +Turn on urpm like package reordering for kernel packages. See +the urpm documentation for more details. + + + Basic rule types: *SOLVER_RULE_UNKNOWN*:: @@ -2415,6 +2565,23 @@ interfaces that show both the job result and the problems. Return the reason why a specific solvable was installed or erased. For most of the reasons the rule that triggered the decision is also returned. + Solvable *get_recommended(bool noselected=0); + my @solvables = $solver->get_recommended(); + solvables = solver.get_recommended() + solvables = solver.get_recommended() + +Return all solvables that are recommended by the solver run result. This includes +solvables included in the result, set noselected if you want to filter those. + + Solvable *get_suggested(bool noselected=0); + my @solvables = $solver->get_suggested(); + solvables = solver.get_suggested() + solvables = solver.get_suggested() + +Return all solvables that are suggested by the solver run result. This includes +solvables included in the result, set noselected if you want to filter those. + + The Problem Class ----------------- Problems are the way of the solver to interact with the user. You can simply list @@ -2451,8 +2618,8 @@ that somewhat describes the problem best to the user. Rule *findallproblemrules(bool unfiltered = 0) my @probrules = $problem->findallproblemrules(); - probrules = problem.findallproblemrule() - probrules = problem.findallproblemrule() + probrules = problem.findallproblemrules() + probrules = problem.findallproblemrules() Return all rules responsible for the problem. The returned set of rules contains all the needed information why there was a problem, but it's hard to present @@ -2741,7 +2908,7 @@ the solver class. Create a job that implements the solution element. Add this job to the array of jobs for all elements of type different to SOLVER_SOLUTION_JOB and -SOLVER_SOLUTION_POOLJOB. For the later two, a SOLVER_NOOB Job is created, +SOLVER_SOLUTION_POOLJOB. For the latter two, a SOLVER_NOOB Job is created, you should replace the old job with the new one. const char *str() @@ -2858,7 +3025,7 @@ Use this flag if you want to map OBSOLETE elements to the UPGRADE type. *SOLVER_TRANSACTION_MERGE_ARCHCHANGES*:: Do not add extra categories for every architecture change, instead cumulate them in one category. - + *SOLVER_TRANSACTION_MERGE_VENDORCHANGES*:: Do not add extra categories for every vendor change, instead cumulate them in one category. @@ -2963,7 +3130,7 @@ be installed packages, returns all of the packages that the new package replaces. The special ``other'' solvable is always the first entry of the returned array. - int calc_installsizechange(); + long long calc_installsizechange(); my $change = $trans->calc_installsizechange(); change = trans.calc_installsizechange() change = trans.calc_installsizechange() @@ -3292,6 +3459,26 @@ after it has been internalized. Write the contents of the repodata area as solv file. + Id str2dir(const char *dir, bool create = 1) + my $did = data->str2dir($dir); + did = data.str2dir(dir) + did = data.str2dir(dir) + + const char *dir2str(Id did, const char *suffix = 0) + $dir = pool->dir2str($did); + dir = pool.dir2str(did) + dir = pool.dir2str(did) + +Convert a string (directory) into an Id and back. If the string is currently not in the +pool and _create_ is false, zero is returned. + + void add_dirstr(Id solvid, Id keyname, Id dir, const char *str) + $data->add_dirstr($solvid, $keyname, $dir, $string) + data.add_dirstr(solvid, keyname, dir, string) + data.add_dirstr(solvid, keyname, dir, string) + +Add a file path consisting of a dirname Id and a basename string. + bool add_solv(FILE *fp, int flags = 0); $data->add_solv($fp); data.add_solv(fp) @@ -3315,9 +3502,10 @@ area. data.extend_to_repo() Extend the repodata so that it has the same size as the repo it belongs to. -This method is only needed when switching to a just written repodata extension -to make the repodata match the written extension (which is always of the -size of the repo). +This method is needed when setting up a new extension repodata so that it +matches the repository size. It is also needed when switching to a just written +repodata extension to make the repodata match the written extension (which is +always of the size of the repo). if ($data1 == $data2) @@ -3334,6 +3522,21 @@ the same id. string = data.lookup_str(solvid, keyname) string = data.lookup_str(solvid, keyname) + const char *lookup_id(Id solvid, Id keyname) + my $string = $data->lookup_id($solvid, $keyname); + string = data.lookup_id(solvid, keyname) + string = data.lookup_id(solvid, keyname) + + unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) + my $num = $data->lookup_num($solvid, $keyname); + num = data.lookup_num(solvid, keyname) + num = data.lookup_num(solvid, keyname) + + bool lookup_void(Id solvid, Id keyname) + my $bool = $data->lookup_void($solvid, $keyname); + bool = data.lookup_void(solvid, keyname) + bool = data.lookup_void(solvid, keyname) + Id *lookup_idarray(Id solvid, Id keyname) my @ids = $data->lookup_idarray($solvid, $keyname); ids = data.lookup_idarray(solvid, keyname) @@ -3350,15 +3553,25 @@ SOLVID_META solvid that stores repodata meta information. === DATA STORAGE METHODS === + void set_str(Id solvid, Id keyname, const char *str); + $data->set_str($solvid, $keyname, $str); + data.set_str(solvid, keyname, str) + data.set_str(solvid, keyname, str) + void set_id(Id solvid, Id keyname, DepId id); $data->set_id($solvid, $keyname, $id); data.set_id(solvid, keyname, id) data.set_id(solvid, keyname, id) - void set_str(Id solvid, Id keyname, const char *str); - $data->set_str($solvid, $keyname, $str); - data.set_str(solvid, keyname, str) - data.set_str(solvid, keyname, str) + void set_num(Id solvid, Id keyname, unsigned long long num); + $data->set_num($solvid, $keyname, $num); + data.set_num(solvid, keyname, num) + data.set_num(solvid, keyname, num) + + void set_void(Id solvid, Id keyname); + $data->set_void($solvid, $keyname); + data.set_void(solvid, keyname) + data.set_void(solvid, keyname) void set_poolstr(Id solvid, Id keyname, const char *str); $data->set_poolstr($solvid, $keyname, $str); @@ -3370,6 +3583,16 @@ SOLVID_META solvid that stores repodata meta information. data.set_checksum(solvid, keyname, chksum) data.set_checksum(solvid, keyname, chksum) + void set_sourcepkg(Id solvid, const char *sourcepkg); + $data.set_sourcepkg($solvid, $sourcepkg); + data.set_sourcepkg(solvid, sourcepkg) + data.set_sourcepkg(solvid, sourcepkg) + + void set_location(Id solvid, unsigned int mediano, const char *location); + $data.set_location($solvid, $mediano, $location); + data.set_location(solvid, mediano, location) + data.set_location(solvid, mediano, location) + void add_idarray(Id solvid, Id keyname, DepId id); $data->add_idarray($solvid, $keyname, $id); data.add_idarray(solvid, keyname, id) @@ -3385,6 +3608,11 @@ SOLVID_META solvid that stores repodata meta information. data.add_flexarray(solvid, keyname, handle) data.add_flexarray(solvid, keyname, handle) + void unset(Id solvid, Id keyname); + $data->unset($solvid, $keyname); + data.unset(solvid, keyname) + data.unset(solvid, keyname) + Data storage methods. Probably only useful to store data in the special SOLVID_META solvid that stores repodata meta information. Note that repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag), @@ -3421,9 +3649,9 @@ Back pointer to repository object. Create a Dataiterator at the position of the datapos object. const char *lookup_deltalocation(unsigned int *OUTPUT); - my ($location, $medianr) = $datapos->lookup_deltalocation(); - location, medianr = datapos.lookup_deltalocation() - location, medianr = datapos.lookup_deltalocation() + my ($location, $mediano) = $datapos->lookup_deltalocation(); + location, mediano = datapos.lookup_deltalocation() + location, mediano = datapos.lookup_deltalocation() Return a tuple containing the on-media location and an optional media number for a delta rpm. This obviously only works if the data position points to @@ -3487,3 +3715,6 @@ Author ------ Michael Schroeder +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/libsolv-constantids.txt b/libsolv-0.7.2/doc/libsolv-constantids.txt similarity index 99% rename from libsolv-0.6.15/doc/libsolv-constantids.txt rename to libsolv-0.7.2/doc/libsolv-constantids.txt index e067642..907a7e5 100644 --- a/libsolv-0.6.15/doc/libsolv-constantids.txt +++ b/libsolv-0.7.2/doc/libsolv-constantids.txt @@ -678,3 +678,6 @@ Author ------ Michael Schroeder +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/libsolv-history.txt b/libsolv-0.7.2/doc/libsolv-history.txt similarity index 99% rename from libsolv-0.6.15/doc/libsolv-history.txt rename to libsolv-0.7.2/doc/libsolv-history.txt index da59fe5..d0a5e62 100644 --- a/libsolv-0.6.15/doc/libsolv-history.txt +++ b/libsolv-0.7.2/doc/libsolv-history.txt @@ -111,3 +111,7 @@ were removed in February. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/libsolv-pool.txt b/libsolv-0.7.2/doc/libsolv-pool.txt similarity index 92% rename from libsolv-0.6.15/doc/libsolv-pool.txt rename to libsolv-0.7.2/doc/libsolv-pool.txt index 8ee0c18..0b9bc41 100644 --- a/libsolv-0.6.15/doc/libsolv-pool.txt +++ b/libsolv-0.7.2/doc/libsolv-pool.txt @@ -270,6 +270,9 @@ should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems. The Function returns the old disttype on success, and -1 if the new disttype is not supported. +Note that any pool_setarch and pool_setarchpolicy calls need to +come after the pool_setdisttype call, as they make use of the +noarch/any/all architecture id. int pool_set_flag(Pool *pool, int flag, int value); @@ -405,11 +408,33 @@ A conditional dependency, the ``name'' sub-dependency is only considered if the ``evr'' sub-dependency is fulfilled. See the section about boolean dependencies about more information. +*REL_UNLESS*:: +A conditional dependency, the ``name'' sub-dependency is only considered if +the ``evr'' sub-dependency is not fulfilled. See the section about boolean +dependencies about more information. + *REL_COMPAT*:: A compat dependency used in Haiku to represent version ranges. The ``name'' part is the actual version, the ``evr'' part is the backwards compatibility version. +*REL_KIND*:: +A pseudo dependency that limits the solvables to a specific kind. +The kind is expected to be a prefix of the solvable name, e.g. +``patch:foo'' would be of kind ``patch''. ``REL_KIND'' is only +supported in the selection functions. + +*REL_MULTIARCH*:: +A debian multiarch annotation. The most common value for the ``evr'' +part is ``any''. + +*REL_ELSE*:: +The else part of a ``REL_COND'' or ``REL_UNLESS'' dependency. See the +section about boolean dependencies. + +*REL_ERROR*:: +An illegal dependency. This is useful to encode dependency parse errors. + === Functions === Id pool_str2id(Pool *pool, const char *str, int create); @@ -474,6 +499,10 @@ Convert a solvable Id into a pointer to the solvable data. Note that the pointer may become invalid if new solvables are created or old solvables deleted, because the array storing all solvables may get reallocated. + Id pool_solvable2id(const Pool *pool, Solvable *s); + +Convert a pointer to the solvable data into a solvable Id. + const char *pool_solvid2str(Pool *pool, Id p); Return a string representing the solvable with the Id _p_. The string will @@ -581,6 +610,16 @@ packages, _idqinst_ for the latter one. This information can be stored in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides is called + void pool_set_whatprovides(pool, Id id, Id offset); + +Manually set an entry in the whatprovides index. You'll never do this for +package dependencies, as those entries are created by calling the +pool_createwhatprovides() function. But this function is useful for +namespace provides if you do not want to use a namespace callback to +lazily set the provides. The offset argument is a offset in the +whatprovides array, thus you can use ``1'' as a false value and ``2'' +as true value. + void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr); Clear the cache of the providers for namespace dependencies matching @@ -812,10 +851,9 @@ SOLVER_FLAG_ALLOW_VENDORCHANGE flag. Boolean Dependencies -------------------- Boolean Dependencies allow to build complex expressions from simple -dependencies. While rpm does not support boolean expressions in -dependencies and debian only allows an "OR" expression, libsolv -allows arbitrary complex expressions. The following basic types -are supported: +dependencies. Note that depending on the package manager only a subset +of those may be useful. For example, debian currently only allows +an "OR" expression. *REL_OR*:: The expression is true if either the first dependency or the second @@ -826,21 +864,33 @@ installed. *REL_AND*:: The expression is true if both dependencies are true. The packages fulfilling the dependencies may be different, i.e. -``Supplements: perl AND python'' is true if both a package providing -perl and a package providing python are installed. The solver currently -only supports REL_AND in Supplements/Enhances dependencies, in other -types of dependencies it gets treated as REL_WITH. +``Supplements: perl REL_AND python'' is true if both a package providing +perl and a package providing python are installed. *REL_WITH*:: The expression is true if both dependencies are true and are fulfilled by -the same package. Thus ``Supplements: perl AND python'' would only be true +the same package. Thus ``Supplements: perl REL_WITH python'' would only be true if a package is installed that provides both dependencies (some kind of multi-language interpreter). *REL_COND*:: The expression is true if the first dependency is true or the second -dependency is false. Libsolv currently does not support this type of -dependency in the solver code. +dependency is false. ``A REL_COND B'' is equivalent to +``A REL_OR (NOT B)'' (except that libsolv does not expose ``NOT''). + +*REL_UNLESS*:: +The expression is true if the first dependency is true and the second +dependency is false. ``A REL_UNLESS B'' is equivalent to +``A REL_AND (NOT B)'' (except that libsolv does not expose ``NOT''). + +*REL_ELSE*:: +The ``else'' part of a ``REL_COND'' or ``REL_UNLESS'' dependency. +It has to be directly in the evr part of the condition, +e.g. ``foo REL_COND (bar REL_ELSE baz)''. +For ``REL_COND'' this is equivalent to writing +``(foo REL_COND bar) REL_AND (bar REL_OR baz)''. +For ``REL_UNLESS'' this is equivalent to writing +``(foo REL_UNLESS bar) REL_OR (bar REL_AND baz)''. Each sub-dependency of a boolean dependency can in turn be a boolean dependency, so you can chain them to create complex dependencies. @@ -879,3 +929,6 @@ Author ------ Michael Schroeder +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/libsolv.txt b/libsolv-0.7.2/doc/libsolv.txt similarity index 98% rename from libsolv-0.6.15/doc/libsolv.txt rename to libsolv-0.7.2/doc/libsolv.txt index af44168..f101808 100644 --- a/libsolv-0.6.15/doc/libsolv.txt +++ b/libsolv-0.7.2/doc/libsolv.txt @@ -56,3 +56,6 @@ Author ------ Michael Schroeder +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/mdk2solv.txt b/libsolv-0.7.2/doc/mdk2solv.txt similarity index 95% rename from libsolv-0.6.15/doc/mdk2solv.txt rename to libsolv-0.7.2/doc/mdk2solv.txt index 2616a87..eb2ac14 100644 --- a/libsolv-0.6.15/doc/mdk2solv.txt +++ b/libsolv-0.7.2/doc/mdk2solv.txt @@ -31,3 +31,7 @@ genhdlist2(1) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/mergesolv.txt b/libsolv-0.7.2/doc/mergesolv.txt similarity index 93% rename from libsolv-0.6.15/doc/mergesolv.txt rename to libsolv-0.7.2/doc/mergesolv.txt index bbe8c72..8ae67d1 100644 --- a/libsolv-0.6.15/doc/mergesolv.txt +++ b/libsolv-0.7.2/doc/mergesolv.txt @@ -23,3 +23,7 @@ Autoexpand SUSE pattern and product provides into packages. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.7.2/doc/repo2solv.txt b/libsolv-0.7.2/doc/repo2solv.txt new file mode 100644 index 0000000..3b2145f --- /dev/null +++ b/libsolv-0.7.2/doc/repo2solv.txt @@ -0,0 +1,60 @@ +repo2solv(1) +============ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +repo2solv - convert repository metadata into a solv file + +Synopsis +-------- +*repo2solv* ['OPTIONS'] 'DIR' + +Description +----------- +The repo2solv tool converts repository metadata in the directory +'DIR' into a solv file written to standard output. + +Note that repo2solv does not verify signatures or checksum, it +is expected that this is done by the tool that downloads the +metadata. + +If no metadata is detected, repo2solv assumes the "plaindir" +format and generates the solv file from all rpm files it +finds. + +*-o* 'OUTFILE':: +Write the solv file to 'OUTFILE' instead of stdout. + +*-R*:: +Also recurse into subdirectories in "plaindir" mode. + +*-F*:: +Put the complete filelist in the output. The default is +to just include the "importent" parts of the file list, +except for "plaindir" mode, which always includes all +files. + +*-C*:: +Add changelog entires to the output. + +*-A*:: +Add appdata pseudo packages to the output. This is an +experimental feature. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +See Also +-------- +dumpsolv(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/repomdxml2solv.txt b/libsolv-0.7.2/doc/repomdxml2solv.txt similarity index 96% rename from libsolv-0.6.15/doc/repomdxml2solv.txt rename to libsolv-0.7.2/doc/repomdxml2solv.txt index feb859c..3b77820 100644 --- a/libsolv-0.6.15/doc/repomdxml2solv.txt +++ b/libsolv-0.7.2/doc/repomdxml2solv.txt @@ -34,3 +34,7 @@ rpmmd2solv(1), mergesolv(1), createrepo(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/rpmdb2solv.txt b/libsolv-0.7.2/doc/rpmdb2solv.txt similarity index 97% rename from libsolv-0.6.15/doc/rpmdb2solv.txt rename to libsolv-0.7.2/doc/rpmdb2solv.txt index 0c4585f..ad8314f 100644 --- a/libsolv-0.6.15/doc/rpmdb2solv.txt +++ b/libsolv-0.7.2/doc/rpmdb2solv.txt @@ -57,3 +57,7 @@ rpms2solv(1) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/rpmmd2solv.txt b/libsolv-0.7.2/doc/rpmmd2solv.txt similarity index 94% rename from libsolv-0.6.15/doc/rpmmd2solv.txt rename to libsolv-0.7.2/doc/rpmmd2solv.txt index c72ccc9..f103f06 100644 --- a/libsolv-0.6.15/doc/rpmmd2solv.txt +++ b/libsolv-0.7.2/doc/rpmmd2solv.txt @@ -28,3 +28,7 @@ repomdxml2solv(1), mergesolv(1), createrepo(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/rpms2solv.txt b/libsolv-0.7.2/doc/rpms2solv.txt similarity index 96% rename from libsolv-0.6.15/doc/rpms2solv.txt rename to libsolv-0.7.2/doc/rpms2solv.txt index 244dffb..11bdcf0 100644 --- a/libsolv-0.6.15/doc/rpms2solv.txt +++ b/libsolv-0.7.2/doc/rpms2solv.txt @@ -46,3 +46,7 @@ rpmdb2solv(1) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.7.2/doc/solv.txt b/libsolv-0.7.2/doc/solv.txt new file mode 100644 index 0000000..936ae78 --- /dev/null +++ b/libsolv-0.7.2/doc/solv.txt @@ -0,0 +1,73 @@ +solv(1) +======= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +solv - example package manager based on libsolv + +Synopsis +-------- +*solv* install [OPTIONS] PKG... + +*solv* erase [OPTIONS] PKG... + +*solv* list [OPTIONS] PKG... + +*solv* info [OPTIONS] PKG... + +*solv* search [OPTIONS] STRING... + +*solv* verify [OPTIONS] PKG... + +*solv* update [OPTIONS] PKG... + +*solv* dist-upgrade [OPTIONS] PKG... + +*solv* repolist [OPTIONS] + +Description +----------- +The solv tool demos some features of the libsolv library. It is not +meant to replace a real package manager, for example it does not cache +downloaded packages. + +*--root* 'ROOTDIR':: +Install packages using 'ROOTDIR' as root of the filesystem. This also +means that the package database of 'ROOTDIR' will be used. + +*--clean*:: +Also get rid of no longer needed packages when erasing, like libraries +that have been used by the erased packages. + +*--best*:: +Force usage of the best package (normally the one with the highest +version) for install and update operations. + +*--testcase*:: +Write a testcase after dependency solving. + +The following options can be used to filter the packages. If the +same option is used multiple times, the result is ORed together. + +*-i*:: +Limit the packages to installed ones. + +*-r* 'REPO':: +Limit the packages to the specified repository. + +*--arch* 'ARCHITECTURE':: +Limit the packages to the specified package architecture. + +*--type* 'TYPE':: +Limit the packages to the specified package type. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/susetags2solv.txt b/libsolv-0.7.2/doc/susetags2solv.txt similarity index 96% rename from libsolv-0.6.15/doc/susetags2solv.txt rename to libsolv-0.7.2/doc/susetags2solv.txt index 9a2e2f1..0d61c4d 100644 --- a/libsolv-0.6.15/doc/susetags2solv.txt +++ b/libsolv-0.7.2/doc/susetags2solv.txt @@ -37,3 +37,7 @@ Autoexpand SUSE pattern and product provides into packages. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/testsolv.txt b/libsolv-0.7.2/doc/testsolv.txt similarity index 97% rename from libsolv-0.6.15/doc/testsolv.txt rename to libsolv-0.7.2/doc/testsolv.txt index dc3a34e..eb52d95 100644 --- a/libsolv-0.6.15/doc/testsolv.txt +++ b/libsolv-0.7.2/doc/testsolv.txt @@ -39,3 +39,7 @@ to encountered problems. Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/doc/updateinfoxml2solv.txt b/libsolv-0.7.2/doc/updateinfoxml2solv.txt similarity index 94% rename from libsolv-0.6.15/doc/updateinfoxml2solv.txt rename to libsolv-0.7.2/doc/updateinfoxml2solv.txt index 7e7c5fc..6ebdeb4 100644 --- a/libsolv-0.6.15/doc/updateinfoxml2solv.txt +++ b/libsolv-0.7.2/doc/updateinfoxml2solv.txt @@ -25,3 +25,7 @@ mergesolv(1), createrepo(8) Author ------ Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/libsolv-0.6.15/examples/CMakeLists.txt b/libsolv-0.7.2/examples/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/examples/CMakeLists.txt rename to libsolv-0.7.2/examples/CMakeLists.txt diff --git a/libsolv-0.6.15/examples/p5solv b/libsolv-0.7.2/examples/p5solv similarity index 99% rename from libsolv-0.6.15/examples/p5solv rename to libsolv-0.7.2/examples/p5solv index 0a1dbb0..6f54247 100755 --- a/libsolv-0.6.15/examples/p5solv +++ b/libsolv-0.7.2/examples/p5solv @@ -256,6 +256,7 @@ sub add_ext { sub add_exts { my ($self) = @_; my $repodata = $self->{handle}->add_repodata(0); + $repodata->extend_to_repo(); $self->add_ext($repodata, 'deltainfo', 'DL'); $self->add_ext($repodata, 'filelists', 'FL'); $repodata->internalize(); @@ -565,6 +566,7 @@ die("unknown command '$cmd'\n") unless defined $cmdactionmap{$cmd}; $pool->addfileprovides(); $pool->createwhatprovides(); +$pool->set_namespaceproviders($solv::NAMESPACE_LANGUAGE, $pool->Dep('de'), 1); my @jobs; for my $arg (@ARGV) { @@ -580,8 +582,8 @@ for my $arg (@ARGV) { print "[ignoring case for '$arg']\n" unless $sel->isempty(); } die("nothing matches '$arg'\n") if $sel->isempty(); - print "[using file list match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_FILELIST; - print "[using capability match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_PROVIDES; + print "[using file list match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_FILELIST; + print "[using capability match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_PROVIDES; push @jobs, $sel->jobs($cmdactionmap{$cmd}); } diff --git a/libsolv-0.6.15/examples/pysolv b/libsolv-0.7.2/examples/pysolv similarity index 99% rename from libsolv-0.6.15/examples/pysolv rename to libsolv-0.7.2/examples/pysolv index 3d6ca07..75067f2 100755 --- a/libsolv-0.6.15/examples/pysolv +++ b/libsolv-0.7.2/examples/pysolv @@ -391,6 +391,7 @@ class repo_repomd(repo_generic): def add_exts(self): repodata = self.handle.add_repodata(0) + repodata.extend_to_repo() self.add_ext(repodata, 'deltainfo', 'DL') self.add_ext(repodata, 'filelists', 'FL') repodata.internalize() @@ -716,9 +717,9 @@ for arg in args: if sel.isempty(): print("nothing matches '%s'" % arg) sys.exit(1) - if sel.flags() & solv.Selection.SELECTION_FILELIST: + if sel.flags & solv.Selection.SELECTION_FILELIST: print("[using file list match for '%s']" % arg) - if sel.flags() & solv.Selection.SELECTION_PROVIDES: + if sel.flags & solv.Selection.SELECTION_PROVIDES: print("[using capability match for '%s']" % arg) jobs += sel.jobs(cmdactionmap[cmd]) diff --git a/libsolv-0.6.15/examples/rbsolv b/libsolv-0.7.2/examples/rbsolv similarity index 99% rename from libsolv-0.6.15/examples/rbsolv rename to libsolv-0.7.2/examples/rbsolv index be633f3..87f0d16 100755 --- a/libsolv-0.6.15/examples/rbsolv +++ b/libsolv-0.7.2/examples/rbsolv @@ -317,6 +317,7 @@ class Repo_rpmmd < Repo_generic def add_exts repodata = @handle.add_repodata(0) + repodata.extend_to_repo() add_ext(repodata, 'deltainfo', 'DL') add_ext(repodata, 'filelists', 'FL') repodata.internalize() diff --git a/libsolv-0.6.15/tools/repo2solv.sh b/libsolv-0.7.2/examples/repo2solv.sh similarity index 92% rename from libsolv-0.6.15/tools/repo2solv.sh rename to libsolv-0.7.2/examples/repo2solv.sh index 11c6567..450b7fa 100755 --- a/libsolv-0.6.15/tools/repo2solv.sh +++ b/libsolv-0.7.2/examples/repo2solv.sh @@ -1,6 +1,9 @@ #! /bin/sh # repo2solv # +# this is a shell implementation of repo2solv that makes use of +# the different parser utilities +# # give it a directory of a local mirror of a repo and this # tries to detect the repo type and generate one SOLV file on stdout @@ -28,7 +31,7 @@ repomd_findfile() { local p=$2 local f if test -n "$t" -a -s repomd.xml ; then - f=`repomdxml2solv -q $t:location < repomd.xml 2>/dev/null` + f=`repomdxml2solv -q "$t:location" < repomd.xml 2>/dev/null` f=${f##*/} if test -f "$f" ; then echo "$f" @@ -44,6 +47,10 @@ repomd_findfile() { fi } +repomd_types() { + test -s repomd.xml && repomdxml2solv -q type < repomd.xml +} + repomd_decompress() { case $1 in *.gz) gzip -dc "$1" ;; @@ -147,6 +154,17 @@ if test "$repotype" = rpmmd ; then if test -f "$susedataxml" ; then repomd_decompress "$susedataxml" fi + # all the languages as well + for t in `repomd_types` ; do + case "$t" in + susedata.*) + susedataxml=`repomd_findfile "$t" "$t.xml"` + if test -f "$susedataxml" ; then + repomd_decompress "$susedataxml" + fi + ;; + esac + done echo '' ) | sed 's/]*>//g' | sed '1i\' | rpmmd2solv $parser_options > $primfile || exit 4 fi @@ -244,6 +262,9 @@ elif test "$repotype" = susetags ; then # Now default language susetags_findfile_cat packages.en + # DL (delta rpms) + susetags_findfile_cat packages.DL + # Now patterns. Not simply those files matching *.pat{,.gz,bz2}, # but only those mentioned in the file 'patterns' if test -f patterns ; then @@ -263,7 +284,7 @@ elif test "$repotype" = susetags ; then esac case $name in # ignore files we handled already - *.DU | *.en | *.FL | packages ) continue ;; + *.DU | *.en | *.FL | *.DL | packages ) continue ;; *) suff=${name#packages.} echo "=Lan: $suff" diff --git a/libsolv-0.6.15/examples/solv/CMakeLists.txt b/libsolv-0.7.2/examples/solv/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/examples/solv/CMakeLists.txt rename to libsolv-0.7.2/examples/solv/CMakeLists.txt diff --git a/libsolv-0.6.15/examples/solv/checksig.c b/libsolv-0.7.2/examples/solv/checksig.c similarity index 86% rename from libsolv-0.6.15/examples/solv/checksig.c rename to libsolv-0.7.2/examples/solv/checksig.c index ff60c66..44603d3 100644 --- a/libsolv-0.6.15/examples/solv/checksig.c +++ b/libsolv-0.7.2/examples/solv/checksig.c @@ -27,6 +27,12 @@ cleanupgpg(char *gpgdir) unlink(cmd); snprintf(cmd, sizeof(cmd), "%s/keys", gpgdir); unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir); + unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/pubring.kbx~", gpgdir); + unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/private-keys-v1.d", gpgdir); + rmdir(cmd); rmdir(gpgdir); } @@ -35,7 +41,7 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) { char *gpgdir; char *keysfile; - const char *pubkey; + const char *pubkey, *pubring; char cmd[256]; FILE *kfp; Solvable *s; @@ -83,7 +89,9 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) lseek(fileno(fp), 0, SEEK_SET); possigfp = lseek(fileno(sigfp), 0, SEEK_CUR); lseek(fileno(sigfp), 0, SEEK_SET); - snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/pubring.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, fileno(sigfp), fileno(fp)); + snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir); + pubring = access(cmd, R_OK) == 0 ? "pubring.kbx" : "pubring.gpg"; + snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/%s /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, pubring, fileno(sigfp), fileno(fp)); fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */ fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */ r = system(cmd); diff --git a/libsolv-0.6.15/examples/solv/checksig.h b/libsolv-0.7.2/examples/solv/checksig.h similarity index 100% rename from libsolv-0.6.15/examples/solv/checksig.h rename to libsolv-0.7.2/examples/solv/checksig.h diff --git a/libsolv-0.6.15/examples/solv/deltarpm.c b/libsolv-0.7.2/examples/solv/deltarpm.c similarity index 97% rename from libsolv-0.6.15/examples/solv/deltarpm.c rename to libsolv-0.7.2/examples/solv/deltarpm.c index 551d570..438c2d8 100644 --- a/libsolv-0.6.15/examples/solv/deltarpm.c +++ b/libsolv-0.7.2/examples/solv/deltarpm.c @@ -75,7 +75,7 @@ trydeltadownload(Solvable *s, const char *loc) seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM)); if (strchr(seq, '\'') != 0) continue; -#ifdef FEDORA +#if defined(FEDORA) || defined(MAGEIA) sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr); #else sprintf(cmd, "/usr/bin/applydeltarpm -c -s '"); @@ -101,7 +101,7 @@ trydeltadownload(Solvable *s, const char *loc) continue; /* got it, now reconstruct */ newfd = opentmpfile(); -#ifdef FEDORA +#if defined(FEDORA) || defined(MAGEIA) sprintf(cmd, "applydeltarpm -a '%s' /dev/fd/%d /dev/fd/%d", archstr, fileno(fp), newfd); #else sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd); diff --git a/libsolv-0.6.15/examples/solv/deltarpm.h b/libsolv-0.7.2/examples/solv/deltarpm.h similarity index 100% rename from libsolv-0.6.15/examples/solv/deltarpm.h rename to libsolv-0.7.2/examples/solv/deltarpm.h diff --git a/libsolv-0.6.15/examples/solv/fastestmirror.c b/libsolv-0.7.2/examples/solv/fastestmirror.c similarity index 100% rename from libsolv-0.6.15/examples/solv/fastestmirror.c rename to libsolv-0.7.2/examples/solv/fastestmirror.c diff --git a/libsolv-0.6.15/examples/solv/fastestmirror.h b/libsolv-0.7.2/examples/solv/fastestmirror.h similarity index 100% rename from libsolv-0.6.15/examples/solv/fastestmirror.h rename to libsolv-0.7.2/examples/solv/fastestmirror.h diff --git a/libsolv-0.6.15/examples/solv/fileconflicts.c b/libsolv-0.7.2/examples/solv/fileconflicts.c similarity index 77% rename from libsolv-0.6.15/examples/solv/fileconflicts.c rename to libsolv-0.7.2/examples/solv/fileconflicts.c index 982de85..2d45bc4 100644 --- a/libsolv-0.6.15/examples/solv/fileconflicts.c +++ b/libsolv-0.7.2/examples/solv/fileconflicts.c @@ -67,7 +67,12 @@ checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Qu { printf("\n"); for (i = 0; i < conflicts->count; i += 6) - printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_solvid2str(pool, conflicts->elements[i + 4])); + { + if (conflicts->elements[i] == conflicts->elements[i + 3]) + printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_solvid2str(pool, conflicts->elements[i + 4])); + else + printf("file %s of package %s conflicts with file %s of package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_id2str(pool, conflicts->elements[i + 3]), pool_solvid2str(pool, conflicts->elements[i + 4])); + } printf("\n"); } return conflicts->count; diff --git a/libsolv-0.6.15/examples/solv/fileconflicts.h b/libsolv-0.7.2/examples/solv/fileconflicts.h similarity index 100% rename from libsolv-0.6.15/examples/solv/fileconflicts.h rename to libsolv-0.7.2/examples/solv/fileconflicts.h diff --git a/libsolv-0.6.15/examples/solv/fileprovides.c b/libsolv-0.7.2/examples/solv/fileprovides.c similarity index 100% rename from libsolv-0.6.15/examples/solv/fileprovides.c rename to libsolv-0.7.2/examples/solv/fileprovides.c diff --git a/libsolv-0.6.15/examples/solv/fileprovides.h b/libsolv-0.7.2/examples/solv/fileprovides.h similarity index 100% rename from libsolv-0.6.15/examples/solv/fileprovides.h rename to libsolv-0.7.2/examples/solv/fileprovides.h diff --git a/libsolv-0.6.15/examples/solv/mirror.c b/libsolv-0.7.2/examples/solv/mirror.c similarity index 100% rename from libsolv-0.6.15/examples/solv/mirror.c rename to libsolv-0.7.2/examples/solv/mirror.c diff --git a/libsolv-0.6.15/examples/solv/mirror.h b/libsolv-0.7.2/examples/solv/mirror.h similarity index 100% rename from libsolv-0.6.15/examples/solv/mirror.h rename to libsolv-0.7.2/examples/solv/mirror.h diff --git a/libsolv-0.6.15/examples/solv/patchjobs.c b/libsolv-0.7.2/examples/solv/patchjobs.c similarity index 93% rename from libsolv-0.6.15/examples/solv/patchjobs.c rename to libsolv-0.7.2/examples/solv/patchjobs.c index 64ad607..929a203 100644 --- a/libsolv-0.6.15/examples/solv/patchjobs.c +++ b/libsolv-0.7.2/examples/solv/patchjobs.c @@ -19,8 +19,10 @@ add_patchjobs(Pool *pool, Queue *job) map_init(&installedmap, pool->nsolvables); solver_calculate_multiversionmap(pool, job, &multiversionmap); if (pool->installed) - FOR_REPO_SOLVABLES(pool->installed, p, s) - MAPSET(&installedmap, p); + { + FOR_REPO_SOLVABLES(pool->installed, p, s) + MAPSET(&installedmap, p); + } /* install all patches */ for (p = 1; p < pool->nsolvables; p++) diff --git a/libsolv-0.6.15/examples/solv/patchjobs.h b/libsolv-0.7.2/examples/solv/patchjobs.h similarity index 100% rename from libsolv-0.6.15/examples/solv/patchjobs.h rename to libsolv-0.7.2/examples/solv/patchjobs.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo.c b/libsolv-0.7.2/examples/solv/repoinfo.c similarity index 93% rename from libsolv-0.6.15/examples/solv/repoinfo.c rename to libsolv-0.7.2/examples/solv/repoinfo.c index e08d160..6273972 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo.c +++ b/libsolv-0.7.2/examples/solv/repoinfo.c @@ -10,17 +10,21 @@ #if defined(ENABLE_DEBIAN) && defined(DEBIAN) #include "repo_deb.h" #endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif + #include "repoinfo.h" #include "repoinfo_cache.h" -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) #include "repoinfo_config_yum.h" #endif #if defined(DEBIAN) #include "repoinfo_config_debian.h" #endif -#if defined(MANDRIVA) || defined(MAGEIA) +#if defined(MANDRIVA) #include "repoinfo_config_urpmi.h" #endif @@ -76,7 +80,7 @@ free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos) solv_free(cinfo->components); } solv_free(repoinfos); -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) yum_substitute((Pool *)0, 0); /* free data */ #endif } @@ -85,10 +89,10 @@ struct repoinfo * read_repoinfos(Pool *pool, int *nrepoinfosp) { struct repoinfo *repoinfos = 0; -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) repoinfos = read_repoinfos_yum(pool, nrepoinfosp); #endif -#if defined(MANDRIVA) || defined(MAGEIA) +#if defined(MANDRIVA) repoinfos = read_repoinfos_urpmi(pool, nrepoinfosp); #endif #if defined(DEBIAN) @@ -110,6 +114,9 @@ read_installed_repo(struct repoinfo *cinfo, Pool *pool) #if defined(ENABLE_DEBIAN) && defined(DEBIAN) r = read_installed_debian(cinfo); #endif +#ifdef SUSE + repo_add_autopattern(cinfo->repo, 0); +#endif pool_set_installed(pool, cinfo->repo); return r; } @@ -235,6 +242,9 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) if ((!cinfo->autorefresh || cinfo->metadata_expire) && usecachedrepo(cinfo, 0, 0)) { +#ifdef SUSE + repo_add_autopattern(cinfo->repo, 0); +#endif printf("repo '%s':", cinfo->alias); printf(" cached\n"); continue; @@ -268,6 +278,10 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) cinfo->repo = 0; break; } +#ifdef SUSE + if (cinfo->repo) + repo_add_autopattern(cinfo->repo, 0); +#endif } if (sigpool) pool_free(sigpool); diff --git a/libsolv-0.6.15/examples/solv/repoinfo.h b/libsolv-0.7.2/examples/solv/repoinfo.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo.h rename to libsolv-0.7.2/examples/solv/repoinfo.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_cache.c b/libsolv-0.7.2/examples/solv/repoinfo_cache.c similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_cache.c rename to libsolv-0.7.2/examples/solv/repoinfo_cache.c diff --git a/libsolv-0.6.15/examples/solv/repoinfo_cache.h b/libsolv-0.7.2/examples/solv/repoinfo_cache.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_cache.h rename to libsolv-0.7.2/examples/solv/repoinfo_cache.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_config_debian.c similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_config_debian.c rename to libsolv-0.7.2/examples/solv/repoinfo_config_debian.c diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_config_debian.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_config_debian.h rename to libsolv-0.7.2/examples/solv/repoinfo_config_debian.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.c b/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.c similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.c rename to libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.c diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.h b/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.h rename to libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_yum.c b/libsolv-0.7.2/examples/solv/repoinfo_config_yum.c similarity index 95% rename from libsolv-0.6.15/examples/solv/repoinfo_config_yum.c rename to libsolv-0.7.2/examples/solv/repoinfo_config_yum.c index 6e2e66a..efccf1e 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_config_yum.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_config_yum.c @@ -1,4 +1,4 @@ -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) #include #include @@ -14,7 +14,7 @@ #include "repoinfo_config_yum.h" -#ifdef FEDORA +#if defined(FEDORA) || defined(MAGEIA) # define REPOINFO_PATH "/etc/yum.repos.d" #endif #ifdef SUSE @@ -48,7 +48,7 @@ yum_substitute(Pool *pool, char *line) queue_init(&q); rpmstate = rpm_state_create(pool, pool_get_rootdir(pool)); - rpm_installedrpmdbids(rpmstate, "Providename", "redhat-release", &q); + rpm_installedrpmdbids(rpmstate, "Providename", "system-release", &q); if (q.count) { void *handle; @@ -62,7 +62,7 @@ yum_substitute(Pool *pool, char *line) queue_free(&q); if (!releaseevr) { - fprintf(stderr, "no installed package provides 'redhat-release', cannot determine $releasever\n"); + fprintf(stderr, "no installed package provides 'system-release', cannot determine $releasever\n"); exit(1); } } @@ -160,7 +160,7 @@ read_repoinfos_yum(Pool *pool, int *nrepoinfosp) cinfo->type = TYPE_RPMMD; cinfo->autorefresh = 1; cinfo->priority = 99; -#ifndef FEDORA +#if !defined(FEDORA) && !defined(MAGEIA) cinfo->repo_gpgcheck = 1; #endif cinfo->metadata_expire = METADATA_EXPIRE; diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_yum.h b/libsolv-0.7.2/examples/solv/repoinfo_config_yum.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_config_yum.h rename to libsolv-0.7.2/examples/solv/repoinfo_config_yum.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_download.c b/libsolv-0.7.2/examples/solv/repoinfo_download.c similarity index 97% rename from libsolv-0.6.15/examples/solv/repoinfo_download.c rename to libsolv-0.7.2/examples/solv/repoinfo_download.c index 5ba3014..f5ba8b9 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_download.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_download.c @@ -13,6 +13,9 @@ #include "repoinfo.h" #include "mirror.h" #include "checksig.h" +#if defined(FEDORA) || defined(MAGEIA) +#include "repoinfo_config_yum.h" +#endif #include "repoinfo_download.h" static inline int @@ -89,7 +92,7 @@ curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsign fclose(fp); if (!cinfo->baseurl) return 0; -#ifdef FEDORA +#if defined(FEDORA) || defined(MAGEIA) if (strchr(cinfo->baseurl, '$')) { char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl); diff --git a/libsolv-0.6.15/examples/solv/repoinfo_download.h b/libsolv-0.7.2/examples/solv/repoinfo_download.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_download.h rename to libsolv-0.7.2/examples/solv/repoinfo_download.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_system_debian.c similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_system_debian.c rename to libsolv-0.7.2/examples/solv/repoinfo_system_debian.c diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_system_debian.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_system_debian.h rename to libsolv-0.7.2/examples/solv/repoinfo_system_debian.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c b/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c similarity index 88% rename from libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c rename to libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c index b385d72..b556afc 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c @@ -17,6 +17,9 @@ #if defined(ENABLE_APPDATA) #include "repo_appdata.h" #endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif #include "transaction.h" #include "repoinfo.h" @@ -27,7 +30,8 @@ # define PRODUCTS_PATH "/etc/products.d" #endif #ifdef ENABLE_APPDATA -# define APPDATA_PATH "/usr/share/appdata" +# define APPDATA_PATH "/usr/share/metainfo" +# define APPDATA_LEGACY_PATH "/usr/share/appdata" #endif static void @@ -101,6 +105,12 @@ read_installed_rpm(struct repoinfo *cinfo) fprintf(stderr, "appdata reading failed: %s\n", pool_errstr(pool)); return 0; } +#elif defined(ENABLE_APPDATA) && defined(APPDATA_LEGACY_PATH) + if (repo_add_appdata_dir(repo, APPDATA_LEGACY_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + fprintf(stderr, "appdata reading from legacy dir failed: %s\n", pool_errstr(pool)); + return 0; + } #endif ofp = fopen(calc_cachepath(repo, 0, 0), "r"); if (repo_add_rpmdb_reffp(repo, ofp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) @@ -111,6 +121,9 @@ read_installed_rpm(struct repoinfo *cinfo) if (ofp) fclose(ofp); repo_internalize(repo); +#ifdef SUSE + repo_add_autopattern(repo, 0); +#endif writecachedrepo(cinfo, 0, 0); return 1; } diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.h b/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_system_rpm.h rename to libsolv-0.7.2/examples/solv/repoinfo_system_rpm.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_type_debian.c similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_type_debian.c rename to libsolv-0.7.2/examples/solv/repoinfo_type_debian.c diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_type_debian.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_type_debian.h rename to libsolv-0.7.2/examples/solv/repoinfo_type_debian.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c b/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c similarity index 86% rename from libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c rename to libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c index 96b005f..69287b3 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c @@ -103,6 +103,18 @@ mdk_load_ext(Repo *repo, Repodata *data) return 1; } +static void +mdk_add_ext(Repo *repo, Repodata *data, const char *what, const char *ext, const char *filename, Id chksumtype, const unsigned char *chksum) +{ + Id handle = repodata_new_handle(data); + /* we mis-use the repomd ids here... need something generic in the future */ + repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, what); + repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, filename); + repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum); + add_ext_keys(data, handle, ext); + repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle); +} + int mdk_load(struct repoinfo *cinfo, Pool **sigpoolp) { @@ -195,13 +207,8 @@ mdk_load(struct repoinfo *cinfo, Pool **sigpoolp) /* setup on-demand loading of filelist data */ if (mdk_find(md5sums, "files.xml.lzma", md5)) { - Id handle = repodata_new_handle(data); - /* we mis-use the repomd ids here... need something generic in the future */ - repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, "filelists"); - repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, "media_info/files.xml.lzma"); - repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, REPOKEY_TYPE_MD5, md5); - add_ext_keys(data, handle, "FL"); - repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle); + repodata_extend_block(data, repo->start, repo->end - repo->start); + mdk_add_ext(repo, data, "filelists", "FL", "media_info/files.xml.lzma", REPOKEY_TYPE_MD5, md5); } solv_free(md5sums); repodata_internalize(data); diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.h b/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_type_mdk.h rename to libsolv-0.7.2/examples/solv/repoinfo_type_mdk.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c b/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c similarity index 97% rename from libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c rename to libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c index 98c5d36..7828379 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c @@ -14,6 +14,9 @@ #ifdef ENABLE_APPDATA #include "repo_appdata.h" #endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif #include "repoinfo.h" #include "repoinfo_cache.h" @@ -195,7 +198,11 @@ repomd_load(struct repoinfo *cinfo, Pool **sigpoolp) fclose(fp); } #endif +#ifdef SUSE + repo_add_autopattern(repo, 0); +#endif data = repo_add_repodata(repo, 0); + repodata_extend_block(data, repo->start, repo->end - repo->start); repomd_add_ext(repo, data, "deltainfo", "DL"); repomd_add_ext(repo, data, "filelists", "FL"); repodata_internalize(data); diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.h b/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.h rename to libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.h diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c b/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c similarity index 97% rename from libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c rename to libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c index 596171c..af933af 100644 --- a/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c +++ b/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c @@ -12,6 +12,9 @@ #ifdef ENABLE_APPDATA #include "repo_appdata.h" #endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif #include "repoinfo.h" #include "repoinfo_cache.h" @@ -47,7 +50,7 @@ susetags_find(Repo *repo, const char *what, const unsigned char **chksump, Id *c return filename; } -void +static void susetags_add_ext(Repo *repo, Repodata *data) { Pool *pool = repo->pool; @@ -263,7 +266,11 @@ susetags_load(struct repoinfo *cinfo, Pool **sigpoolp) } #endif repo_internalize(repo); +#ifdef SUSE + repo_add_autopattern(repo, 0); +#endif data = repo_add_repodata(repo, 0); + repodata_extend_block(data, repo->start, repo->end - repo->start); susetags_add_ext(repo, data); repodata_internalize(data); writecachedrepo(cinfo, 0, 0); diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.h b/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.h similarity index 100% rename from libsolv-0.6.15/examples/solv/repoinfo_type_susetags.h rename to libsolv-0.7.2/examples/solv/repoinfo_type_susetags.h diff --git a/libsolv-0.6.15/examples/solv/solv.c b/libsolv-0.7.2/examples/solv/solv.c similarity index 83% rename from libsolv-0.6.15/examples/solv/solv.c rename to libsolv-0.7.2/examples/solv/solv.c index 6840a6e..3deb1a0 100644 --- a/libsolv-0.6.15/examples/solv/solv.c +++ b/libsolv-0.7.2/examples/solv/solv.c @@ -36,6 +36,7 @@ #include "solver.h" #include "solverdebug.h" #include "transaction.h" +#include "testcase.h" #ifdef SUSE #include "repo_autopattern.h" #endif @@ -49,7 +50,7 @@ #include "fileconflicts.h" #include "deltarpm.h" #endif -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) #include "patchjobs.h" #endif @@ -67,7 +68,7 @@ setarch(Pool *pool) int -yesno(const char *str) +yesno(const char *str, int other) { char inbuf[128], *ip; @@ -88,8 +89,8 @@ yesno(const char *str) printf("Abort.\n"); exit(1); } - if (*ip == 'y' || *ip == 'n') - return *ip == 'y' ? 1 : 0; + if (*ip == 'y' || *ip == 'n' || *ip == other) + return *ip == 'n' ? 0 : *ip; } } @@ -116,17 +117,6 @@ nscallback(Pool *pool, void *data, Id name, Id evr) #ifdef SUSE static void -add_autopackages(Pool *pool) -{ - int i; - Repo *repo; - FOR_REPOS(i, repo) - repo_add_autopattern(repo, 0); -} -#endif - -#ifdef SUSE -static void showdiskusagechanges(Transaction *trans) { DUChanges duc[4]; @@ -140,7 +130,7 @@ showdiskusagechanges(Transaction *trans) duc[3].path = "/etc"; transaction_calc_duchanges(trans, duc, 4); for (i = 0; i < 4; i++) - printf("duchanges %s: %d K %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files); + printf("duchanges %s: %lld K %lld inodes\n", duc[i].path, duc[i].kbytes, duc[i].files); } #endif @@ -179,7 +169,6 @@ find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinf return 0; } - #define MODE_LIST 0 #define MODE_INSTALL 1 #define MODE_ERASE 2 @@ -206,7 +195,7 @@ usage(int r) fprintf(stderr, " search: search name/summary/description\n"); fprintf(stderr, " update: update installed packages\n"); fprintf(stderr, " verify: check dependencies of installed packages\n"); -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) fprintf(stderr, " patch: install newest maintenance updates\n"); #endif fprintf(stderr, "\n"); @@ -236,7 +225,11 @@ main(int argc, char **argv) int forcebest = 0; char *rootdir = 0; char *keyname = 0; + int keyname_depstr = 0; + int keyname_alldeps = 0; /* dnf repoquesy --alldeps */ int debuglevel = 0; + int answer, acnt = 0; + char *testcase = 0; argc--; argv++; @@ -253,7 +246,7 @@ main(int argc, char **argv) mainmode = MODE_INSTALL; mode = SOLVER_INSTALL; } -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) else if (!strcmp(argv[0], "patch")) { mainmode = MODE_PATCH; @@ -323,12 +316,30 @@ main(int argc, char **argv) argc--; argv++; } - if (argc > 2 && !strcmp(argv[1], "--keyname")) + else if (argc > 1 && !strcmp(argv[1], "--alldeps")) + { + keyname_alldeps = 1; /* dnf repoquesy --alldeps */ + argc--; + argv++; + } + else if (argc > 1 && !strcmp(argv[1], "--depstr")) + { + keyname_depstr = 1; /* do literal matching instead of dep intersection */ + argc--; + argv++; + } + else if (argc > 2 && !strcmp(argv[1], "--keyname")) { keyname = argv[2]; argc -= 2; argv += 2; } + else if (argc > 2 && !strcmp(argv[1], "--testcase")) + { + testcase = argv[2]; + argc -= 2; + argv += 2; + } else break; } @@ -454,6 +465,10 @@ main(int argc, char **argv) dataiterator_free(&di); if (repofilter.count) selection_filter(pool, &sel, &repofilter); + if (archfilter.count) + selection_filter(pool, &sel, &archfilter); + if (kindfilter.count) + selection_filter(pool, &sel, &kindfilter); queue_init(&q); selection_solvables(pool, &sel, &q); @@ -492,16 +507,18 @@ main(int argc, char **argv) commandlinepkgs[i] = p; } if (commandlinerepo) - repo_internalize(commandlinerepo); + { + repo_internalize(commandlinerepo); +#ifdef SUSE + repo_add_autopattern(commandlinerepo, 0); +#endif + } } #if defined(ENABLE_RPMDB) if (pool->disttype == DISTTYPE_RPM) addfileprovides(pool); #endif -#ifdef SUSE - add_autopackages(pool); -#endif pool_createwhatprovides(pool); if (keyname) @@ -526,7 +543,9 @@ main(int argc, char **argv) flags |= SELECTION_WITH_SOURCE; if (argv[i][0] == '/') flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0); - if (!keyname) + if (keyname && keyname_depstr) + flags |= SELECTION_MATCH_DEPSTR; + if (!keyname || keyname_alldeps) rflags = selection_make(pool, &job2, argv[i], flags); else rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); @@ -539,7 +558,7 @@ main(int argc, char **argv) if (!job2.count) { flags |= SELECTION_NOCASE; - if (!keyname) + if (!keyname || keyname_alldeps) rflags = selection_make(pool, &job2, argv[i], flags); else rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); @@ -561,6 +580,14 @@ main(int argc, char **argv) printf("[using file list match for '%s']\n", argv[i]); if (rflags & SELECTION_PROVIDES) printf("[using capability match for '%s']\n", argv[i]); + if (keyname && keyname_alldeps) + { + Queue q; + queue_init(&q); + selection_solvables(pool, &job2, &q); + selection_make_matchsolvablelist(pool, &job2, &q, 0, pool_str2id(pool, keyname, 1), 0); + queue_free(&q); + } queue_insertn(&job, job.count, job2.count, job2.elements); queue_free(&job2); } @@ -635,7 +662,7 @@ main(int argc, char **argv) exit(0); } -#if defined(SUSE) || defined(FEDORA) +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) if (mainmode == MODE_PATCH) add_patchjobs(pool, &job); #endif @@ -652,21 +679,22 @@ main(int argc, char **argv) job.elements[i] |= SOLVER_FORCEBEST; } +#if 0 // multiversion test - // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1)); - // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1)); - // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1)); + queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_PROVIDES, pool_str2id(pool, "multiversion(kernel)", 1)); +#endif #if 0 queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); #endif -#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) rerunsolver: -#endif solv = solver_create(pool); solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1); -#ifdef FEDORA +#if 0 + solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); +#endif +#if defined(FEDORA) || defined(MAGEIA) solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1); #endif if (mainmode == MODE_ERASE) @@ -678,7 +706,15 @@ rerunsolver: Id problem, solution; int pcnt, scnt; - if (!solver_solve(solv, &job)) + pcnt = solver_solve(solv, &job); + if (testcase) + { + printf("Writing solver testcase:\n"); + if (!testcase_write(solv, testcase, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0)) + printf("%s\n", pool_errstr(pool)); + testcase = 0; + } + if (!pcnt) break; pcnt = solver_problem_count(solv); printf("Found %d problems:\n", pcnt); @@ -751,10 +787,93 @@ rerunsolver: #if defined(SUSE) showdiskusagechanges(trans); #endif - printf("install size change: %d K\n", transaction_calc_installsizechange(trans)); + printf("install size change: %lld K\n", transaction_calc_installsizechange(trans)); printf("\n"); - if (!yesno("OK to continue (y/n)? ")) + acnt = solver_alternatives_count(solv); + if (acnt) + { + if (acnt == 1) + printf("Have one alternative:\n"); + else + printf("Have %d alternatives:\n", acnt); + for (i = 1; i <= acnt; i++) + { + Id id, from; + int atype = solver_get_alternative(solv, i, &id, &from, 0, 0, 0); + printf(" - %s\n", solver_alternative2str(solv, atype, id, from)); + } + printf("\n"); + answer = yesno("OK to continue (y/n/a)? ", 'a'); + } + else + answer = yesno("OK to continue (y/n)? ", 0); + if (answer == 'a') + { + Queue choicesq; + Queue answerq; + Id id, from, chosen; + int j; + + queue_init(&choicesq); + queue_init(&answerq); + for (i = 1; i <= acnt; i++) + { + int atype = solver_get_alternative(solv, i, &id, &from, &chosen, &choicesq, 0); + printf("\n%s\n", solver_alternative2str(solv, atype, id, from)); + for (j = 0; j < choicesq.count; j++) + { + Id p = choicesq.elements[j]; + if (p < 0) + p = -p; + queue_push(&answerq, p); + printf("%6d: %s\n", answerq.count, pool_solvid2str(pool, p)); + } + } + queue_free(&choicesq); + printf("\n"); + for (;;) + { + char inbuf[128], *ip; + int neg = 0; + printf("OK to continue (y/n), or number to change alternative: "); + fflush(stdout); + *inbuf = 0; + if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) + { + printf("Abort.\n"); + exit(1); + } + while (*ip == ' ' || *ip == '\t') + ip++; + if (*ip == '-' && ip[1] >= '0' && ip[1] <= '9') + { + neg = 1; + ip++; + } + if (*ip >= '0' && *ip <= '9') + { + int take = atoi(ip); + if (take > 0 && take <= answerq.count) + { + Id p = answerq.elements[take - 1]; + queue_free(&answerq); + queue_push2(&job, (neg ? SOLVER_DISFAVOR : SOLVER_FAVOR) | SOLVER_SOLVABLE_NAME, pool->solvables[p].name); + solver_free(solv); + solv = 0; + goto rerunsolver; + break; + } + } + if (*ip == 'n' || *ip == 'y') + { + answer = *ip == 'n' ? 0 : *ip; + break; + } + } + queue_free(&answerq); + } + if (!answer) { printf("Abort.\n"); transaction_free(trans); @@ -843,7 +962,7 @@ rerunsolver: queue_init(&conflicts); if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts)) { - if (yesno("Re-run solver (y/n/q)? ")) + if (yesno("Re-run solver (y/n/q)? ", 0)) { for (i = 0; i < newpkgs; i++) if (newpkgsfps[i]) diff --git a/libsolv-0.6.15/examples/tclsolv b/libsolv-0.7.2/examples/tclsolv similarity index 99% rename from libsolv-0.6.15/examples/tclsolv rename to libsolv-0.7.2/examples/tclsolv index 0fc4e2a..e24c1d8 100755 --- a/libsolv-0.6.15/examples/tclsolv +++ b/libsolv-0.7.2/examples/tclsolv @@ -260,6 +260,7 @@ proc repo_repomd_add_ext {selfName repodata what ext} { proc repo_repomd_add_exts {selfName} { upvar $selfName self set repodata [$self(handle) add_repodata 0] + $repodata extend_to_repo repo_repomd_add_ext self $repodata "filelists" "FL" $repodata internalize } @@ -383,6 +384,7 @@ proc repo_susetags_add_ext {selfName repodata what ext} { proc repo_susetags_add_exts {selfName} { upvar $selfName self set repodata [$self(handle) add_repodata 0] + $repodata extend_to_repo repo_susetags_add_ext self $repodata "packages.FL" "FL" repo_susetags_add_ext self $repodata "packages.FL.gz" "FL" $repodata internalize @@ -634,10 +636,10 @@ foreach arg $::argv { puts "nothing matches '$arg'" exit 1 } - if {[$sel flags] & $solv::Selection_SELECTION_FILELIST} { + if {[$sel cget -flags] & $solv::Selection_SELECTION_FILELIST} { puts "\[using file list match for '$arg']" } - if {[$sel flags] & $solv::Selection_SELECTION_PROVIDES} { + if {[$sel cget -flags] & $solv::Selection_SELECTION_PROVIDES} { puts "\[using capability match for '$arg']" } lappend jobs {*}[$sel jobs $cmdactionmap($cmd)] diff --git a/libsolv-0.6.15/ext/CMakeLists.txt b/libsolv-0.7.2/ext/CMakeLists.txt similarity index 82% rename from libsolv-0.6.15/ext/CMakeLists.txt rename to libsolv-0.7.2/ext/CMakeLists.txt index ad52495..edc2b9f 100644 --- a/libsolv-0.6.15/ext/CMakeLists.txt +++ b/libsolv-0.7.2/ext/CMakeLists.txt @@ -4,12 +4,12 @@ SET (libsolvext_SRCS SET (libsolvext_HEADERS tools_util.h solv_xfopen.h testcase.h) -IF (ENABLE_RPMDB) +IF (ENABLE_RPMDB OR ENABLE_RPMPKG) SET (libsolvext_SRCS ${libsolvext_SRCS} pool_fileconflicts.c repo_rpmdb.c) SET (libsolvext_HEADERS ${libsolvext_HEADERS} pool_fileconflicts.h repo_rpmdb.h) -ENDIF (ENABLE_RPMDB) +ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG) IF (ENABLE_PUBKEY) SET (libsolvext_SRCS ${libsolvext_SRCS} @@ -45,10 +45,12 @@ ENDIF (ENABLE_SUSEREPO) # old cmake does not support parenthetical expressions... IF (ENABLE_COMPLEX_DEPS) -IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB) +IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG) SET (libsolvext_SRCS ${libsolvext_SRCS} pool_parserpmrichdep.c) -ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB) + SET (libsolvext_HEADERS ${libsolvext_HEADERS} + pool_parserpmrichdep.h) +ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG) ENDIF (ENABLE_COMPLEX_DEPS) IF (SUSE) @@ -114,6 +116,21 @@ IF (ENABLE_APPDATA) repo_appdata.h) ENDIF (ENABLE_APPDATA) +IF (ENABLE_RPMMD OR ENABLE_SUSEREPO) + SET (libsolvext_SRCS ${libsolvext_SRCS} + repodata_diskusage.c) +ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO) + +IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) + SET (libsolvext_SRCS ${libsolvext_SRCS} + solv_xmlparser.c) +ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO) + +IF (ENABLE_ZCHUNK_COMPRESSION) + SET (libsolvext_SRCS ${libsolvext_SRCS} + solv_zchunk.c) +ENDIF (ENABLE_ZCHUNK_COMPRESSION) + SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") IF (HAVE_LINKER_VERSION_SCRIPT) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver") @@ -131,7 +148,7 @@ SET_TARGET_PROPERTIES(libsolvext PROPERTIES SOVERSION ${LIBSOLVEXT_SOVERSION}) SET_TARGET_PROPERTIES(libsolvext PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR}) INSTALL (FILES ${libsolvext_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv") -INSTALL (TARGETS libsolvext LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) +INSTALL (TARGETS libsolvext LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION bin) IF (ENABLE_STATIC AND NOT DISABLE_SHARED) ADD_LIBRARY (libsolvext_static STATIC ${libsolvext_SRCS}) diff --git a/libsolv-0.6.15/ext/libsolvext.ver b/libsolv-0.7.2/ext/libsolvext.ver similarity index 97% rename from libsolv-0.6.15/ext/libsolvext.ver rename to libsolv-0.7.2/ext/libsolvext.ver index 654469b..4896e85 100644 --- a/libsolv-0.6.15/ext/libsolvext.ver +++ b/libsolv-0.7.2/ext/libsolvext.ver @@ -2,6 +2,7 @@ SOLV_1.0 { global: pool_deb_get_autoinstalled; pool_findfileconflicts; + pool_parserpmrichdep; repo_add_appdata; repo_add_appdata_dir; repo_add_arch_local; @@ -65,6 +66,7 @@ SOLV_1.0 { testcase_str2dep; testcase_str2job; testcase_str2repo; + testcase_str2solvid; testcase_read; testcase_resultdiff; testcase_solverresult; diff --git a/libsolv-0.6.15/ext/pool_fileconflicts.c b/libsolv-0.7.2/ext/pool_fileconflicts.c similarity index 74% rename from libsolv-0.6.15/ext/pool_fileconflicts.c rename to libsolv-0.7.2/ext/pool_fileconflicts.c index 4238d2d..eaeb52b 100644 --- a/libsolv-0.6.15/ext/pool_fileconflicts.c +++ b/libsolv-0.7.2/ext/pool_fileconflicts.c @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include "pool.h" @@ -38,14 +36,10 @@ struct cbdata { unsigned int lastdiridx; /* last diridx we have seen */ unsigned int lastdirhash; /* strhash of last dir we have seen */ + int lastdiridxbad; Id idx; /* index of package we're looking at */ - Id hx; /* used in findfileconflicts2_cb, limit to files matching hx */ - - Id dirid; /* used in findfileconflicts2_cb, limit to dirs matching dirid */ - Id dirhash; /* used in findfileconflicts2_cb, limit to dirs matching dirhash */ - Queue files; unsigned char *filesspace; unsigned int filesspacen; @@ -66,6 +60,12 @@ struct cbdata { char *canonspace; int canonspacen; + + Hashtable fetchmap; + Hashval fetchmapn; + Map fetchdirmap; + int fetchdirmapn; + Queue newlookat; }; #define FILESSPACE_BLOCK 255 @@ -102,25 +102,29 @@ growhash(Hashtable map, Hashval *mapnp) return m; } +/* first pass for non-alias mode: + * create hash (dhx, idx) of directories that may have conflicts. + * also create map "ixdmap" of packages involved + */ static void finddirs_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { struct cbdata *cbdata = cbdatav; Hashval h, hh; - Id hx, qx; + Id dhx, qx; Id oidx, idx = cbdata->idx; - hx = strhash(fn); - if (!hx) - hx = strlen(fn) + 1; - h = hx & cbdata->dirmapn; + dhx = strhash(fn); + if (!dhx) + dhx = strlen(fn) + 1; /* make sure dhx is not zero */ + h = dhx & cbdata->dirmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->dirmap[2 * h]; if (!qx) break; - if (qx == hx) + if (qx == dhx) break; h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn); } @@ -129,12 +133,13 @@ finddirs_cb(void *cbdatav, const char *fn, struct filelistinfo *info) /* a miss */ if (!cbdata->create) return; - cbdata->dirmap[2 * h] = hx; + cbdata->dirmap[2 * h] = dhx; cbdata->dirmap[2 * h + 1] = idx; if (++cbdata->dirmapused * 2 > cbdata->dirmapn) cbdata->dirmap = growhash(cbdata->dirmap, &cbdata->dirmapn); return; } + /* we saw this dir before */ oidx = cbdata->dirmap[2 * h + 1]; if (oidx == idx) return; @@ -142,31 +147,36 @@ finddirs_cb(void *cbdatav, const char *fn, struct filelistinfo *info) if (oidx != -1) { MAPSET(&cbdata->idxmap, oidx); - cbdata->dirmap[2 * h + 1] = -1; + cbdata->dirmap[2 * h + 1] = -1; /* mark as "multiple packages" */ cbdata->dirconflicts++; } MAPSET(&cbdata->idxmap, idx); } +/* check if a dhx value is marked as "multiple" in the dirmap created by finddirs_cb */ static inline int -isindirmap(struct cbdata *cbdata, Id hx) +isindirmap(struct cbdata *cbdata, Id dhx) { Hashval h, hh; Id qx; - h = hx & cbdata->dirmapn; + h = dhx & cbdata->dirmapn; hh = HASHCHAIN_START; for (;;) { qx = cbdata->dirmap[2 * h]; if (!qx) return 0; - if (qx == hx) + if (qx == dhx) return cbdata->dirmap[2 * h + 1] == -1 ? 1 : 0; h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn); } } +/* collect all possible file conflicts candidates in cbdata->lookat */ +/* algorithm: hash file name into hx. Use cflmap the check if we have seen + * this value before. If yes, we have a file conflict candidate. */ +/* we also do extra work to ignore all-directory conflicts */ static void findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { @@ -188,12 +198,15 @@ findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info) cbdata->lastdirhash = strnhash(fn, dp - fn); } dhx = cbdata->lastdirhash; - /* this mirrors the "if (!hx) hx = strlen(fn) + 1" in finddirs_cb */ + + /* check if the directory is marked as "multiple" in the dirmap */ + /* this mirrors the "if (!dhx) dhx = strlen(fn) + 1" used in finddirs_cb */ if (!isindirmap(cbdata, dhx ? dhx : dp - fn + 1)) return; - hx = strhash_cont(dp, dhx); + + hx = strhash_cont(dp, dhx); /* extend hash to complete file name */ if (!hx) - hx = strlen(fn) + 1; + hx = strlen(fn) + 1; /* make sure hx is not zero */ h = hx & cbdata->cflmapn; hh = HASHCHAIN_START; @@ -217,6 +230,7 @@ findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info) cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn); return; } + /* we have seen this hx before */ oidx = cbdata->cflmap[2 * h + 1]; if (oidx < 0) { @@ -249,7 +263,10 @@ findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info) /* same as findfileconflicts_cb, but * - hashes with just the basename * - sets idx in a map instead of pushing to lookat - * - sets the hash element to -1 if there may be a conflict + * - sets the hash element to -1 ("multiple") if there may be a conflict + * we then use findfileconflicts_alias_cb as second step to generate the candidates. + * we do it this way because normailzing file names is expensive and thus we + * only want to do it for entries marked as "multiple" */ static void findfileconflicts_basename_cb(void *cbdatav, const char *fn, struct filelistinfo *info) @@ -558,6 +575,7 @@ normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create return nspaceoff; } +/* collect all candidates for cflmap entries marked as "multiple" */ static void findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { @@ -596,6 +614,7 @@ findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *i } if (!qx || cbdata->cflmap[2 * h + 1] != -1) return; + /* found entry marked as "multiple", recored as conflict candidate */ if (!cbdata->lastdirhash) cbdata->lastdirhash = strnhash(fn, dp - fn); dirid = normalizedir(cbdata, fn, dp - fn, cbdata->lastdirhash, 1); @@ -603,14 +622,18 @@ findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *i queue_push2(&cbdata->lookat, cbdata->lastdirhash, isdir ? -dirid : dirid); } +/* turn (hx, idx, dhx, dirid) entries into (hx, idx, off, dirid) entries, + * where off is an offset into the filespace block */ static void -findfileconflicts2_cb(void *cbdatav, const char *fn, struct filelistinfo *info) +findfileconflicts_expand_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { struct cbdata *cbdata = cbdatav; - Hashval hx; + Id hx, dhx; + Hashval h, hh; const char *dp; char md5padded[34]; - Id off; + Id off, dirid; + int i; if (!info->dirlen) return; @@ -619,32 +642,47 @@ findfileconflicts2_cb(void *cbdatav, const char *fn, struct filelistinfo *info) { cbdata->lastdiridx = info->diridx; cbdata->lastdirhash = strnhash(fn, dp - fn); + if (cbdata->aliases) + cbdata->lastdiridxbad = MAPTST(&cbdata->fetchdirmap, cbdata->lastdirhash & cbdata->fetchdirmapn) ? 0 : 1; } + if (cbdata->lastdiridxbad) + return; if (cbdata->aliases) { - if (cbdata->lastdirhash != cbdata->dirhash) - return; hx = strhash(dp); + dhx = cbdata->lastdirhash; + dirid = normalizedir(cbdata, fn, dp - fn, dhx, 0); } else { hx = cbdata->lastdirhash; hx = strhash_cont(dp, hx); + dhx = dirid = 0; } if (!hx) hx = strlen(fn) + 1; - if ((Id)hx != cbdata->hx) - return; - if (cbdata->dirid && cbdata->dirid != normalizedir(cbdata, fn, dp - fn, cbdata->dirhash, 0)) - return; - strncpy(md5padded, info->digest, 32); - md5padded[32] = 0; - md5padded[33] = info->color; - /* printf("%d, hx %x -> %s %d %s\n", cbdata->idx, hx, fn, info->mode, info->digest); */ - off = addfilesspace(cbdata, strlen(fn) + (34 + 1)); - memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34); - strcpy((char *)cbdata->filesspace + off + 34, fn); - queue_push(&cbdata->files, off); + + h = (hx ^ (dirid * 37)) & cbdata->fetchmapn; + hh = HASHCHAIN_START; + for (;;) + { + i = cbdata->fetchmap[h]; + if (!i) + break; + if (cbdata->lookat.elements[i - 1] == hx && cbdata->lookat.elements[i + 2] == dirid && cbdata->lookat.elements[i + 1] == dhx) + { + /* printf("%d, hx %x dhx %x dirid %d -> %s %d %s %d\n", cbdata->idx, hx, dhx, dirid, fn, info->mode, info->digest, info->color); */ + strncpy(md5padded, info->digest, 32); + md5padded[32] = 0; + md5padded[33] = info->color; + off = addfilesspace(cbdata, strlen(fn) + (34 + 1)); + memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34); + strcpy((char *)cbdata->filesspace + off + 34, fn); + queue_push2(&cbdata->lookat, hx, cbdata->idx); + queue_push2(&cbdata->lookat, off, dirid); + } + h = HASHCHAIN_NEXT(h, hh, cbdata->fetchmapn); + } } static int @@ -796,25 +834,44 @@ precheck_solvable_files(struct cbdata *cbdata, Pool *pool, Id p) } +/* pool_findfileconflicts: find file conflicts in a set of packages + * input: + * - pkgs: list of packages to check + * - cutoff: packages after this are not checked against each other + * this is useful to ignore file conflicts in already installed packages + * - flags: see pool_fileconflicts.h + * - handle_cb, handle_cbdata: callback for rpm header fetches + * output: + * - conflicts: list of conflicts + * + * This is designed for needing only little memory while still being reasonable fast. + * We do this by hashing the file names and working with the 32bit hash values in the + * first steps of the algorithm. A hash conflict is not a problem as it will just + * lead to some unneeded extra work later on. + */ + int pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata) { - int i, j, cflmapn, idxmapset; + int i, j, idxmapset; struct cbdata cbdata; unsigned int now, start; void *handle; Repo *installed = pool->installed; Id p; - int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS); + int usefilecolors; int hdrfetches; + int lookat_cnt; queue_empty(conflicts); if (!pkgs->count) return 0; now = start = solv_timems(0); + /* Hmm, should we have a different flag for this? */ + usefilecolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS); POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n"); - POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d\n", pkgs->count, cutoff); + POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d, usefilecolors %d\n", pkgs->count, cutoff, usefilecolors); memset(&cbdata, 0, sizeof(cbdata)); cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING; @@ -839,15 +896,12 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in /* avarage file list size: 200 files per package */ /* avarage dir count: 20 dirs per package */ - /* first pass: scan dirs */ + /* first pass: find dirs belonging to multiple packages */ if (!cbdata.aliases) { hdrfetches = 0; - cflmapn = (cutoff + 3) * 64; - while ((cflmapn & (cflmapn - 1)) != 0) - cflmapn = cflmapn & (cflmapn - 1); - cbdata.dirmap = solv_calloc(cflmapn, 2 * sizeof(Id)); - cbdata.dirmapn = cflmapn - 1; /* make it a mask */ + cbdata.dirmapn = mkmask((cutoff + 3) * 16); + cbdata.dirmap = solv_calloc(cbdata.dirmapn + 1, 2 * sizeof(Id)); cbdata.create = 1; idxmapset = 0; for (i = 0; i < pkgs->count; i++) @@ -881,13 +935,10 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in POOL_DEBUG(SOLV_DEBUG_STATS, "dir conflicts found: %d, idxmap %d of %d\n", cbdata.dirconflicts, idxmapset, pkgs->count); } - /* second pass: scan files */ + /* second pass: scan files in the directories found above */ now = solv_timems(0); - cflmapn = (cutoff + 3) * 128; - while ((cflmapn & (cflmapn - 1)) != 0) - cflmapn = cflmapn & (cflmapn - 1); - cbdata.cflmap = solv_calloc(cflmapn, 2 * sizeof(Id)); - cbdata.cflmapn = cflmapn - 1; /* make it a mask */ + cbdata.cflmapn = mkmask((cutoff + 3) * 32); + cbdata.cflmap = solv_calloc(cbdata.cflmapn + 1, 2 * sizeof(Id)); cbdata.create = 1; hdrfetches = 0; for (i = 0; i < pkgs->count; i++) @@ -921,21 +972,18 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in POOL_DEBUG(SOLV_DEBUG_STATS, "lookat_dir size: %d\n", cbdata.lookat_dir.count); queue_free(&cbdata.lookat_dir); - /* we need another pass for aliases */ + /* we need another pass for aliases to generate the normalized directory ids */ + queue_init(&cbdata.norq); if (cbdata.aliases) { now = solv_timems(0); - /* make sure the first offset is not zero */ - addfilesspace(&cbdata, 1); - cflmapn = (cutoff + 3) * 16; - while ((cflmapn & (cflmapn - 1)) != 0) - cflmapn = cflmapn & (cflmapn - 1); - cbdata.normap = solv_calloc(cflmapn, 2 * sizeof(Id)); - cbdata.normapn = cflmapn - 1; /* make it a mask */ + addfilesspace(&cbdata, 1); /* make sure the first offset is not zero */ + cbdata.normapn = mkmask((cutoff + 3) * 4); + cbdata.normap = solv_calloc(cbdata.normapn + 1, 2 * sizeof(Id)); if (cbdata.usestat) { - cbdata.statmap = solv_calloc(cflmapn, 2 * sizeof(Id)); - cbdata.statmapn = cflmapn - 1; /* make it a mask */ + cbdata.statmapn = cbdata.normapn; + cbdata.statmap = solv_calloc(cbdata.statmapn + 1, 2 * sizeof(Id)); } cbdata.create = 0; hdrfetches = 0; @@ -970,22 +1018,23 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in POOL_DEBUG(SOLV_DEBUG_STATS, "alias processing took %d ms\n", solv_timems(now)); } + /* free no longer used stuff */ cbdata.dirmap = solv_free(cbdata.dirmap); cbdata.dirmapn = 0; cbdata.dirmapused = 0; cbdata.cflmap = solv_free(cbdata.cflmap); cbdata.cflmapn = 0; cbdata.cflmapused = 0; - map_free(&cbdata.idxmap); /* sort and unify/prune */ + /* this also makes all dirids positive as side effect */ now = solv_timems(0); - POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d, pruning\n", cbdata.lookat.count / 4); + POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d\n", cbdata.lookat.count / 4); solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool); for (i = j = 0; i < cbdata.lookat.count; ) { - int first = 1; + int first = 1, jstart = j; Id hx = cbdata.lookat.elements[i]; Id idx = cbdata.lookat.elements[i + 1]; Id dhx = cbdata.lookat.elements[i + 2]; @@ -994,7 +1043,12 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in for (; i < cbdata.lookat.count && hx == cbdata.lookat.elements[i] && (dirid == cbdata.lookat.elements[i + 3] || dirid == -cbdata.lookat.elements[i + 3]); i += 4) { if (idx == cbdata.lookat.elements[i + 1] && dhx == cbdata.lookat.elements[i + 2]) - continue; /* ignore duplicates */ + { + if (first && idx < cutoff && cbdata.aliases && dirid >= 0) + first = 0; /* special self-conflict case with dhx hash collision, e.g. /foo/xx and /fpf/xx */ + else + continue; /* ignore duplicates */ + } if (first) { if (dirid < 0) @@ -1004,6 +1058,8 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in cbdata.lookat.elements[j++] = dhx; cbdata.lookat.elements[j++] = dirid; first = 0; + if (jstart >= 0 && idx < cutoff) + jstart = -1; } idx = cbdata.lookat.elements[i + 1]; dhx = cbdata.lookat.elements[i + 2]; @@ -1011,102 +1067,144 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in cbdata.lookat.elements[j++] = idx; cbdata.lookat.elements[j++] = dhx; cbdata.lookat.elements[j++] = dirid; + if (jstart >= 0 && idx < cutoff) + jstart = -1; } + if (jstart >= 0) /* we need at least one new candidate */ + j = jstart; } queue_truncate(&cbdata.lookat, j); - POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4); + POOL_DEBUG(SOLV_DEBUG_STATS, "pruned candidates: %d\n", cbdata.lookat.count / 4); POOL_DEBUG(SOLV_DEBUG_STATS, "pruning took %d ms\n", solv_timems(now)); - /* third pass: collect file info for all files that match a hx */ + /* third pass: expand to real file names */ now = solv_timems(0); + /* sort by idx so we can do all files of a package in one go */ solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_idx_cmp, pool); - queue_init(&cbdata.files); hdrfetches = 0; - for (i = 0; i < cbdata.lookat.count; i += 4) + queue_init(&cbdata.newlookat); + if (cbdata.lookat.count) { - Id idx = cbdata.lookat.elements[i + 1]; + /* setup fetch map space */ + cbdata.fetchmapn = mkmask(cbdata.lookat.count + 3); + if (cbdata.fetchmapn < 4095) + cbdata.fetchmapn = 4095; + cbdata.fetchmap = solv_calloc(cbdata.fetchmapn + 1, sizeof(Id)); + if (cbdata.aliases) + { + cbdata.fetchdirmapn = ((cbdata.fetchmapn + 1) / 16) - 1; + map_init(&cbdata.fetchdirmap, cbdata.fetchdirmapn + 1); + } + } + lookat_cnt = cbdata.lookat.count; + while (lookat_cnt) + { + Id idx = cbdata.lookat.elements[1]; int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS; - if (obsoleteusescolors) + if (usefilecolors) iterflags |= RPM_ITERATE_FILELIST_WITHCOL; + /* find end of idx block */ + for (j = 4; j < lookat_cnt; j += 4) + if (cbdata.lookat.elements[j + 1] != idx) + break; p = pkgs->elements[idx]; handle = (*handle_cb)(pool, p, handle_cbdata); - if (handle) - hdrfetches++; - for (;; i += 4) + if (!handle) { - int fstart = cbdata.files.count; - queue_push(&cbdata.files, idx); - queue_push(&cbdata.files, 0); - cbdata.idx = idx; - cbdata.hx = cbdata.lookat.elements[i]; - cbdata.dirhash = cbdata.lookat.elements[i + 2]; - cbdata.dirid = cbdata.lookat.elements[i + 3]; - cbdata.lastdiridx = -1; - if (handle) - rpm_iterate_filelist(handle, iterflags, findfileconflicts2_cb, &cbdata); - cbdata.files.elements[fstart + 1] = cbdata.files.count; - cbdata.lookat.elements[i + 1] = fstart; - if (i + 4 >= cbdata.lookat.count || cbdata.lookat.elements[i + 4 + 1] != idx) - break; + queue_deleten(&cbdata.lookat, 0, j); + lookat_cnt -= j; + continue; + } + hdrfetches++; + /* create hash which maps (hx, dirid) to lookat elements */ + /* also create map from dhx values for fast reject */ + for (i = 0; i < j; i += 4) + { + Hashval h, hh; + h = (cbdata.lookat.elements[i] ^ (cbdata.lookat.elements[i + 3] * 37)) & cbdata.fetchmapn; + hh = HASHCHAIN_START; + while (cbdata.fetchmap[h]) + h = HASHCHAIN_NEXT(h, hh, cbdata.fetchmapn); + cbdata.fetchmap[h] = i + 1; + cbdata.lookat.elements[i + 1] = (Id)h; /* hack: misuse idx for easy hash cleanup */ + if (cbdata.fetchdirmapn) + MAPSET(&cbdata.fetchdirmap, cbdata.lookat.elements[i + 2] & cbdata.fetchdirmapn); + } + cbdata.idx = idx; + cbdata.lastdiridx = -1; + cbdata.lastdiridxbad = 0; + queue_prealloc(&cbdata.newlookat, j + 256); + rpm_iterate_filelist(handle, iterflags, findfileconflicts_expand_cb, &cbdata); + /* clear hash and map again */ + for (i = 0; i < j; i += 4) + { + Hashval h = (Hashval)cbdata.lookat.elements[i + 1]; + cbdata.fetchmap[h] = 0; + if (cbdata.fetchdirmapn) + MAPCLR_AT(&cbdata.fetchdirmap, cbdata.lookat.elements[i + 2] & cbdata.fetchdirmapn); } + /* now delete old block and add new block to the end */ + queue_deleten(&cbdata.lookat, 0, j); + queue_insertn(&cbdata.lookat, cbdata.lookat.count, cbdata.newlookat.count, cbdata.newlookat.elements); + queue_empty(&cbdata.newlookat); + lookat_cnt -= j; } + queue_free(&cbdata.newlookat); POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches); - POOL_DEBUG(SOLV_DEBUG_STATS, "file info fetching took %d ms\n", solv_timems(now)); - + POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4); + POOL_DEBUG(SOLV_DEBUG_STATS, "file expansion took %d ms\n", solv_timems(now)); + /* free memory */ + cbdata.fetchmap = solv_free(cbdata.fetchmap); + cbdata.fetchmapn = 0; + if (cbdata.fetchdirmapn) + map_free(&cbdata.fetchdirmap); + cbdata.fetchdirmapn = 0; cbdata.normap = solv_free(cbdata.normap); cbdata.normapn = 0; + queue_free(&cbdata.norq); - /* forth pass: for each hx we have, compare all matching files against all other matching files */ + /* forth pass: for each (hx,dirid) we have, compare all matching files against all other matching files */ now = solv_timems(0); solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool); for (i = 0; i < cbdata.lookat.count - 4; i += 4) { Id hx = cbdata.lookat.elements[i]; - Id pstart = cbdata.lookat.elements[i + 1]; Id dirid = cbdata.lookat.elements[i + 3]; - Id pidx = cbdata.files.elements[pstart]; - Id pend = cbdata.files.elements[pstart + 1]; - if (cbdata.lookat.elements[i + 4] != hx) - continue; /* no package left with that hx */ + Id idxi = cbdata.lookat.elements[i + 1]; + Id offi = cbdata.lookat.elements[i + 2]; + if (idxi >= cutoff) + continue; /* no conflicts between packages with idx >= cutoff */ for (j = i + 4; j < cbdata.lookat.count && cbdata.lookat.elements[j] == hx && cbdata.lookat.elements[j + 3] == dirid; j += 4) { - Id qstart = cbdata.lookat.elements[j + 1]; - Id qidx = cbdata.files.elements[qstart]; - Id qend = cbdata.files.elements[qstart + 1]; - int ii, jj; - if (pidx >= cutoff && qidx >= cutoff) - continue; /* no conflicts between packages with idx >= cutoff */ - for (ii = pstart + 2; ii < pend; ii++) - for (jj = qstart + 2; jj < qend; jj++) - { - char *fsi = (char *)cbdata.filesspace + cbdata.files.elements[ii]; - char *fsj = (char *)cbdata.filesspace + cbdata.files.elements[jj]; - if (cbdata.aliases) - { - /* compare just the basenames, the dirs match because of the dirid */ - char *bsi = strrchr(fsi + 34, '/'); - char *bsj = strrchr(fsj + 34, '/'); - if (!bsi || !bsj) - continue; - if (strcmp(bsi, bsj)) - continue; /* different base names */ - } - else - { - if (strcmp(fsi + 34, fsj + 34)) - continue; /* different file names */ - } - if (!strcmp(fsi, fsj)) - continue; /* file digests match, no conflict */ - if (obsoleteusescolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0) - continue; /* colors do not conflict */ - queue_push(conflicts, pool_str2id(pool, fsi + 34, 1)); - queue_push(conflicts, pkgs->elements[pidx]); - queue_push(conflicts, pool_str2id(pool, fsi, 1)); - queue_push(conflicts, pool_str2id(pool, fsj + 34, 1)); - queue_push(conflicts, pkgs->elements[qidx]); - queue_push(conflicts, pool_str2id(pool, fsj, 1)); - } + Id idxj = cbdata.lookat.elements[j + 1]; + Id offj = cbdata.lookat.elements[j + 2]; + char *fsi = (char *)cbdata.filesspace + offi; + char *fsj = (char *)cbdata.filesspace + offj; + if (cbdata.aliases) + { + /* compare just the basenames, the dirs match because of the dirid */ + char *bsi = strrchr(fsi + 34, '/'); + char *bsj = strrchr(fsj + 34, '/'); + if (!bsi || !bsj) + continue; + if (strcmp(bsi, bsj)) + continue; /* different base names */ + } + else + { + if (strcmp(fsi + 34, fsj + 34)) + continue; /* different file names */ + } + if (!strcmp(fsi, fsj)) + continue; /* file digests match, no conflict */ + if (usefilecolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0) + continue; /* colors do not conflict */ + queue_push(conflicts, pool_str2id(pool, fsi + 34, 1)); + queue_push(conflicts, pkgs->elements[idxi]); + queue_push(conflicts, pool_str2id(pool, fsi, 1)); + queue_push(conflicts, pool_str2id(pool, fsj + 34, 1)); + queue_push(conflicts, pkgs->elements[idxj]); + queue_push(conflicts, pool_str2id(pool, fsj, 1)); } } POOL_DEBUG(SOLV_DEBUG_STATS, "filespace size: %d K\n", cbdata.filesspacen / 1024); @@ -1114,7 +1212,6 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in cbdata.filesspace = solv_free(cbdata.filesspace); cbdata.filesspacen = 0; queue_free(&cbdata.lookat); - queue_free(&cbdata.files); if (conflicts->count > 6) solv_sort(conflicts->elements, conflicts->count / 6, 6 * sizeof(Id), conflicts_cmp, pool); POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file conflicts\n", conflicts->count / 6); diff --git a/libsolv-0.6.15/ext/pool_fileconflicts.h b/libsolv-0.7.2/ext/pool_fileconflicts.h similarity index 100% rename from libsolv-0.6.15/ext/pool_fileconflicts.h rename to libsolv-0.7.2/ext/pool_fileconflicts.h diff --git a/libsolv-0.6.15/ext/pool_parserpmrichdep.c b/libsolv-0.7.2/ext/pool_parserpmrichdep.c similarity index 88% rename from libsolv-0.6.15/ext/pool_parserpmrichdep.c rename to libsolv-0.7.2/ext/pool_parserpmrichdep.c index d3e559e..93d77f8 100644 --- a/libsolv-0.6.15/ext/pool_parserpmrichdep.c +++ b/libsolv-0.7.2/ext/pool_parserpmrichdep.c @@ -17,10 +17,13 @@ static struct RichOpComp { int l; Id fl; } RichOps[] = { - { "and", 3, REL_AND }, - { "or", 2, REL_OR }, - { "if", 2, REL_COND }, - { "else", 4, REL_ELSE }, + { "and", 3, REL_AND }, + { "or", 2, REL_OR }, + { "if", 2, REL_COND }, + { "unless", 6, REL_UNLESS }, + { "else", 4, REL_ELSE }, + { "with", 4, REL_WITH }, + { "without", 7, REL_WITHOUT }, { NULL, 0, 0}, }; @@ -106,7 +109,7 @@ parseRichDep(Pool *pool, const char **depp, Id chainfl) fl = op->fl; if (!fl) return 0; - if (chainfl == REL_COND && fl == REL_ELSE) + if ((chainfl == REL_COND || chainfl == REL_UNLESS) && fl == REL_ELSE) chainfl = 0; if (chainfl && fl != chainfl) return 0; diff --git a/libsolv-0.6.15/ext/pool_parserpmrichdep.h b/libsolv-0.7.2/ext/pool_parserpmrichdep.h similarity index 100% rename from libsolv-0.6.15/ext/pool_parserpmrichdep.h rename to libsolv-0.7.2/ext/pool_parserpmrichdep.h diff --git a/libsolv-0.6.15/ext/repo_appdata.c b/libsolv-0.7.2/ext/repo_appdata.c similarity index 66% rename from libsolv-0.6.15/ext/repo_appdata.c rename to libsolv-0.7.2/ext/repo_appdata.c index cbc42e4..3174968 100644 --- a/libsolv-0.6.15/ext/repo_appdata.c +++ b/libsolv-0.7.2/ext/repo_appdata.c @@ -14,20 +14,17 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include #include #include "pool.h" #include "repo.h" #include "util.h" +#include "solv_xmlparser.h" #include "repo_appdata.h" @@ -53,15 +50,8 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { { STATE_START, "applications", STATE_START, 0 }, { STATE_START, "components", STATE_START, 0 }, { STATE_START, "application", STATE_APPLICATION, 0 }, @@ -86,23 +76,15 @@ static struct stateswitch stateswitches[] = { }; struct parsedata { - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Pool *pool; Repo *repo; Repodata *data; - - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; + int ret; Solvable *solvable; Id handle; + int skiplang; char *description; int licnt; int skip_depth; @@ -111,79 +93,41 @@ struct parsedata { int havesummary; const char *filename; Queue *owners; -}; - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - if (!strcmp(*atts, txt)) - return atts[1]; - return 0; -} + struct solv_xmlparser xmlp; +}; -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; - struct stateswitch *sw; const char *type; -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) /* no statetable -> no substates */ - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - - if (!pd->skip_depth && find_attr("xml:lang", atts)) - pd->skip_depth = pd->depth; - if (pd->skip_depth) + /* ignore all language tags */ + if (pd->skiplang || solv_xmlparser_find_attr("xml:lang", atts)) { - pd->docontent = 0; + pd->skiplang++; return; } - switch(pd->state) + switch(state) { case STATE_APPLICATION: + type = solv_xmlparser_find_attr("type", atts); + if (!type || !*type) + type = "desktop"; + if (strcmp(type, "desktop") != 0) + { + /* ignore for now */ + pd->solvable = 0; + break; + } s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); pd->handle = s - pool->solvables; pd->havesummary = 0; - type = find_attr("type", atts); - if (!type || !*type) - type = "desktop"; repodata_set_poolstr(pd->data, pd->handle, SOLVABLE_CATEGORY, type); break; case STATE_DESCRIPTION: @@ -200,51 +144,55 @@ startElement(void *userData, const char *name, const char **atts) /* replace whitespace with one space/newline */ /* also strip starting/ending whitespace */ -static void +static char * wsstrip(struct parsedata *pd) { + struct solv_xmlparser *xmlp = &pd->xmlp; int i, j; int ws = 0; - for (i = j = 0; pd->content[i]; i++) + for (i = j = 0; xmlp->content[i]; i++) { - if (pd->content[i] == ' ' || pd->content[i] == '\t' || pd->content[i] == '\n') + if (xmlp->content[i] == ' ' || xmlp->content[i] == '\t' || xmlp->content[i] == '\n') { - ws |= pd->content[i] == '\n' ? 2 : 1; + ws |= xmlp->content[i] == '\n' ? 2 : 1; continue; } if (ws && j) - pd->content[j++] = (ws & 2) ? '\n' : ' '; + xmlp->content[j++] = (ws & 2) ? '\n' : ' '; ws = 0; - pd->content[j++] = pd->content[i]; + xmlp->content[j++] = xmlp->content[i]; } - pd->content[j] = 0; - pd->lcontent = j; + xmlp->content[j] = 0; + xmlp->lcontent = j; + return xmlp->content; } /* indent all lines */ -static void +static char * indent(struct parsedata *pd, int il) { + struct solv_xmlparser *xmlp = &pd->xmlp; int i, l; - for (l = 0; pd->content[l]; ) + for (l = 0; xmlp->content[l]; ) { - if (pd->content[l] == '\n') + if (xmlp->content[l] == '\n') { l++; continue; } - if (pd->lcontent + il + 1 > pd->acontent) + if (xmlp->lcontent + il + 1 > xmlp->acontent) { - pd->acontent = pd->lcontent + il + 256; - pd->content = realloc(pd->content, pd->acontent); + xmlp->acontent = xmlp->lcontent + il + 256; + xmlp->content = realloc(xmlp->content, xmlp->acontent); } - memmove(pd->content + l + il, pd->content + l, pd->lcontent - l + 1); + memmove(xmlp->content + l + il, xmlp->content + l, xmlp->lcontent - l + 1); for (i = 0; i < il; i++) - pd->content[l + i] = ' '; - pd->lcontent += il; - while (pd->content[l] && pd->content[l] != '\n') + xmlp->content[l + i] = ' '; + xmlp->lcontent += il; + while (xmlp->content[l] && xmlp->content[l] != '\n') l++; } + return xmlp->content; } static void @@ -340,40 +288,23 @@ guess_filename_from_id(Pool *pool, const char *id) return r; } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; Id id; -#if 0 - fprintf(stderr, "end: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - - if (pd->skip_depth && pd->depth + 1 >= pd->skip_depth) + if (pd->skiplang) { - if (pd->depth + 1 == pd->skip_depth) - pd->skip_depth = 0; - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; + pd->skiplang--; return; } - pd->skip_depth = 0; + if (!s) + return; - switch (pd->state) + switch (state) { case STATE_APPLICATION: if (!s->arch) @@ -421,26 +352,26 @@ endElement(void *userData, const char *name) pd->desktop_file = solv_free(pd->desktop_file); break; case STATE_ID: - pd->desktop_file = solv_strdup(pd->content); + pd->desktop_file = solv_strdup(content); break; case STATE_NAME: - s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", pd->content, 0), 1); + s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", content, 0), 1); break; case STATE_LICENCE: - repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, pd->content); + repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, content); break; case STATE_SUMMARY: pd->havesummary = 1; - repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content); + repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content); break; case STATE_URL: - repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, pd->content); + repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, content); break; case STATE_GROUP: - repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, pd->content); + repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, content); break; case STATE_EXTENDS: - repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, pd->content); + repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, content); break; case STATE_DESCRIPTION: if (pd->description) @@ -453,83 +384,47 @@ endElement(void *userData, const char *name) } break; case STATE_P: - wsstrip(pd); - pd->description = solv_dupappend(pd->description, pd->content, "\n\n"); + content = wsstrip(pd); + pd->description = solv_dupappend(pd->description, content, "\n\n"); break; case STATE_UL_LI: wsstrip(pd); - indent(pd, 4); - pd->content[2] = '-'; - pd->description = solv_dupappend(pd->description, pd->content, "\n"); + content = indent(pd, 4); + content[2] = '-'; + pd->description = solv_dupappend(pd->description, content, "\n"); break; case STATE_OL_LI: wsstrip(pd); - indent(pd, 4); + content = indent(pd, 4); if (++pd->licnt >= 10) - pd->content[0] = '0' + (pd->licnt / 10) % 10; - pd->content[1] = '0' + pd->licnt % 10; - pd->content[2] = '.'; - pd->description = solv_dupappend(pd->description, pd->content, "\n"); + content[0] = '0' + (pd->licnt / 10) % 10; + content[1] = '0' + pd->licnt % 10; + content[2] = '.'; + pd->description = solv_dupappend(pd->description, content, "\n"); break; case STATE_UL: case STATE_OL: pd->description = solv_dupappend(pd->description, "\n", 0); break; case STATE_PKGNAME: - id = pool_str2id(pd->pool, pd->content, 1); + id = pool_str2id(pd->pool, content, 1); s->requires = repo_addid_dep(pd->repo, s->requires, id, 0); - id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pd->content, ")"), 1); + id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", content, ")"), 1); s->provides = repo_addid_dep(pd->repo, s->provides, id, 0); break; case STATE_KEYWORD: - repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, pd->content); + repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, content); break; default: break; } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - -#if 0 - fprintf(stderr, "end: [%s] -> %d\n", name, pd->state); -#endif -} - - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->acontent = l + 256; - pd->content = realloc(pd->content, pd->acontent); - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; } -#define BUFF_SIZE 8192 - static int repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners) { - Pool *pool = repo->pool; - struct parsedata pd; - struct stateswitch *sw; Repodata *data; - char buf[BUFF_SIZE]; - int i, l; - int ret = 0; + struct parsedata pd; data = repo_add_repodata(repo, flags); memset(&pd, 0, sizeof(pd)); @@ -540,47 +435,22 @@ repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue pd.filename = filename; pd.owners = owners; - pd.content = malloc(256); - pd.acontent = 256; - - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; + pool_debug(pd.pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + pd.ret = -1; + pd.solvable = solvable_free(pd.solvable, 1); } + solv_xmlparser_free(&pd.xmlp); - XML_Parser parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pool_error(pool, -1, "repo_appdata: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - if (pd.solvable) - { - repo_free_solvable(repo, pd.solvable - pd.pool->solvables, 1); - pd.solvable = 0; - } - ret = -1; - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); + solv_free(pd.desktop_file); + solv_free(pd.description); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); - solv_free(pd.content); - solv_free(pd.desktop_file); - solv_free(pd.description); - return ret; + return pd.ret; } int @@ -589,13 +459,40 @@ repo_add_appdata(Repo *repo, FILE *fp, int flags) return repo_add_appdata_fn(repo, fp, flags, 0, 0); } +struct uninternalized_filelist_data { + Id did; + Queue *res; +}; + +static int +search_uninternalized_filelist_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +{ + struct uninternalized_filelist_data *uf = cbdata; + const char *str; + Id id; + size_t l; + if (key->type != REPOKEY_TYPE_DIRSTRARRAY || kv->id != uf->did) + return 0; + str = kv->str; + l = strlen(str); + if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12)) + id = pool_str2id(data->repo->pool, str, 1); + else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13)) + id = pool_str2id(data->repo->pool, str, 1); + else + return 0; + queue_push2(uf->res, s - data->repo->pool->solvables, id); + return 0; +} + static void search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res) { Pool *pool = repo->pool; - Id rdid, p; - Id iter, did, idid; + Id did, rdid, p; + struct uninternalized_filelist_data uf; + uf.res = res; for (rdid = 1; rdid < repo->nrepodata; rdid++) { Repodata *data = repo_id2repodata(repo, rdid); @@ -608,31 +505,12 @@ search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res) did = repodata_str2dir(data, dir, 0); if (!did) continue; + uf.did = did; for (p = data->start; p < data->end; p++) { - if (p >= pool->nsolvables) - continue; - if (pool->solvables[p].repo != repo) + if (p >= pool->nsolvables || pool->solvables[p].repo != repo) continue; - iter = 0; - for (;;) - { - const char *str; - int l; - Id id; - idid = did; - str = repodata_lookup_dirstrarray_uninternalized(data, p, SOLVABLE_FILELIST, &idid, &iter); - if (!iter) - break; - l = strlen(str); - if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12)) - id = pool_str2id(pool, str, 1); - else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13)) - id = pool_str2id(pool, str, 1); - else - continue; - queue_push2(res, p, id); - } + repodata_search_uninternalized(data, p, SOLVABLE_FILELIST, 0, search_uninternalized_filelist_cb, &uf); } } } diff --git a/libsolv-0.6.15/ext/repo_appdata.h b/libsolv-0.7.2/ext/repo_appdata.h similarity index 100% rename from libsolv-0.6.15/ext/repo_appdata.h rename to libsolv-0.7.2/ext/repo_appdata.h diff --git a/libsolv-0.6.15/ext/repo_arch.c b/libsolv-0.7.2/ext/repo_arch.c similarity index 99% rename from libsolv-0.6.15/ext/repo_arch.c rename to libsolv-0.7.2/ext/repo_arch.c index a0c45ce..698d506 100644 --- a/libsolv-0.6.15/ext/repo_arch.c +++ b/libsolv-0.7.2/ext/repo_arch.c @@ -444,8 +444,7 @@ repo_add_arch_pkg(Repo *repo, const char *fn, int flags) if (s && !s->name) { pool_error(pool, -1, "%s: package has no name", fn); - repo_free_solvable(repo, s - pool->solvables, 1); - s = 0; + s = solvable_free(s, 1); } if (s) { @@ -728,7 +727,7 @@ finishsolvable(Repo *repo, Solvable *s) return; if (!s->name) { - repo_free_solvable(repo, s - pool->solvables, 1); + solvable_free(s, 1); return; } if (!s->arch) diff --git a/libsolv-0.6.15/ext/repo_arch.h b/libsolv-0.7.2/ext/repo_arch.h similarity index 100% rename from libsolv-0.6.15/ext/repo_arch.h rename to libsolv-0.7.2/ext/repo_arch.h diff --git a/libsolv-0.6.15/ext/repo_autopattern.c b/libsolv-0.7.2/ext/repo_autopattern.c similarity index 89% rename from libsolv-0.6.15/ext/repo_autopattern.c rename to libsolv-0.7.2/ext/repo_autopattern.c index 4c767e1..4c09e79 100644 --- a/libsolv-0.6.15/ext/repo_autopattern.c +++ b/libsolv-0.7.2/ext/repo_autopattern.c @@ -82,6 +82,33 @@ datestr2timestamp(const char *date) return timegm(&tm); } +/* we just look at the repodata keys and do not iterate + * over the solvables, because iterating would mean a + * load of stub repodata areas */ +static void +find_langkeys(Repo *repo, Id keyname, Queue *q) +{ + Pool *pool = repo->pool; + int rid; + int i; + const char *keyname_str; + size_t keyname_len; + + keyname_str = pool_id2str(pool, keyname); + keyname_len = strlen(keyname_str); + queue_empty(q); + for (rid = 1; rid < repo->nrepodata; rid++) + { + Repodata *data = repo_id2repodata(repo, rid); + for (i = 1; i < data->nkeys; i++) + { + const char *s = pool_id2str(pool, data->keys[i].name); + if (!strncmp(s, keyname_str, keyname_len) && s[keyname_len] == ':') + queue_pushunique(q, data->keys[i].name); + } + } +} + int repo_add_autopattern(Repo *repo, int flags) { @@ -94,6 +121,7 @@ repo_add_autopattern(Repo *repo, int flags) Id pattern_id, product_id; Id autopattern_id = 0, autoproduct_id = 0; int i, j; + Queue categorykeys; queue_init(&patq); queue_init(&patq2); @@ -105,6 +133,8 @@ repo_add_autopattern(Repo *repo, int flags) pattern_id = pool_str2id(pool, "pattern()", 9); product_id = pool_str2id(pool, "product()", 9); + + queue_init(&categorykeys); FOR_REPO_SOLVABLES(repo, p, s) { const char *n = pool_id2str(pool, s->name); @@ -159,6 +189,11 @@ repo_add_autopattern(Repo *repo, int flags) } } } + if (patq2.count) + { + find_langkeys(repo, SOLVABLE_CATEGORY, &categorykeys); + queue_unshift(&categorykeys, SOLVABLE_CATEGORY); + } for (i = 0; i < patq2.count; i += 2) { const char *pn = 0; @@ -273,9 +308,17 @@ repo_add_autopattern(Repo *repo, int flags) repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE, newname); } } + /* also try to copy the pattern category from the solvable */ + for (j = 0; j < categorykeys.count; j++) + { + Id catkey = categorykeys.elements[j]; + if ((str = solvable_lookup_str(s, catkey)) != 0) + repodata_set_str(data, s2 - pool->solvables, catkey, str); + } } queue_free(&patq); queue_free(&patq2); + queue_free(&categorykeys); if ((flags & ADD_NO_AUTOPRODUCTS) != 0) queue_empty(&prdq2); @@ -396,11 +439,10 @@ repo_add_autopattern(Repo *repo, int flags) repodata_set_str(data, h, PRODUCT_UPDATES_REPOID, newname); repodata_add_flexarray(data, s2 - pool->solvables, PRODUCT_UPDATES, h); } - else if (!strcmp(pn, "product-endoflife()") && evr) + else if (!strcmp(pn, "product-endoflife()")) { - time_t t = datestr2timestamp(newname); - if (t) - repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE, t); + /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */ + repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE,(evr ? datestr2timestamp(newname) : 0) ); } else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32) { diff --git a/libsolv-0.6.15/ext/repo_autopattern.h b/libsolv-0.7.2/ext/repo_autopattern.h similarity index 100% rename from libsolv-0.6.15/ext/repo_autopattern.h rename to libsolv-0.7.2/ext/repo_autopattern.h diff --git a/libsolv-0.7.2/ext/repo_comps.c b/libsolv-0.7.2/ext/repo_comps.c new file mode 100644 index 0000000..9400e1e --- /dev/null +++ b/libsolv-0.7.2/ext/repo_comps.c @@ -0,0 +1,232 @@ +/* + * repo_comps.c + * + * Parses RedHat comps format + * + * Copyright (c) 2012, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "solv_xmlparser.h" +#define DISABLE_SPLIT +#include "tools_util.h" +#include "repo_comps.h" + +/* + * TODO: + * + * what's the difference between group/category? + * handle "default" and "langonly". + * + * maybe handle REL_COND in solver recommends handling? + */ + +enum state { + STATE_START, + STATE_COMPS, + STATE_GROUP, + STATE_ID, + STATE_NAME, + STATE_DESCRIPTION, + STATE_DISPLAY_ORDER, + STATE_DEFAULT, + STATE_LANGONLY, + STATE_LANG_ONLY, + STATE_USERVISIBLE, + STATE_PACKAGELIST, + STATE_PACKAGEREQ, + STATE_CATEGORY, + STATE_CID, + STATE_CNAME, + STATE_CDESCRIPTION, + STATE_CDISPLAY_ORDER, + STATE_GROUPLIST, + STATE_GROUPID, + NUMSTATES +}; + +static struct solv_xmlparser_element stateswitches[] = { + { STATE_START, "comps", STATE_COMPS, 0 }, + { STATE_COMPS, "group", STATE_GROUP, 0 }, + { STATE_COMPS, "category", STATE_CATEGORY, 0 }, + { STATE_GROUP, "id", STATE_ID, 1 }, + { STATE_GROUP, "name", STATE_NAME, 1 }, + { STATE_GROUP, "description", STATE_DESCRIPTION, 1 }, + { STATE_GROUP, "uservisible", STATE_USERVISIBLE, 1 }, + { STATE_GROUP, "display_order", STATE_DISPLAY_ORDER, 1 }, + { STATE_GROUP, "default", STATE_DEFAULT, 1 }, + { STATE_GROUP, "langonly", STATE_LANGONLY, 1 }, + { STATE_GROUP, "lang_only", STATE_LANG_ONLY, 1 }, + { STATE_GROUP, "packagelist", STATE_PACKAGELIST, 0 }, + { STATE_PACKAGELIST, "packagereq", STATE_PACKAGEREQ, 1 }, + { STATE_CATEGORY, "id", STATE_ID, 1 }, + { STATE_CATEGORY, "name", STATE_NAME, 1 }, + { STATE_CATEGORY, "description", STATE_DESCRIPTION, 1 }, + { STATE_CATEGORY , "grouplist", STATE_GROUPLIST, 0 }, + { STATE_CATEGORY , "display_order", STATE_DISPLAY_ORDER, 1 }, + { STATE_GROUPLIST, "groupid", STATE_GROUPID, 1 }, + { NUMSTATES } +}; + +struct parsedata { + Pool *pool; + Repo *repo; + Repodata *data; + const char *filename; + const char *basename; + + struct solv_xmlparser xmlp; + struct joindata jd; + + const char *tmplang; + Id reqtype; + Id condreq; + + Solvable *solvable; + const char *kind; + Id handle; +}; + + + +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) +{ + struct parsedata *pd = xmlp->userdata; + Pool *pool = pd->pool; + Solvable *s = pd->solvable; + + switch(state) + { + case STATE_GROUP: + case STATE_CATEGORY: + s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); + pd->handle = s - pool->solvables; + pd->kind = state == STATE_GROUP ? "group" : "category"; + break; + + case STATE_NAME: + case STATE_CNAME: + case STATE_DESCRIPTION: + case STATE_CDESCRIPTION: + pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts)); + break; + + case STATE_PACKAGEREQ: + { + const char *type = solv_xmlparser_find_attr("type", atts); + pd->condreq = 0; + pd->reqtype = SOLVABLE_RECOMMENDS; + if (type && !strcmp(type, "conditional")) + { + const char *requires = solv_xmlparser_find_attr("requires", atts); + if (requires && *requires) + pd->condreq = pool_str2id(pool, requires, 1); + } + else if (type && !strcmp(type, "mandatory")) + pd->reqtype = SOLVABLE_REQUIRES; + else if (type && !strcmp(type, "optional")) + pd->reqtype = SOLVABLE_SUGGESTS; + break; + } + + default: + break; + } +} + + +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) +{ + struct parsedata *pd = xmlp->userdata; + Solvable *s = pd->solvable; + Id id; + + switch (state) + { + case STATE_GROUP: + case STATE_CATEGORY: + if (!s->arch) + s->arch = ARCH_NOARCH; + if (!s->evr) + s->evr = ID_EMPTY; + if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0); + pd->solvable = 0; + break; + + case STATE_ID: + s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1); + break; + + case STATE_NAME: + repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content); + break; + + case STATE_DESCRIPTION: + repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content); + break; + + case STATE_PACKAGEREQ: + id = pool_str2id(pd->pool, content, 1); + if (pd->condreq) + id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1); + repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id); + break; + + case STATE_GROUPID: + id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1); + s->requires = repo_addid_dep(pd->repo, s->requires, id, 0); + break; + + case STATE_USERVISIBLE: + repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE); + break; + + case STATE_DISPLAY_ORDER: + repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content); + break; + + default: + break; + } +} + +int +repo_add_comps(Repo *repo, FILE *fp, int flags) +{ + Repodata *data; + struct parsedata pd; + + data = repo_add_repodata(repo, flags); + + memset(&pd, 0, sizeof(pd)); + pd.repo = repo; + pd.pool = repo->pool; + pd.data = data; + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pool_debug(pd.pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); + join_freemem(&pd.jd); + + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +/* EOF */ diff --git a/libsolv-0.6.15/ext/repo_comps.h b/libsolv-0.7.2/ext/repo_comps.h similarity index 100% rename from libsolv-0.6.15/ext/repo_comps.h rename to libsolv-0.7.2/ext/repo_comps.h diff --git a/libsolv-0.6.15/ext/repo_content.c b/libsolv-0.7.2/ext/repo_content.c similarity index 98% rename from libsolv-0.6.15/ext/repo_content.c rename to libsolv-0.7.2/ext/repo_content.c index 0cd1293..f361900 100644 --- a/libsolv-0.6.15/ext/repo_content.c +++ b/libsolv-0.7.2/ext/repo_content.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include @@ -404,7 +402,7 @@ repo_add_content(Repo *repo, FILE *fp, int flags) if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); if (code10) - s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); + repo_rewrite_suse_deps(s, 0); } /* create new solvable */ s = pool_id2solvable(pool, repo_add_solvable(repo)); @@ -519,8 +517,7 @@ repo_add_content(Repo *repo, FILE *fp, int flags) if (s && !s->name) { pool_debug(pool, SOLV_ERROR, "repo_content: 'content' incomplete, no product solvable created!\n"); - repo_free_solvable(repo, s - pool->solvables, 1); - s = 0; + s = solvable_free(s, 1); } if (s) { @@ -538,7 +535,7 @@ repo_add_content(Repo *repo, FILE *fp, int flags) if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); if (code10) - s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); + repo_rewrite_suse_deps(s, 0); /* now for every other arch, clone the product except the architecture */ for (i = 0; i < numotherarchs; ++i) diff --git a/libsolv-0.6.15/ext/repo_content.h b/libsolv-0.7.2/ext/repo_content.h similarity index 100% rename from libsolv-0.6.15/ext/repo_content.h rename to libsolv-0.7.2/ext/repo_content.h diff --git a/libsolv-0.6.15/ext/repo_cudf.c b/libsolv-0.7.2/ext/repo_cudf.c similarity index 96% rename from libsolv-0.6.15/ext/repo_cudf.c rename to libsolv-0.7.2/ext/repo_cudf.c index 00a4f87..64bb86f 100644 --- a/libsolv-0.6.15/ext/repo_cudf.c +++ b/libsolv-0.7.2/ext/repo_cudf.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "pool.h" @@ -225,10 +224,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags) if (!*buf) { if (s && !repo && !isinstalled) - { - repo_free_solvable(repo, s - pool->solvables, 1); - s = 0; - } + s = solvable_free(s, 1); if (s) finishpackage(pool, s, keep, job); s = 0; @@ -324,10 +320,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags) { isinstalled = 1; if (!installedrepo) - { - repo_free_solvable(repo, s - pool->solvables, 1); - s = 0; - } + s = solvable_free(s, 1); else if (s->repo != installedrepo) { copysolvabledata(pool, s, installedrepo); @@ -372,10 +365,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags) } } if (s && !repo && !isinstalled) - { - repo_free_solvable(repo, s - pool->solvables, 1); - s = 0; - } + s = solvable_free(s, 1); if (s) finishpackage(pool, s, keep, job); solv_free(buf); diff --git a/libsolv-0.6.15/ext/repo_cudf.h b/libsolv-0.7.2/ext/repo_cudf.h similarity index 100% rename from libsolv-0.6.15/ext/repo_cudf.h rename to libsolv-0.7.2/ext/repo_cudf.h diff --git a/libsolv-0.7.2/ext/repo_deb.c b/libsolv-0.7.2/ext/repo_deb.c new file mode 100644 index 0000000..0f17fea --- /dev/null +++ b/libsolv-0.7.2/ext/repo_deb.c @@ -0,0 +1,891 @@ +/* + * Copyright (c) 2009, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_ZLIB_COMPRESSION +#include +#endif +#ifdef ENABLE_LZMA_COMPRESSION +#include +#endif +#ifdef ENABLE_ZSTD_COMPRESSION +#include +#endif + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "solver.h" /* for GET_USERINSTALLED_ flags */ +#include "chksum.h" +#include "repo_deb.h" + +#define MAX_CONTROL_SIZE 0x1000000 + +#ifdef ENABLE_ZLIB_COMPRESSION + +static unsigned char * +decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + z_stream strm; + int outl, ret; + unsigned char *bp, *out; + + /* first skip the gz header */ + if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b) + return 0; + if (in[2] != 8 || (in[3] & 0xe0) != 0) + return 0; + bp = in + 4; + bp += 6; /* skip time, xflags and OS code */ + if (in[3] & 0x04) + { + /* skip extra field */ + int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8); + bp += l + 2; + } + if (in[3] & 0x08) /* orig filename */ + while (bp < in + inl && *bp++) + ; + if (in[3] & 0x10) /* file comment */ + while (bp < in + inl && *bp++) + ; + if (in[3] & 0x02) /* header crc */ + bp += 2; + if (bp >= in + inl) + return 0; + inl -= bp - in; + in = bp; + + memset(&strm, 0, sizeof(strm)); + strm.next_in = in; + strm.avail_in = inl; + out = solv_malloc(4096); + strm.next_out = out; + strm.avail_out = 4096; + outl = 0; + ret = inflateInit2(&strm, -MAX_WBITS); + if (ret != Z_OK) + { + free(out); + return 0; + } + for (;;) + { + if (strm.avail_out == 0) + { + outl += 4096; + if (outl >= maxoutl) + { + inflateEnd(&strm); + free(out); + return 0; + } + out = solv_realloc(out, outl + 4096); + strm.next_out = out + outl; + strm.avail_out = 4096; + } + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_END) + break; + if (ret != Z_OK) + { + inflateEnd(&strm); + free(out); + return 0; + } + } + outl += 4096 - strm.avail_out; + inflateEnd(&strm); + *outlp = outl; + return out; +} + +#else + +static unsigned char * +decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + return 0; +} + +#endif /* ENABLE_ZLIB_COMPRESSION */ + +#ifdef ENABLE_LZMA_COMPRESSION + +static unsigned char * +decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + static lzma_stream stream_init = LZMA_STREAM_INIT; + lzma_stream strm; + int outl, ret; + unsigned char *out; + + strm = stream_init; + strm.next_in = in; + strm.avail_in = inl; + out = solv_malloc(4096); + strm.next_out = out; + strm.avail_out = 4096; + outl = 0; + ret = lzma_auto_decoder(&strm, 100 << 20, 0); + if (ret != LZMA_OK) + { + free(out); + return 0; + } + for (;;) + { + if (strm.avail_out == 0) + { + outl += 4096; + if (outl >= maxoutl) + { + lzma_end(&strm); + free(out); + return 0; + } + out = solv_realloc(out, outl + 4096); + strm.next_out = out + outl; + strm.avail_out = 4096; + } + ret = lzma_code(&strm, LZMA_RUN); + if (ret == LZMA_STREAM_END) + break; + if (ret != LZMA_OK) + { + lzma_end(&strm); + free(out); + return 0; + } + } + outl += 4096 - strm.avail_out; + lzma_end(&strm); + *outlp = outl; + return out; +} + +#else + +static unsigned char * +decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + return 0; +} + +#endif /* ENABLE_LZMA_COMPRESSION */ + +#ifdef ENABLE_ZSTD_COMPRESSION + +static unsigned char * +decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + ZSTD_DStream *dstream; + ZSTD_inBuffer inbuf; + ZSTD_outBuffer outbuf; + int ret; + + dstream = ZSTD_createDStream(); + if (!dstream) + return 0; + if (ZSTD_isError(ZSTD_initDStream(dstream))) + { + ZSTD_freeDStream(dstream); + return 0; + } + inbuf.src = in; + inbuf.pos = 0; + inbuf.size = inl; + outbuf.dst = solv_malloc(4096); + outbuf.pos = 0; + outbuf.size = 4096; + for (;;) + { + if (outbuf.pos == outbuf.size) + { + outbuf.size += 4096; + if (outbuf.size >= maxoutl) + { + ret = 1; + break; + } + outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096); + } + ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf); + if (ret == 0 && inbuf.pos == inbuf.size) + break; + if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size)) + { + ret = 1; + break; + } + } + ZSTD_freeDStream(dstream); + if (ret) + { + solv_free(outbuf.dst); + return 0; + } + *outlp = outbuf.pos; + return outbuf.dst; +} + +#else + +static unsigned char * +decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl) +{ + return 0; +} + +#endif /* ENABLE_ZSTD_COMPRESSION */ + +static Id +parseonedep(Pool *pool, char *p) +{ + char *n, *ne, *e, *ee; + Id name, evr; + int flags; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (!*p || *p == '(') + return 0; + n = p; + /* find end of name */ + while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|') + p++; + ne = p; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + evr = 0; + flags = 0; + e = ee = 0; + if (*p == '(') + { + p++; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (*p == '>') + flags |= REL_GT; + else if (*p == '=') + flags |= REL_EQ; + else if (*p == '<') + flags |= REL_LT; + if (flags) + { + p++; + if (*p == '>') + flags |= REL_GT; + else if (*p == '=') + flags |= REL_EQ; + else if (*p == '<') + flags |= REL_LT; + else + p--; + p++; + } + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + e = p; + while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')') + p++; + ee = p; + while (*p && *p != ')') + p++; + if (*p) + p++; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + } + if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4)) + { + /* multiarch annotation */ + name = pool_strn2id(pool, n, ne - n - 4, 1); + name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1); + } + else + name = pool_strn2id(pool, n, ne - n, 1); + if (e) + { + evr = pool_strn2id(pool, e, ee - e, 1); + name = pool_rel2id(pool, name, evr, flags, 1); + } + if (*p == '|') + { + Id id = parseonedep(pool, p + 1); + if (id) + name = pool_rel2id(pool, name, id, REL_OR, 1); + } + return name; +} + +static unsigned int +makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker) +{ + Pool *pool = repo->pool; + char *p; + Id id; + + while ((p = strchr(deps, ',')) != 0) + { + *p = 0; + olddeps = makedeps(repo, deps, olddeps, marker); + *p = ','; + deps = p + 1; + } + id = parseonedep(pool, deps); + if (!id) + return olddeps; + return repo_addid_dep(repo, olddeps, id, marker); +} + + +/* put data from control file into the solvable */ +/* warning: does inplace changes */ +static void +control2solvable(Solvable *s, Repodata *data, char *control) +{ + Repo *repo = s->repo; + Pool *pool = repo->pool; + char *p, *q, *end, *tag; + int x, l; + int havesource = 0; + char checksum[32 * 2 + 1]; + Id checksumtype = 0; + Id newtype; + + p = control; + while (*p) + { + p = strchr(p, '\n'); + if (!p) + break; + if (p[1] == ' ' || p[1] == '\t') + { + char *q; + /* continuation line */ + q = p - 1; + while (q >= control && *q == ' ' && *q == '\t') + q--; + l = q + 1 - control; + if (l) + memmove(p + 1 - l, control, l); + control = p + 1 - l; + p[1] = '\n'; + p += 2; + continue; + } + end = p - 1; + if (*p) + *p++ = 0; + /* strip trailing space */ + while (end >= control && (*end == ' ' || *end == '\t')) + *end-- = 0; + tag = control; + control = p; + q = strchr(tag, ':'); + if (!q || q - tag < 4) + continue; + *q++ = 0; + while (*q == ' ' || *q == '\t') + q++; + x = '@' + (tag[0] & 0x1f); + x = (x << 8) + '@' + (tag[1] & 0x1f); + switch(x) + { + case 'A' << 8 | 'R': + if (!strcasecmp(tag, "architecture")) + s->arch = pool_str2id(pool, q, 1); + break; + case 'B' << 8 | 'R': + if (!strcasecmp(tag, "breaks")) + s->conflicts = makedeps(repo, q, s->conflicts, 0); + break; + case 'C' << 8 | 'O': + if (!strcasecmp(tag, "conflicts")) + s->conflicts = makedeps(repo, q, s->conflicts, 0); + break; + case 'D' << 8 | 'E': + if (!strcasecmp(tag, "depends")) + s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER); + else if (!strcasecmp(tag, "description")) + { + char *ld = strchr(q, '\n'); + if (ld) + { + *ld++ = 0; + repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld); + } + else + repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q); + repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q); + } + break; + case 'E' << 8 | 'N': + if (!strcasecmp(tag, "enhances")) + s->enhances = makedeps(repo, q, s->enhances, 0); + break; + case 'F' << 8 | 'I': + if (!strcasecmp(tag, "filename")) + repodata_set_location(data, s - pool->solvables, 0, 0, q); + break; + case 'H' << 8 | 'O': + if (!strcasecmp(tag, "homepage")) + repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q); + break; + case 'I' << 8 | 'N': + if (!strcasecmp(tag, "installed-size")) + repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10); + break; + case 'M' << 8 | 'D': + if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2) + { + strcpy(checksum, q); + checksumtype = REPOKEY_TYPE_MD5; + } + break; + case 'P' << 8 | 'A': + if (!strcasecmp(tag, "package")) + s->name = pool_str2id(pool, q, 1); + break; + case 'P' << 8 | 'R': + if (!strcasecmp(tag, "pre-depends")) + s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER); + else if (!strcasecmp(tag, "provides")) + s->provides = makedeps(repo, q, s->provides, 0); + break; + case 'R' << 8 | 'E': + if (!strcasecmp(tag, "replaces")) + s->obsoletes = makedeps(repo, q, s->obsoletes, 0); + else if (!strcasecmp(tag, "recommends")) + s->recommends = makedeps(repo, q, s->recommends, 0); + break; + case 'S' << 8 | 'H': + newtype = solv_chksum_str2type(tag); + if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q)) + break; + if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256) + { + strcpy(checksum, q); + checksumtype = newtype; + } + break; + case 'S' << 8 | 'O': + if (!strcasecmp(tag, "source")) + { + char *q2; + /* ignore version for now */ + for (q2 = q; *q2; q2++) + if (*q2 == ' ' || *q2 == '\t') + { + *q2 = 0; + break; + } + if (s->name && !strcmp(q, pool_id2str(pool, s->name))) + repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME); + else + repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1)); + havesource = 1; + } + break; + case 'S' << 8 | 'T': + if (!strcasecmp(tag, "status")) + repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q); + break; + case 'S' << 8 | 'U': + if (!strcasecmp(tag, "suggests")) + s->suggests = makedeps(repo, q, s->suggests, 0); + break; + case 'V' << 8 | 'E': + if (!strcasecmp(tag, "version")) + s->evr = pool_str2id(pool, q, 1); + break; + } + } + if (checksumtype) + repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum); + if (!s->arch) + s->arch = ARCH_ALL; + if (!s->evr) + s->evr = ID_EMPTY; + if (s->name) + s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); + if (s->name && !havesource) + repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME); + if (s->obsoletes) + { + /* obsoletes only count when the packages also conflict */ + /* XXX: should not transcode here */ + int i, j, k; + Id d, cid; + for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++) + { + if (!s->conflicts) + continue; + for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++) + { + if (repo->idarraydata[k] == cid) + break; + if (ISRELDEP(cid)) + { + Reldep *rd = GETRELDEP(pool, cid); + if (rd->flags < 8 && rd->name == d) + break; /* specialize obsoletes */ + } + } + if (cid) + repo->idarraydata[j++] = cid; + } + repo->idarraydata[j] = 0; + if (j == s->obsoletes) + s->obsoletes = 0; + } +} + +int +repo_add_debpackages(Repo *repo, FILE *fp, int flags) +{ + Pool *pool = repo->pool; + Repodata *data; + char *buf, *p; + int bufl, l, ll; + Solvable *s; + + data = repo_add_repodata(repo, flags); + buf = solv_malloc(4096); + bufl = 4096; + l = 0; + buf[l] = 0; + p = buf; + for (;;) + { + if (!(p = strchr(p, '\n'))) + { + int l3; + while (l + 1024 >= bufl) + { + buf = solv_realloc(buf, bufl + 4096); + bufl += 4096; + } + p = buf + l; + ll = fread(p, 1, bufl - l - 1, fp); + if (ll <= 0) + break; + p[ll] = 0; + while ((l3 = strlen(p)) < ll) + p[l3] = '\n'; + l += ll; + if (p != buf) + p--; + continue; + } + p++; + if (*p != '\n') + continue; + *p = 0; + ll = p - buf + 1; + s = pool_id2solvable(pool, repo_add_solvable(repo)); + control2solvable(s, data, buf); + if (!s->name) + s = solvable_free(s, 1); + if (l > ll) + memmove(buf, p + 1, l - ll); + l -= ll; + p = buf; + buf[l] = 0; + } + if (l) + { + s = pool_id2solvable(pool, repo_add_solvable(repo)); + control2solvable(s, data, buf); + if (!s->name) + s = solvable_free(s, 1); + } + solv_free(buf); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +int +repo_add_debdb(Repo *repo, int flags) +{ + FILE *fp; + const char *path = "/var/lib/dpkg/status"; + if (flags & REPO_USE_ROOTDIR) + path = pool_prepend_rootdir_tmp(repo->pool, path); + if ((fp = fopen(path, "r")) == 0) + return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno)); + repo_add_debpackages(repo, fp, flags); + fclose(fp); + return 0; +} + +#define CONTROL_COMP_NONE 0 +#define CONTROL_COMP_GZIP 1 +#define CONTROL_COMP_XZ 2 +#define CONTROL_COMP_ZSTD 3 + +Id +repo_add_deb(Repo *repo, const char *deb, int flags) +{ + Pool *pool = repo->pool; + Repodata *data; + unsigned char buf[4096], *bp; + int l, l2, vlen, clen, ctarlen; + int control_comp; + unsigned char *ctgz; + unsigned char pkgid[16]; + unsigned char *ctar; + int gotpkgid; + FILE *fp; + Solvable *s; + struct stat stb; + + data = repo_add_repodata(repo, flags); + if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0) + { + pool_error(pool, -1, "%s: %s", deb, strerror(errno)); + return 0; + } + if (fstat(fileno(fp), &stb)) + { + pool_error(pool, -1, "fstat: %s", strerror(errno)); + fclose(fp); + return 0; + } + l = fread(buf, 1, sizeof(buf), fp); + if (l < 8 + 60 || (strncmp((char *)buf, "!\ndebian-binary ", 8 + 16) != 0 && strncmp((char *)buf, "!\ndebian-binary/ ", 8 + 16) != 0)) + { + pool_error(pool, -1, "%s: not a deb package", deb); + fclose(fp); + return 0; + } + vlen = atoi((char *)buf + 8 + 48); + if (vlen < 0 || vlen > l) + { + pool_error(pool, -1, "%s: not a deb package", deb); + fclose(fp); + return 0; + } + vlen += vlen & 1; + if (l < 8 + 60 + vlen + 60) + { + pool_error(pool, -1, "%s: unhandled deb package", deb); + fclose(fp); + return 0; + } + control_comp = 0; + if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16)) + control_comp = CONTROL_COMP_GZIP; + else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16)) + control_comp = CONTROL_COMP_XZ; + else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16)) + control_comp = CONTROL_COMP_ZSTD; + else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/ ", 16)) + control_comp = CONTROL_COMP_NONE; + else + { + pool_error(pool, -1, "%s: control.tar is not second entry", deb); + fclose(fp); + return 0; + } + /* dpkg has no actual maximum size for the control.tar member, so this + * just keeps from allocating arbitrarily large amounts of memory. + */ + clen = atoi((char *)buf + 8 + 60 + vlen + 48); + if (clen <= 0 || clen >= MAX_CONTROL_SIZE) + { + pool_error(pool, -1, "%s: control.tar has illegal size", deb); + fclose(fp); + return 0; + } + ctgz = solv_calloc(1, clen + 4); + bp = buf + 8 + 60 + vlen + 60; + l -= 8 + 60 + vlen + 60; + if (l > clen) + l = clen; + if (l) + memcpy(ctgz, bp, l); + if (l < clen) + { + if (fread(ctgz + l, clen - l, 1, fp) != 1) + { + pool_error(pool, -1, "%s: unexpected EOF", deb); + solv_free(ctgz); + fclose(fp); + return 0; + } + } + fclose(fp); + gotpkgid = 0; + if (flags & DEBS_ADD_WITH_PKGID) + { + Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5); + solv_chksum_add(chk, ctgz, clen); + solv_chksum_free(chk, pkgid); + gotpkgid = 1; + } + ctar = 0; + if (control_comp == CONTROL_COMP_GZIP) + ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE); + else if (control_comp == CONTROL_COMP_XZ) + ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE); + else if (control_comp == CONTROL_COMP_ZSTD) + ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE); + else + { + ctarlen = clen; + ctar = solv_memdup(ctgz, clen); + } + solv_free(ctgz); + if (!ctar) + { + pool_error(pool, -1, "%s: control.tar decompression error", deb); + return 0; + } + bp = ctar; + l = ctarlen; + l2 = 0; + while (l > 512) + { + int j; + l2 = 0; + for (j = 124; j < 124 + 12; j++) + if (bp[j] >= '0' && bp[j] <= '7') + l2 = l2 * 8 + (bp[j] - '0'); + if (l2 < 0 || l2 > l) + { + l2 = 0; + break; + } + bp[124] = 0; + if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control")) + break; + l2 = 512 + ((l2 + 511) & ~511); + l -= l2; + bp += l2; + } + if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0) + { + pool_error(pool, -1, "%s: control.tar contains no control file", deb); + free(ctar); + return 0; + } + memmove(ctar, bp + 512, l2); + ctar = solv_realloc(ctar, l2 + 1); + ctar[l2] = 0; + s = pool_id2solvable(pool, repo_add_solvable(repo)); + control2solvable(s, data, (char *)ctar); + if (!(flags & REPO_NO_LOCATION)) + repodata_set_location(data, s - pool->solvables, 0, 0, deb); + if (S_ISREG(stb.st_mode)) + repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size); + if (gotpkgid) + repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid); + solv_free(ctar); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return s - pool->solvables; +} + +void +pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags) +{ + Id name = 0, arch = 0; + int autoinstalled = -1; + char *buf, *bp; + int x, l, bufl, eof = 0; + Id p, pp; + + queue_empty(q); + buf = solv_malloc(4096); + bufl = 4096; + l = 0; + while (!eof) + { + while (bufl - l < 1024) + { + bufl += 4096; + if (bufl > 1024 * 64) + break; /* hmm? */ + buf = solv_realloc(buf, bufl); + } + if (!fgets(buf + l, bufl - l, fp)) + { + eof = 1; + buf[l] = '\n'; + buf[l + 1] = 0; + } + l = strlen(buf); + if (l && buf[l - 1] == '\n') + buf[--l] = 0; + if (!*buf || eof) + { + l = 0; + if (name && autoinstalled > 0) + { + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + queue_push2(q, name, arch); + else if ((flags & GET_USERINSTALLED_NAMES) != 0) + queue_push(q, name); + else + { + FOR_PROVIDES(p, pp, name) + { + Solvable *s = pool->solvables + p; + if (s->name != name) + continue; + if (arch && s->arch != arch) + continue; + queue_push(q, p); + } + } + } + name = arch = 0; + autoinstalled = -1; + continue; + } + /* strip trailing space */ + while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t')) + buf[--l] = 0; + l = 0; + + bp = strchr(buf, ':'); + if (!bp || bp - buf < 4) + continue; + *bp++ = 0; + while (*bp == ' ' || *bp == '\t') + bp++; + x = '@' + (buf[0] & 0x1f); + x = (x << 8) + '@' + (buf[1] & 0x1f); + switch(x) + { + case 'P' << 8 | 'A': + if (!strcasecmp(buf, "package")) + name = pool_str2id(pool, bp, 1); + break; + case 'A' << 8 | 'R': + if (!strcasecmp(buf, "architecture")) + arch = pool_str2id(pool, bp, 1); + break; + case 'A' << 8 | 'U': + if (!strcasecmp(buf, "auto-installed")) + autoinstalled = atoi(bp); + break; + default: + break; + } + } +} + diff --git a/libsolv-0.6.15/ext/repo_deb.c b/libsolv-0.7.2/ext/repo_deb.c.orig old mode 100755 new mode 100644 similarity index 99% rename from libsolv-0.6.15/ext/repo_deb.c rename to libsolv-0.7.2/ext/repo_deb.c.orig index 6af7f10..5dd79f4 --- a/libsolv-0.6.15/ext/repo_deb.c +++ b/libsolv-0.7.2/ext/repo_deb.c.orig @@ -499,7 +499,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags) s = pool_id2solvable(pool, repo_add_solvable(repo)); control2solvable(s, data, buf); if (!s->name) - repo_free_solvable(repo, s - pool->solvables, 1); + s = solvable_free(s, 1); if (l > ll) memmove(buf, p + 1, l - ll); l -= ll; @@ -511,7 +511,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags) s = pool_id2solvable(pool, repo_add_solvable(repo)); control2solvable(s, data, buf); if (!s->name) - repo_free_solvable(repo, s - pool->solvables, 1); + s = solvable_free(s, 1); } solv_free(buf); if (!(flags & REPO_NO_INTERNALIZE)) diff --git a/libsolv-0.6.15/ext/repo_deb.h b/libsolv-0.7.2/ext/repo_deb.h similarity index 100% rename from libsolv-0.6.15/ext/repo_deb.h rename to libsolv-0.7.2/ext/repo_deb.h diff --git a/libsolv-0.6.15/ext/repo_deltainfoxml.c b/libsolv-0.7.2/ext/repo_deltainfoxml.c similarity index 64% rename from libsolv-0.6.15/ext/repo_deltainfoxml.c rename to libsolv-0.7.2/ext/repo_deltainfoxml.c index 06df1a3..ad315da 100644 --- a/libsolv-0.6.15/ext/repo_deltainfoxml.c +++ b/libsolv-0.7.2/ext/repo_deltainfoxml.c @@ -5,20 +5,16 @@ * for further information */ -#define DO_ARRAY 1 - #define _GNU_SOURCE #include -#include -#include #include #include #include -#include #include "pool.h" #include "repo.h" #include "chksum.h" +#include "solv_xmlparser.h" #include "repo_deltainfoxml.h" /* @@ -52,15 +48,7 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { /* compatibility with old yum-presto */ { STATE_START, "prestodelta", STATE_START, 0 }, { STATE_START, "deltainfo", STATE_START, 0 }, @@ -93,19 +81,10 @@ struct deltarpm { struct parsedata { int ret; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Pool *pool; Repo *repo; Repodata *data; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; struct deltarpm delta; Id newpkgevr; Id newpkgname; @@ -113,22 +92,9 @@ struct parsedata { Id *handles; int nhandles; -}; -/* - * find attribute - */ - -static const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} + struct solv_xmlparser xmlp; +}; /* @@ -139,7 +105,7 @@ static Id makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) { const char *e, *v, *r, *v2; - char *c; + char *c, *space; int l; e = v = r = 0; @@ -174,12 +140,7 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) l += strlen(v); if (r) l += strlen(r) + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content; + c = space = solv_xmlparser_contentspace(&pd->xmlp, l); if (e) { strcpy(c, e); @@ -198,59 +159,28 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) c += strlen(c); } *c = 0; - if (!*pd->content) + if (!*space) return 0; #if 0 - fprintf(stderr, "evr: %s\n", pd->content); + fprintf(stderr, "evr: %s\n", space); #endif - return pool_str2id(pool, pd->content, 1); + return pool_str2id(pool, space, 1); } -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; - struct stateswitch *sw; const char *str; -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) + switch(state) { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) - return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - - switch(pd->state) - { - case STATE_START: - break; case STATE_NEWPACKAGE: - if ((str = find_attr("name", atts)) != 0) + if ((str = solv_xmlparser_find_attr("name", atts)) != 0) pd->newpkgname = pool_str2id(pool, str, 1); pd->newpkgevr = makeevr_atts(pool, pd, atts); - if ((str = find_attr("arch", atts)) != 0) + if ((str = solv_xmlparser_find_attr("arch", atts)) != 0) pd->newpkgarch = pool_str2id(pool, str, 1); break; @@ -259,62 +189,44 @@ startElement(void *userData, const char *name, const char **atts) pd->delta.bevr = solv_extend(pd->delta.bevr, pd->delta.nbevr, 1, sizeof(Id), 7); pd->delta.bevr[pd->delta.nbevr++] = makeevr_atts(pool, pd, atts); break; + case STATE_FILENAME: - if ((str = find_attr("xml:base", atts))) + if ((str = solv_xmlparser_find_attr("xml:base", atts))) pd->delta.locbase = solv_strdup(str); break; + case STATE_LOCATION: - pd->delta.location = solv_strdup(find_attr("href", atts)); - if ((str = find_attr("xml:base", atts))) + pd->delta.location = solv_strdup(solv_xmlparser_find_attr("href", atts)); + if ((str = solv_xmlparser_find_attr("xml:base", atts))) pd->delta.locbase = solv_strdup(str); break; - case STATE_SIZE: - break; + case STATE_CHECKSUM: pd->delta.filechecksum = 0; pd->delta.filechecksumtype = REPOKEY_TYPE_SHA1; - if ((str = find_attr("type", atts)) != 0) + if ((str = solv_xmlparser_find_attr("type", atts)) != 0) { pd->delta.filechecksumtype = solv_chksum_str2type(str); if (!pd->delta.filechecksumtype) pool_debug(pool, SOLV_ERROR, "unknown checksum type: '%s'\n", str); } break; - case STATE_SEQUENCE: - break; + default: break; } } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; const char *str; -#if 0 - fprintf(stderr, "end: %s\n", name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - switch (pd->state) + switch (state) { - case STATE_START: - break; - case STATE_NEWPACKAGE: - break; case STATE_DELTA: { /* read all data for a deltarpm. commit into attributes */ @@ -356,16 +268,16 @@ endElement(void *userData, const char *name) pd->delta.locbase = solv_free(pd->delta.locbase); break; case STATE_FILENAME: - pd->delta.location = solv_strdup(pd->content); + pd->delta.location = solv_strdup(content); break; case STATE_CHECKSUM: - pd->delta.filechecksum = solv_strdup(pd->content); + pd->delta.filechecksum = solv_strdup(content); break; case STATE_SIZE: - pd->delta.downloadsize = strtoull(pd->content, 0, 10); + pd->delta.downloadsize = strtoull(content, 0, 10); break; case STATE_SEQUENCE: - if ((str = pd->content)) + if ((str = content) != 0) { const char *s1, *s2; s1 = strrchr(str, '-'); @@ -392,80 +304,26 @@ endElement(void *userData, const char *name) default: break; } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; -} - - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; } -#define BUFF_SIZE 8192 - int repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags) { Pool *pool = repo->pool; - struct parsedata pd; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; Repodata *data; - XML_Parser parser; + struct parsedata pd; + int i; data = repo_add_repodata(repo, flags); memset(&pd, 0, sizeof(pd)); - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } pd.pool = pool; pd.repo = repo; pd.data = data; - - pd.content = solv_malloc(256); - pd.acontent = 256; - pd.lcontent = 0; - - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); - solv_free(pd.content); + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pd.ret = pool_error(pd.pool, -1, "repo_deltainfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); /* now commit all handles */ if (!pd.ret) diff --git a/libsolv-0.6.15/ext/repo_deltainfoxml.h b/libsolv-0.7.2/ext/repo_deltainfoxml.h similarity index 100% rename from libsolv-0.6.15/ext/repo_deltainfoxml.h rename to libsolv-0.7.2/ext/repo_deltainfoxml.h diff --git a/libsolv-0.6.15/ext/repo_haiku.cpp b/libsolv-0.7.2/ext/repo_haiku.cpp similarity index 100% rename from libsolv-0.6.15/ext/repo_haiku.cpp rename to libsolv-0.7.2/ext/repo_haiku.cpp diff --git a/libsolv-0.6.15/ext/repo_haiku.h b/libsolv-0.7.2/ext/repo_haiku.h similarity index 100% rename from libsolv-0.6.15/ext/repo_haiku.h rename to libsolv-0.7.2/ext/repo_haiku.h diff --git a/libsolv-0.6.15/ext/repo_helix.c b/libsolv-0.7.2/ext/repo_helix.c similarity index 71% rename from libsolv-0.6.15/ext/repo_helix.c rename to libsolv-0.7.2/ext/repo_helix.c index f495be7..37359bb 100644 --- a/libsolv-0.6.15/ext/repo_helix.c +++ b/libsolv-0.7.2/ext/repo_helix.c @@ -21,13 +21,12 @@ */ #include -#include -#include #include #include #include -#include +#include "queue.h" +#include "solv_xmlparser.h" #include "repo_helix.h" #include "evr.h" @@ -75,22 +74,10 @@ enum state { STATE_PATCH, STATE_PRODUCT, - STATE_PEPOCH, - STATE_PVERSION, - STATE_PRELEASE, - STATE_PARCH, - NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { { STATE_START, "channel", STATE_CHANNEL, 0 }, { STATE_CHANNEL, "subchannel", STATE_SUBCHANNEL, 0 }, { STATE_SUBCHANNEL, "package", STATE_PACKAGE, 0 }, @@ -104,10 +91,10 @@ static struct stateswitch stateswitches[] = { { STATE_PACKAGE, "name", STATE_NAME, 1 }, { STATE_PACKAGE, "vendor", STATE_VENDOR, 1 }, { STATE_PACKAGE, "buildtime", STATE_BUILDTIME, 1 }, - { STATE_PACKAGE, "epoch", STATE_PEPOCH, 1 }, - { STATE_PACKAGE, "version", STATE_PVERSION, 1 }, - { STATE_PACKAGE, "release", STATE_PRELEASE, 1 }, - { STATE_PACKAGE, "arch", STATE_PARCH, 1 }, + { STATE_PACKAGE, "epoch", STATE_EPOCH, 1 }, + { STATE_PACKAGE, "version", STATE_VERSION, 1 }, + { STATE_PACKAGE, "release", STATE_RELEASE, 1 }, + { STATE_PACKAGE, "arch", STATE_ARCH, 1 }, { STATE_PACKAGE, "history", STATE_HISTORY, 0 }, { STATE_PACKAGE, "provides", STATE_PROVIDES, 0 }, { STATE_PACKAGE, "requires", STATE_REQUIRES, 0 }, @@ -119,6 +106,7 @@ static struct stateswitch stateswitches[] = { { STATE_PACKAGE, "suggests", STATE_SUGGESTS, 0 }, { STATE_PACKAGE, "enhances", STATE_ENHANCES, 0 }, { STATE_PACKAGE, "freshens", STATE_FRESHENS, 0 }, + { STATE_PACKAGE, "deps", STATE_PACKAGE, 0 }, /* ignore deps element */ { STATE_HISTORY, "update", STATE_UPDATE, 0 }, { STATE_UPDATE, "epoch", STATE_EPOCH, 1 }, @@ -144,17 +132,8 @@ static struct stateswitch stateswitches[] = { * parser data */ -typedef struct _parsedata { +struct parsedata { int ret; - /* XML parser data */ - int depth; - enum state state; /* current state */ - int statedepth; - char *content; /* buffer for content of node */ - int lcontent; /* actual length of current content */ - int acontent; /* actual buffer size */ - int docontent; /* handle content */ - /* repo data */ Pool *pool; /* current pool */ Repo *repo; /* current repo */ @@ -163,6 +142,7 @@ typedef struct _parsedata { Offset freshens; /* current freshens vector */ /* package data */ + int srcpackage; /* is srcpackage element */ int epoch; /* epoch (as offset into evrspace) */ int version; /* version (as offset into evrspace) */ int release; /* release (as offset into evrspace) */ @@ -171,9 +151,8 @@ typedef struct _parsedata { int levrspace; /* actual evr length */ char *kind; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; -} Parsedata; + struct solv_xmlparser xmlp; +}; /*------------------------------------------------------------------*/ @@ -182,9 +161,9 @@ typedef struct _parsedata { /* create Id from epoch:version-release */ static Id -evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r) +evr2id(Pool *pool, struct parsedata *pd, const char *e, const char *v, const char *r) { - char *c; + char *c, *space; int l; /* treat explitcit 0 as NULL */ @@ -211,15 +190,10 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r) if (r) l += strlen(r) + 1; /* -r */ - /* extend content if not sufficient */ - if (l > pd->acontent) - { - pd->content = (char *)realloc(pd->content, l + 256); - pd->acontent = l + 256; - } + /* get content space */ + c = space = solv_xmlparser_contentspace(&pd->xmlp, l); - /* copy e-v-r to content */ - c = pd->content; + /* copy e-v-r */ if (e) { strcpy(c, e); @@ -239,13 +213,13 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r) } *c = 0; /* if nothing inserted, return Id 0 */ - if (!*pd->content) - return ID_NULL; + if (!*space) + return 0; #if 0 - fprintf(stderr, "evr: %s\n", pd->content); + fprintf(stderr, "evr: %s\n", space); #endif /* intern and create */ - return pool_str2id(pool, pd->content, 1); + return pool_str2id(pool, space, 1); } @@ -255,7 +229,7 @@ evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r) * odd index is value */ static Id -evr_atts2id(Pool *pool, Parsedata *pd, const char **atts) +evr_atts2id(Pool *pool, struct parsedata *pd, const char **atts) { const char *e, *v, *r; e = v = r = 0; @@ -312,7 +286,7 @@ static struct flagtab flagtab[] = { */ static unsigned int -adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id marker) +adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, Id marker) { Id id, name; const char *n, *f, *k; @@ -342,13 +316,9 @@ adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id ma if (k) /* if kind!=package, intern : */ { int l = strlen(k) + 1 + strlen(n) + 1; - if (l > pd->acontent) /* extend buffer if needed */ - { - pd->content = (char *)realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - sprintf(pd->content, "%s:%s", k, n); - name = pool_str2id(pool, pd->content, 1); + char *space = solv_xmlparser_contentspace(&pd->xmlp, l); + sprintf(space, "%s:%s", k, n); + name = pool_str2id(pool, space, 1); } else { @@ -382,76 +352,30 @@ adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id ma /*----------------------------------------------------------------*/ -/* - * XML callback - * - * - */ - -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - Parsedata *pd = (Parsedata *)userData; - struct stateswitch *sw; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - /* ignore deps element */ - if (pd->state == STATE_PACKAGE && !strcmp(name, "deps")) - return; - - pd->depth++; - - /* find node name in stateswitch */ - if (!pd->swtab[pd->state]) - return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) - { - if (!strcmp(sw->ename, name)) - break; - } - - /* check if we're at the right level */ - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s\n", name); -#endif - return; - } - - /* set new state */ - pd->state = sw->to; - - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - - /* start with empty content */ - /* (will collect data until end element) */ - pd->lcontent = 0; - *pd->content = 0; - - switch (pd->state) + switch (state) { case STATE_NAME: if (pd->kind) /* if kind is set (non package) */ { - strcpy(pd->content, pd->kind); - pd->lcontent = strlen(pd->content); - pd->content[pd->lcontent++] = ':'; /* prefix name with ':' */ - pd->content[pd->lcontent] = 0; + strcpy(xmlp->content, pd->kind); + xmlp->lcontent = strlen(xmlp->content); + xmlp->content[xmlp->lcontent++] = ':'; /* prefix name with ':' */ + xmlp->content[xmlp->lcontent] = 0; } break; case STATE_PACKAGE: /* solvable name */ pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); + pd->srcpackage = 0; + pd->kind = NULL; /* default is (src)package */ if (!strcmp(name, "selection")) pd->kind = "selection"; else if (!strcmp(name, "pattern")) @@ -464,8 +388,8 @@ startElement(void *userData, const char *name, const char **atts) pd->kind = "patch"; else if (!strcmp(name, "application")) pd->kind = "application"; - else - pd->kind = NULL; /* default is package */ + else if (!strcmp(name, "srcpackage")) + pd->srcpackage = 1; pd->levrspace = 1; pd->epoch = 0; pd->version = 0; @@ -542,7 +466,8 @@ startElement(void *userData, const char *name, const char **atts) } } -static const char *findKernelFlavor(Parsedata *pd, Solvable *s) +static const char * +findKernelFlavor(struct parsedata *pd, Solvable *s) { Pool *pool = pd->pool; Id pid, *pidp; @@ -589,41 +514,21 @@ static const char *findKernelFlavor(Parsedata *pd, Solvable *s) } -/* - * XML callback - * - * - * create Solvable from collected data - */ - -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - Parsedata *pd = (Parsedata *)userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; Id evr; unsigned int t = 0; const char *flavor; - if (pd->depth != pd->statedepth) - { - pd->depth--; - /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */ - return; - } - - /* ignore deps element */ - if (pd->state == STATE_PACKAGE && !strcmp(name, "deps")) - return; - - pd->depth--; - pd->statedepth--; - switch (pd->state) + switch (state) { case STATE_PACKAGE: /* package complete */ - if (name[0] == 's' && name[1] == 'r' && name[2] == 'c' && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + if (pd->srcpackage && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->arch = ARCH_SRC; if (!s->arch) /* default to "noarch" */ s->arch = ARCH_NOARCH; @@ -636,8 +541,7 @@ endElement(void *userData, const char *name) /* ensure self-provides */ if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->supplements = repo_fix_supplements(pd->repo, s->provides, s->supplements, pd->freshens); - s->conflicts = repo_fix_conflicts(pd->repo, s->conflicts); + repo_rewrite_suse_deps(s, pd->freshens); pd->freshens = 0; /* see bugzilla bnc#190163 */ @@ -721,13 +625,13 @@ endElement(void *userData, const char *name) } break; case STATE_NAME: - s->name = pool_str2id(pool, pd->content, 1); + s->name = pool_str2id(pool, content, 1); break; case STATE_VENDOR: - s->vendor = pool_str2id(pool, pd->content, 1); + s->vendor = pool_str2id(pool, content, 1); break; case STATE_BUILDTIME: - t = atoi (pd->content); + t = atoi(content); if (t) repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t); break; @@ -747,73 +651,31 @@ endElement(void *userData, const char *name) case STATE_EPOCH: case STATE_VERSION: case STATE_RELEASE: - case STATE_PEPOCH: - case STATE_PVERSION: - case STATE_PRELEASE: /* ensure buffer space */ - if (pd->lcontent + 1 + pd->levrspace > pd->aevrspace) + if (xmlp->lcontent + 1 + pd->levrspace > pd->aevrspace) { - pd->evrspace = (char *)realloc(pd->evrspace, pd->lcontent + 1 + pd->levrspace + 256); - pd->aevrspace = pd->lcontent + 1 + pd->levrspace + 256; + pd->aevrspace = xmlp->lcontent + 1 + pd->levrspace + 256; + pd->evrspace = (char *)realloc(pd->evrspace, pd->aevrspace); } - memcpy(pd->evrspace + pd->levrspace, pd->content, pd->lcontent + 1); - if (pd->state == STATE_EPOCH || pd->state == STATE_PEPOCH) + memcpy(pd->evrspace + pd->levrspace, xmlp->content, xmlp->lcontent + 1); + if (state == STATE_EPOCH) pd->epoch = pd->levrspace; - else if (pd->state == STATE_VERSION || pd->state == STATE_PVERSION) + else if (state == STATE_VERSION) pd->version = pd->levrspace; else pd->release = pd->levrspace; - pd->levrspace += pd->lcontent + 1; + pd->levrspace += xmlp->lcontent + 1; break; case STATE_ARCH: - case STATE_PARCH: - s->arch = pool_str2id(pool, pd->content, 1); + s->arch = pool_str2id(pool, content, 1); break; default: break; } - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - /* printf("back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */ -} - - -/* - * XML callback - * character data - * - */ - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - Parsedata *pd = (Parsedata *)userData; - int l; - char *c; - - /* check if current nodes content is interesting */ - if (!pd->docontent) - return; - - /* adapt content buffer */ - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = (char *)realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - /* append new content to buffer */ - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; } /*-------------------------------------------------------------------*/ -#define BUFF_SIZE 8192 - /* * read 'helix' type xml from fp * add packages to pool/repo @@ -824,60 +686,29 @@ int repo_add_helix(Repo *repo, FILE *fp, int flags) { Pool *pool = repo->pool; - Parsedata pd; + struct parsedata pd; Repodata *data; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; unsigned int now; - XML_Parser parser; now = solv_timems(0); data = repo_add_repodata(repo, flags); /* prepare parsedata */ memset(&pd, 0, sizeof(pd)); - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } - pd.pool = pool; pd.repo = repo; - - pd.content = (char *)malloc(256); /* must hold all solvable kinds! */ - pd.acontent = 256; - pd.lcontent = 0; - - pd.evrspace = (char *)malloc(256); - pd.aevrspace= 256; - pd.levrspace = 1; pd.data = data; - /* set up XML parser */ + pd.evrspace = (char *)solv_malloc(256); + pd.aevrspace = 256; + pd.levrspace = 1; - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); /* make parserdata available to XML callbacks */ - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pd.ret = pool_error(pd.pool, -1, "repo_helix: %s at line %u", pd.xmlp.errstr, pd.xmlp.line); + solv_xmlparser_free(&pd.xmlp); - /* read/parse XML file */ - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pd.ret = pool_error(pool, -1, "%s at line %u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); - free(pd.content); - free(pd.evrspace); + solv_free(pd.evrspace); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); diff --git a/libsolv-0.6.15/ext/repo_helix.h b/libsolv-0.7.2/ext/repo_helix.h similarity index 100% rename from libsolv-0.6.15/ext/repo_helix.h rename to libsolv-0.7.2/ext/repo_helix.h diff --git a/libsolv-0.6.15/ext/repo_mdk.c b/libsolv-0.7.2/ext/repo_mdk.c similarity index 75% rename from libsolv-0.6.15/ext/repo_mdk.c rename to libsolv-0.7.2/ext/repo_mdk.c index 345d416..4d3e102 100644 --- a/libsolv-0.6.15/ext/repo_mdk.c +++ b/libsolv-0.7.2/ext/repo_mdk.c @@ -11,12 +11,12 @@ #include #include #include -#include #include "pool.h" #include "repo.h" #include "util.h" #include "chksum.h" +#include "solv_xmlparser.h" #include "repo_mdk.h" static Offset @@ -230,7 +230,7 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags) if (s) { pool_debug(pool, SOLV_ERROR, "unclosed package at EOF\n"); - repo_free_solvable(s->repo, s - pool->solvables, 1); + s = solvable_free(s, 1); } solv_free(buf); if (!(flags & REPO_NO_INTERNALIZE)) @@ -246,15 +246,7 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* must be sorted by first column */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { { STATE_START, "media_info", STATE_MEDIA_INFO, 0 }, { STATE_MEDIA_INFO, "info", STATE_INFO, 1 }, { STATE_MEDIA_INFO, "files", STATE_FILES, 1 }, @@ -265,31 +257,12 @@ struct parsedata { Pool *pool; Repo *repo; Repodata *data; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; Solvable *solvable; Hashtable joinhash; Hashval joinhashmask; + struct solv_xmlparser xmlp; }; -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} - static Hashtable joinhash_init(Repo *repo, Hashval *hmp) { @@ -380,56 +353,37 @@ joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn, const char return 0; } -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; - struct stateswitch *sw; - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - pd->depth++; - if (!pd->swtab[pd->state]) - return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) - if (!strcmp(sw->ename, name)) - break; - if (sw->from != pd->state) - return; - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - switch (pd->state) + switch (state) { case STATE_INFO: { - const char *fn = find_attr("fn", atts); - const char *distepoch = find_attr("distepoch", atts); + const char *fn = solv_xmlparser_find_attr("fn", atts); + const char *distepoch = solv_xmlparser_find_attr("distepoch", atts); const char *str; pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch); if (!pd->solvable) break; - str = find_attr("url", atts); + str = solv_xmlparser_find_attr("url", atts); if (str && *str) repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str); - str = find_attr("license", atts); + str = solv_xmlparser_find_attr("license", atts); if (str && *str) repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str); - str = find_attr("sourcerpm", atts); + str = solv_xmlparser_find_attr("sourcerpm", atts); if (str && *str) repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str); break; } case STATE_FILES: { - const char *fn = find_attr("fn", atts); - const char *distepoch = find_attr("distepoch", atts); + const char *fn = solv_xmlparser_find_attr("fn", atts); + const char *distepoch = solv_xmlparser_find_attr("distepoch", atts); pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch); break; } @@ -438,29 +392,22 @@ startElement(void *userData, const char *name, const char **atts) } } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Solvable *s = pd->solvable; - if (pd->depth != pd->statedepth) - { - pd->depth--; - return; - } - pd->depth--; - pd->statedepth--; - switch (pd->state) + switch (state) { case STATE_INFO: - if (s && *pd->content) - repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, pd->content); + if (s && *content) + repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, content); break; case STATE_FILES: - if (s && *pd->content) + if (s && *content) { char *np, *p, *sl; - for (p = pd->content; p && *p; p = np) + for (p = content; p && *p; p = np) { Id id; np = strchr(p, '\n'); @@ -488,42 +435,13 @@ endElement(void *userData, const char *name) default: break; } - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; } -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; -} - -#define BUFF_SIZE 8192 - int repo_add_mdk_info(Repo *repo, FILE *fp, int flags) { Repodata *data; struct parsedata pd; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; - XML_Parser parser; if (!(flags & REPO_EXTEND_SOLVABLES)) { @@ -537,36 +455,11 @@ repo_add_mdk_info(Repo *repo, FILE *fp, int flags) pd.repo = repo; pd.pool = repo->pool; pd.data = data; - - pd.content = solv_malloc(256); - pd.acontent = 256; - + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); pd.joinhash = joinhash_init(repo, &pd.joinhashmask); - - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } - - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); - solv_free(pd.content); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); solv_free(pd.joinhash); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); diff --git a/libsolv-0.6.15/ext/repo_mdk.h b/libsolv-0.7.2/ext/repo_mdk.h similarity index 100% rename from libsolv-0.6.15/ext/repo_mdk.h rename to libsolv-0.7.2/ext/repo_mdk.h diff --git a/libsolv-0.6.15/ext/repo_products.c b/libsolv-0.7.2/ext/repo_products.c similarity index 65% rename from libsolv-0.6.15/ext/repo_products.c rename to libsolv-0.7.2/ext/repo_products.c index cb69c49..edf15bf 100644 --- a/libsolv-0.6.15/ext/repo_products.c +++ b/libsolv-0.7.2/ext/repo_products.c @@ -18,19 +18,16 @@ #include #include #include -#include -#include -#include #include #include #include #include #include -#include #include "pool.h" #include "repo.h" #include "util.h" +#include "solv_xmlparser.h" #define DISABLE_SPLIT #include "tools_util.h" #include "repo_content.h" @@ -68,15 +65,7 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { { STATE_START, "product", STATE_PRODUCT, 0 }, { STATE_PRODUCT, "vendor", STATE_VENDOR, 1 }, { STATE_PRODUCT, "name", STATE_NAME, 1 }, @@ -107,19 +96,11 @@ static struct stateswitch stateswitches[] = { struct parsedata { const char *filename; const char *basename; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Pool *pool; Repo *repo; Repodata *data; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; + struct solv_xmlparser xmlp; struct joindata jd; const char *tmplang; @@ -139,26 +120,6 @@ struct parsedata { }; -/* - * find_attr - * find value for xml attribute - * I: txt, name of attribute - * I: atts, list of key/value attributes - * O: pointer to value of matching key, or NULL - * - */ - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} - static time_t datestr2timestamp(const char *date) { @@ -183,58 +144,19 @@ datestr2timestamp(const char *date) return timegm(&tm); } -/* - * XML callback: startElement - */ - -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; - struct stateswitch *sw; - -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - pd->depth++; - if (!pd->swtab[pd->state]) /* no statetable -> no substates */ - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - - switch(pd->state) + switch(state) { case STATE_PRODUCT: /* parse 'schemeversion' and store in global variable */ { - const char * scheme = find_attr("schemeversion", atts); + const char * scheme = solv_xmlparser_find_attr("schemeversion", atts); pd->productscheme = (scheme && *scheme) ? atoi(scheme) : -1; } if (!s) @@ -247,14 +169,14 @@ startElement(void *userData, const char *name, const char **atts) /* ... */ case STATE_SUMMARY: case STATE_DESCRIPTION: - pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts)); + pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts)); break; case STATE_URL: - pd->urltype = pool_str2id(pd->pool, find_attr("name", atts), 1); + pd->urltype = pool_str2id(pd->pool, solv_xmlparser_find_attr("name", atts), 1); break; case STATE_REGUPDREPO: { - const char *repoid = find_attr("repoid", atts); + const char *repoid = solv_xmlparser_find_attr("repoid", atts); if (repoid && *repoid) { Id h = repodata_new_handle(pd->data); @@ -269,28 +191,13 @@ startElement(void *userData, const char *name, const char **atts) } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Solvable *s = pd->solvable; -#if 0 - fprintf(stderr, "end: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - - switch (pd->state) + switch (state) { case STATE_PRODUCT: /* product done, finish solvable */ @@ -326,159 +233,70 @@ endElement(void *userData, const char *name) pd->solvable = 0; break; case STATE_VENDOR: - s->vendor = pool_str2id(pd->pool, pd->content, 1); + s->vendor = pool_str2id(pd->pool, content, 1); break; case STATE_NAME: - s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1); + s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1); break; case STATE_VERSION: - pd->tmpvers = solv_strdup(pd->content); + pd->tmpvers = solv_strdup(content); break; case STATE_RELEASE: - pd->tmprel = solv_strdup(pd->content); + pd->tmprel = solv_strdup(content); break; case STATE_ARCH: - s->arch = pool_str2id(pd->pool, pd->content, 1); + s->arch = pool_str2id(pd->pool, content, 1); break; case STATE_PRODUCTLINE: - repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, pd->content); + repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, content); break; case STATE_UPDATEREPOKEY: /** obsolete **/ break; case STATE_SUMMARY: - repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content); + repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content); break; case STATE_SHORTSUMMARY: - repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content); + repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, content); break; case STATE_DESCRIPTION: - repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content); + repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content); break; case STATE_URL: if (pd->urltype) { - repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content); + repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, content); repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, pd->urltype); } break; case STATE_TARGET: - repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, pd->content); + repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, content); break; case STATE_REGRELEASE: - repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, pd->content); + repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, content); break; case STATE_REGFLAVOR: - repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, pd->content); + repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, content); break; case STATE_CPEID: - if (*pd->content) - repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, pd->content); + if (*content) + repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, content); break; case STATE_ENDOFLIFE: - if (*pd->content) - { - time_t t = datestr2timestamp(pd->content); - if (t) - repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (unsigned long long)t); - } + /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */ + repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*content ? datestr2timestamp(content) : 0)); break; default: break; } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - -#if 0 - fprintf(stderr, "end: [%s] -> %d\n", name, pd->state); -#endif } - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; -} - -#define BUFF_SIZE 8192 - - -/* - * add single product to repo - * - */ - -static void -add_code11_product(struct parsedata *pd, FILE *fp) -{ - char buf[BUFF_SIZE]; - int l; - struct stat st; - XML_Parser parser; - - if (!fstat(fileno(fp), &st)) - { - pd->currentproduct = st.st_ino; - pd->ctime = (unsigned int)st.st_ctime; - } - else - { - pd->currentproduct = pd->baseproduct + 1; /* make it != baseproduct if stat fails */ - pool_error(pd->pool, 0, "fstat: %s", strerror(errno)); - pd->ctime = 0; - } - - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - XML_ParserFree(parser); - if (pd->solvable) - { - repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); - pd->solvable = 0; - } - return; - } - if (l == 0) - break; - } - XML_ParserFree(parser); -} - - int repo_add_code11_products(Repo *repo, const char *dirpath, int flags) { Repodata *data; struct parsedata pd; - struct stateswitch *sw; DIR *dir; - int i; data = repo_add_repodata(repo, flags); @@ -487,15 +305,7 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags) pd.pool = repo->pool; pd.data = data; - pd.content = solv_malloc(256); - pd.acontent = 256; - - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); if (flags & REPO_USE_ROOTDIR) dirpath = pool_prepend_rootdir(repo->pool, dirpath); @@ -525,14 +335,26 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags) pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno)); continue; } + if (fstat(fileno(fp), &st)) + { + pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno)); + fclose(fp); + continue; + } + pd.currentproduct = st.st_ino; + pd.ctime = (unsigned int)st.st_ctime; pd.filename = fullpath; pd.basename = entry->d_name; - add_code11_product(&pd, fp); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + { + pool_debug(pd.pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + pd.solvable = solvable_free(pd.solvable, 1); + } fclose(fp); } closedir(dir); } - solv_free(pd.content); + solv_xmlparser_free(&pd.xmlp); join_freemem(&pd.jd); if (flags & REPO_USE_ROOTDIR) solv_free((char *)dirpath); diff --git a/libsolv-0.6.15/ext/repo_products.h b/libsolv-0.7.2/ext/repo_products.h similarity index 100% rename from libsolv-0.6.15/ext/repo_products.h rename to libsolv-0.7.2/ext/repo_products.h diff --git a/libsolv-0.6.15/ext/repo_pubkey.c b/libsolv-0.7.2/ext/repo_pubkey.c similarity index 99% rename from libsolv-0.6.15/ext/repo_pubkey.c rename to libsolv-0.7.2/ext/repo_pubkey.c index d8496dc..eb83839 100644 --- a/libsolv-0.6.15/ext/repo_pubkey.c +++ b/libsolv-0.7.2/ext/repo_pubkey.c @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include #include diff --git a/libsolv-0.6.15/ext/repo_pubkey.h b/libsolv-0.7.2/ext/repo_pubkey.h similarity index 97% rename from libsolv-0.6.15/ext/repo_pubkey.h rename to libsolv-0.7.2/ext/repo_pubkey.h index dbc7f9c..26cf0e1 100644 --- a/libsolv-0.6.15/ext/repo_pubkey.h +++ b/libsolv-0.7.2/ext/repo_pubkey.h @@ -19,7 +19,7 @@ extern int repo_add_keyring(Repo *repo, FILE *fp, int flags); extern int repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags); /* signature parsing */ -typedef struct _solvsig { +typedef struct s_Solvsig { unsigned char *sigpkt; int sigpktl; Id htype; diff --git a/libsolv-0.6.15/ext/repo_releasefile_products.c b/libsolv-0.7.2/ext/repo_releasefile_products.c similarity index 100% rename from libsolv-0.6.15/ext/repo_releasefile_products.c rename to libsolv-0.7.2/ext/repo_releasefile_products.c diff --git a/libsolv-0.6.15/ext/repo_releasefile_products.h b/libsolv-0.7.2/ext/repo_releasefile_products.h similarity index 100% rename from libsolv-0.6.15/ext/repo_releasefile_products.h rename to libsolv-0.7.2/ext/repo_releasefile_products.h diff --git a/libsolv-0.6.15/ext/repo_repomdxml.c b/libsolv-0.7.2/ext/repo_repomdxml.c similarity index 66% rename from libsolv-0.6.15/ext/repo_repomdxml.c rename to libsolv-0.7.2/ext/repo_repomdxml.c index 1d1197e..fd46272 100644 --- a/libsolv-0.6.15/ext/repo_repomdxml.c +++ b/libsolv-0.7.2/ext/repo_repomdxml.c @@ -5,20 +5,16 @@ * for further information */ -#define DO_ARRAY 1 - #define _GNU_SOURCE #include -#include -#include #include #include #include -#include #include "pool.h" #include "repo.h" #include "chksum.h" +#include "solv_xmlparser.h" #include "repo_repomdxml.h" /* @@ -110,15 +106,7 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { /* suseinfo tags */ { STATE_START, "repomd", STATE_REPOMD, 0 }, { STATE_START, "suseinfo", STATE_SUSEINFO, 0 }, @@ -153,20 +141,12 @@ static struct stateswitch stateswitches[] = { struct parsedata { int ret; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Pool *pool; Repo *repo; Repodata *data; - XML_Parser *parser; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; + struct solv_xmlparser xmlp; + int timestamp; /* handles for collection structures */ @@ -180,66 +160,20 @@ struct parsedata { Id chksumtype; }; -/* - * find attribute - */ - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; -} - -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; - /*Pool *pool = pd->pool;*/ - struct stateswitch *sw; - -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) - return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; + struct parsedata *pd = xmlp->userdata; - switch(pd->state) + switch(state) { case STATE_REPOMD: { const char *updstr; /* this should be OBSOLETE soon */ - updstr = find_attr("updates", atts); + updstr = solv_xmlparser_find_attr("updates", atts); if (updstr) { char *value = solv_strdup(updstr); @@ -253,7 +187,7 @@ startElement(void *userData, const char *name, const char **atts) repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value); value = p; } - free(fvalue); + solv_free(fvalue); } break; } @@ -261,7 +195,7 @@ startElement(void *userData, const char *name, const char **atts) { /* this is extra metadata about the product this repository was designed for */ - const char *cpeid = find_attr("cpeid", atts); + const char *cpeid = solv_xmlparser_find_attr("cpeid", atts); pd->rphandle = repodata_new_handle(pd->data); /* set the cpeid for the product the label is set in the content of the tag */ @@ -273,7 +207,7 @@ startElement(void *userData, const char *name, const char **atts) { /* this is extra metadata about the product this repository was designed for */ - const char *cpeid = find_attr("cpeid", atts); + const char *cpeid = solv_xmlparser_find_attr("cpeid", atts); pd->ruhandle = repodata_new_handle(pd->data); /* set the cpeid for the product the label is set in the content of the tag */ @@ -283,7 +217,7 @@ startElement(void *userData, const char *name, const char **atts) } case STATE_DATA: { - const char *type= find_attr("type", atts); + const char *type= solv_xmlparser_find_attr("type", atts); pd->rdhandle = repodata_new_handle(pd->data); if (type) repodata_set_poolstr(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TYPE, type); @@ -291,7 +225,7 @@ startElement(void *userData, const char *name, const char **atts) } case STATE_LOCATION: { - const char *href = find_attr("href", atts); + const char *href = solv_xmlparser_find_attr("href", atts); if (href) repodata_set_str(pd->data, pd->rdhandle, REPOSITORY_REPOMD_LOCATION, href); break; @@ -299,10 +233,10 @@ startElement(void *userData, const char *name, const char **atts) case STATE_CHECKSUM: case STATE_OPENCHECKSUM: { - const char *type= find_attr("type", atts); + const char *type= solv_xmlparser_find_attr("type", atts); pd->chksumtype = type && *type ? solv_chksum_str2type(type) : 0; if (!pd->chksumtype) - pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), type ? type : "NULL"); + pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), type ? type : "NULL"); break; } default: @@ -311,27 +245,11 @@ startElement(void *userData, const char *name, const char **atts) return; } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; - /* Pool *pool = pd->pool; */ - -#if 0 - fprintf(stderr, "endElement: %s\n", name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - switch (pd->state) + struct parsedata *pd = xmlp->userdata; + switch (state) { case STATE_REPOMD: if (pd->timestamp > 0) @@ -347,10 +265,10 @@ endElement(void *userData, const char *name) case STATE_OPENCHECKSUM: if (!pd->chksumtype) break; - if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype)) - pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); + if (strlen(content) != 2 * solv_chksum_len(pd->chksumtype)) + pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype)); else - repodata_set_checksum(pd->data, pd->rdhandle, pd->state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, pd->content); + repodata_set_checksum(pd->data, pd->rdhandle, state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, content); break; case STATE_TIMESTAMP: @@ -360,7 +278,7 @@ endElement(void *userData, const char *name) * of all resources to save it as the time * the metadata was generated */ - int timestamp = atoi(pd->content); + int timestamp = atoi(content); if (timestamp) repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TIMESTAMP, timestamp); if (timestamp > pd->timestamp) @@ -369,7 +287,7 @@ endElement(void *userData, const char *name) } case STATE_EXPIRE: { - int expire = atoi(pd->content); + int expire = atoi(content); if (expire > 0) repodata_set_num(pd->data, SOLVID_META, REPOSITORY_EXPIRE, expire); break; @@ -377,119 +295,62 @@ endElement(void *userData, const char *name) /* repomd.xml content and suseinfo.xml keywords are equivalent */ case STATE_CONTENT: case STATE_KEYWORD: - if (*pd->content) - repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, pd->content); + if (*content) + repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, content); break; case STATE_REVISION: - if (*pd->content) - repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, pd->content); + if (*content) + repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, content); break; case STATE_DISTRO: /* distro tag is used in repomd.xml to say the product this repo is made for */ - if (*pd->content) - repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, pd->content); + if (*content) + repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, content); repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_DISTROS, pd->rphandle); break; case STATE_UPDATES: /* updates tag is used in suseinfo.xml to say the repo updates a product however it s not yet a tag standarized for repomd.xml */ - if (*pd->content) - repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, pd->content); + if (*content) + repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, content); repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_UPDATES, pd->ruhandle); break; case STATE_REPO: - if (*pd->content) - repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, pd->content); + if (*content) + repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, content); break; case STATE_SIZE: - if (*pd->content) - repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(pd->content, 0, 10)); + if (*content) + repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(content, 0, 10)); break; default: break; } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - - return; -} - - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; } -#define BUFF_SIZE 8192 - int repo_add_repomdxml(Repo *repo, FILE *fp, int flags) { Pool *pool = repo->pool; struct parsedata pd; Repodata *data; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; - XML_Parser parser; data = repo_add_repodata(repo, flags); memset(&pd, 0, sizeof(pd)); pd.timestamp = 0; - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } pd.pool = pool; pd.repo = repo; pd.data = data; - - pd.content = malloc(256); - pd.acontent = 256; - pd.lcontent = 0; - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - pd.parser = &parser; - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pd.ret = pool_error(pool, -1, "repo_repomdxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pd.ret = pool_error(pd.pool, -1, "repo_repomdxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); - free(pd.content); return pd.ret; } diff --git a/libsolv-0.6.15/ext/repo_repomdxml.h b/libsolv-0.7.2/ext/repo_repomdxml.h similarity index 100% rename from libsolv-0.6.15/ext/repo_repomdxml.h rename to libsolv-0.7.2/ext/repo_repomdxml.h diff --git a/libsolv-0.6.15/ext/repo_rpmdb.c b/libsolv-0.7.2/ext/repo_rpmdb.c similarity index 69% rename from libsolv-0.6.15/ext/repo_rpmdb.c rename to libsolv-0.7.2/ext/repo_rpmdb.c index d49f9d8..9acb400 100644 --- a/libsolv-0.6.15/ext/repo_rpmdb.c +++ b/libsolv-0.7.2/ext/repo_rpmdb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2012, Novell Inc. + * Copyright (c) 2007-2018, SUSE Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -24,6 +24,8 @@ #include #include +#ifdef ENABLE_RPMDB + #include #include #ifndef RPM5 @@ -31,12 +33,6 @@ #endif #include -#ifndef DB_CREATE -# if defined(SUSE) || defined(HAVE_RPM_DB_H) -# include -# else -# include -# endif #endif #include "pool.h" @@ -54,7 +50,9 @@ /* 3: added triggers */ /* 4: fixed triggers */ /* 5: fixed checksum copying */ -#define RPMDB_COOKIE_VERSION 5 +/* 6: add SOLVABLE_PREREQ_IGNOREINST support */ +/* 7: fix bug in ignoreinst logic */ +#define RPMDB_COOKIE_VERSION 7 #define TAG_NAME 1000 #define TAG_VERSION 1001 @@ -138,6 +136,7 @@ #define TAG_SIGBASE 256 #define TAG_SIGMD5 (TAG_SIGBASE + 5) #define TAG_SHA1HEADER (TAG_SIGBASE + 13) +#define TAG_SHA256HEADER (TAG_SIGBASE + 17) #define SIGTAG_SIZE 1000 #define SIGTAG_PGP 1002 /* RSA signature */ @@ -151,21 +150,24 @@ #define DEP_PRE_IN ((1 << 6) | (1 << 9) | (1 << 10)) #define DEP_PRE_UN ((1 << 6) | (1 << 11) | (1 << 12)) -#define FILEFLAG_GHOST (1 << 6) +#define FILEFLAG_GHOST (1 << 6) -#ifdef RPM5 -# define RPM_INDEX_SIZE 4 /* just the rpmdbid */ -#else -# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */ -#endif +/* some limits to guard against corrupt rpms */ +/* dsize limits taken from rpm's lib/header.c */ +#define MAX_SIG_CNT 0x10000 +#define MAX_SIG_DSIZE 0x4000000 + +#define MAX_HDR_CNT 0x10000 +#define MAX_HDR_DSIZE 0x10000000 +#ifndef ENABLE_RPMPKG_LIBRPM + typedef struct rpmhead { int cnt; - int dcnt; + unsigned int dcnt; unsigned char *dp; - int forcebinary; /* sigh, see rh#478907 */ unsigned char data[1]; } RpmHead; @@ -192,20 +194,21 @@ headexists(RpmHead *h, int tag) return headfindtag(h, tag) ? 1 : 0; } -static unsigned int * +static uint32_t * headint32array(RpmHead *h, int tag, int *cnt) { - unsigned int i, o, *r; + uint32_t *r; + unsigned int i, o; unsigned char *d = headfindtag(h, tag); if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o + 4 * i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt) return 0; d = h->dp + o; - r = solv_calloc(i ? i : 1, sizeof(unsigned int)); + r = solv_calloc(i ? i : 1, sizeof(uint32_t)); if (cnt) *cnt = i; for (o = 0; o < i; o++, d += 4) @@ -214,7 +217,7 @@ headint32array(RpmHead *h, int tag, int *cnt) } /* returns the first entry of an integer array */ -static unsigned int +static uint32_t headint32(RpmHead *h, int tag) { unsigned int i, o; @@ -224,68 +227,71 @@ headint32(RpmHead *h, int tag) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (i == 0 || o + 4 * i > h->dcnt) + if (i == 0 || o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt) return 0; d = h->dp + o; return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; } -static unsigned long long * +static uint64_t * headint64array(RpmHead *h, int tag, int *cnt) { + uint64_t *r; unsigned int i, o; - unsigned long long *r; unsigned char *d = headfindtag(h, tag); if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o + 8 * i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt) return 0; d = h->dp + o; - r = solv_calloc(i ? i : 1, sizeof(unsigned long long)); + r = solv_calloc(i ? i : 1, sizeof(uint64_t)); if (cnt) *cnt = i; for (o = 0; o < i; o++, d += 8) { - unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; - r[o] = (unsigned long long)x << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); + uint32_t x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; + r[o] = (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); } return r; } /* returns the first entry of an 64bit integer array */ -static unsigned long long +static uint64_t headint64(RpmHead *h, int tag) { + uint32_t x; unsigned int i, o; unsigned char *d = headfindtag(h, tag); + if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (i == 0 || o + 8 * i > h->dcnt) + if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt) return 0; d = h->dp + o; - i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; - return (unsigned long long)i << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); + x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; + return (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); } -static unsigned int * +static uint16_t * headint16array(RpmHead *h, int tag, int *cnt) { - unsigned int i, o, *r; + uint16_t *r; + unsigned int i, o; unsigned char *d = headfindtag(h, tag); if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o + 4 * i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt) return 0; d = h->dp + o; - r = solv_calloc(i ? i : 1, sizeof(unsigned int)); + r = solv_calloc(i ? i : 1, sizeof(uint16_t)); if (cnt) *cnt = i; for (o = 0; o < i; o++, d += 2) @@ -318,6 +324,8 @@ headstringarray(RpmHead *h, int tag, int *cnt) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; + if (o > h->dcnt || i > h->dcnt) + return 0; r = solv_calloc(i ? i : 1, sizeof(char *)); if (cnt) *cnt = i; @@ -345,13 +353,127 @@ headbinary(RpmHead *h, int tag, unsigned int *sizep) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o > h->dcnt || o + i < o || o + i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + i > h->dcnt) return 0; if (sizep) *sizep = i; return h->dp + o; } +static int +headissourceheuristic(RpmHead *h) +{ + unsigned int i, o; + unsigned char *d = headfindtag(h, TAG_DIRNAMES); + if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8) + return 0; + o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; + i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; + return i == 1 && o < h->dcnt && !h->dp[o] ? 1 : 0; +} + +static inline void +headfree(RpmHead *h) +{ + solv_free(h); +} + +#else + +typedef struct headerToken_s RpmHead; + +static int +headexists(RpmHead *h, int tag) +{ + return headerIsEntry(h, tag); +} + +static void *headget(RpmHead *h, int tag, int *cnt, int alloc) +{ + struct rpmtd_s td; + if (!headerGet(h, tag, &td, alloc ? HEADERGET_ALLOC : HEADERGET_MINMEM)) + return 0; + if (cnt) + *cnt = td.count; + return td.data; +} + +static uint32_t * +headint32array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static uint32_t +headint32(RpmHead *h, int tag) +{ + uint32_t *arr = headget(h, tag, 0, 0); + return arr ? arr[0] : 0; +} + +static uint64_t * +headint64array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +/* returns the first entry of an 64bit integer array */ +static uint64_t +headint64(RpmHead *h, int tag) +{ + uint64_t *arr = headget(h, tag, 0, 0); + return arr ? arr[0] : 0; +} + +static uint16_t * +headint16array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static char * +headstring(RpmHead *h, int tag) +{ + return headget(h, tag, 0, 0); +} + +static char ** +headstringarray(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static unsigned char * +headbinary(RpmHead *h, int tag, unsigned int *sizep) +{ + unsigned char *b = headget(h, tag, (int *)sizep, 0); + if (b && sizep && (tag == TAG_SIGMD5 || tag == SIGTAG_MD5) && *sizep > 16) { + /* due to a bug in rpm the count may be bigger if HEADERIMPORT_FAST is used */ + *sizep = 16; + } + return b; +} + +static int +headissourceheuristic(RpmHead *h) +{ + struct rpmtd_s td; + int issource; + if (!headerGet(h, TAG_DIRNAMES, &td, HEADERGET_MINMEM)) + return 0; + issource = td.count == 1 && td.data && ((char **)td.data)[0] && !((char **)td.data)[0][0]; + rpmtdFreeData(&td); + return issource; +} + +static inline void +headfree(RpmHead *h) +{ + headerFree(h); +} + +#endif + static char *headtoevr(RpmHead *h) { unsigned int epoch; @@ -364,10 +486,7 @@ static char *headtoevr(RpmHead *h) release = headstring(h, TAG_RELEASE); epoch = headint32(h, TAG_EPOCH); if (!version || !release) - { - fprintf(stderr, "headtoevr: bad rpm header\n"); - return 0; - } + return 0; for (v = version; *v >= '0' && *v <= '9'; v++) ; if (epoch || (v != version && *v == ':')) @@ -407,18 +526,27 @@ setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) repodata_set_str(repodata, handle, tag, str); } +static int +ignq_sortcmp(const void *va, const void *vb, void *dp) +{ + int r = *(Id *)va - *(Id *)vb; + if (!r) + r = ((Id *)va)[1] - ((Id *)vb)[1]; + return r; +} + /* * strong: 0: ignore strongness * 1: filter to strong * 2: filter to weak */ static unsigned int -makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags) +makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq) { char **n, **v; - unsigned int *f; + uint32_t *f; int i, cc, nc, vc, fc; - int haspre, premask; + int haspre, premask, has_ign; unsigned int olddeps; Id *ida; int strong = 0; @@ -512,6 +640,8 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, cc += haspre; /* add slot for the prereq marker */ olddeps = repo_reserve_ids(repo, 0, cc); ida = repo->idarraydata + olddeps; + + has_ign = 0; for (i = 0; ; i++) { Id id; @@ -564,23 +694,69 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, id = pool_rel2id(pool, id, evr, fl, 1); } *ida++ = id; + if (haspre == 2 && ignq) + { + int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0; + has_ign |= is_ign; + queue_push2(ignq, id, is_ign); + } } *ida++ = 0; repo->idarraysize += cc + 1; solv_free(n); solv_free(v); solv_free(f); + if (ignq && ignq->count) + { + int j = 0; + if (has_ign && ignq->count == 2) + j = 1; + else if (has_ign) + { + Id id, lastid = 0; + + solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0); + for (i = j = 0; i < ignq->count; i += 2) + { + id = ignq->elements[i]; + if (id != lastid && ignq->elements[i + 1] > 0) + ignq->elements[j++] = id; + lastid = id; + } + } + queue_truncate(ignq, j); + } return olddeps; } +static Id +repodata_str2dir_rooted(Repodata *data, char *str, int create) +{ + char buf[256], *bp; + int l = strlen(str); + Id id; + + if (l + 2 <= sizeof(buf)) + bp = buf; + else + bp = solv_malloc(l + 2); + bp[0] = '/'; + strcpy(bp + 1, str); + id = repodata_str2dir(data, bp, create); + if (bp != buf) + solv_free(bp); + return id; +} static void -adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc) +adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, uint32_t *di, int fc, int dc) { Id did; int i, fszc; - unsigned int *fkb, *fn, *fsz, *fm, *fino; - unsigned long long *fsz64; + unsigned int *fkb, *fn; + uint64_t *fsz64; + uint32_t *fsz, *fino; + uint16_t *fm; unsigned int inotest[256], inotestok; if (!fc) @@ -714,13 +890,13 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * { if (!fn[i]) continue; - if (!*dn[i]) + if (dn[i][0] != '/') { - Solvable *s = data->repo->pool->solvables + handle; + Solvable *s = data->repo->pool->solvables + handle; if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) did = repodata_str2dir(data, "/usr/src", 1); else - continue; /* work around rpm bug */ + did = repodata_str2dir_rooted(data, dn[i], 1); } else did = repodata_str2dir(data, dn[i], 1); @@ -750,11 +926,11 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags) { char **bn; char **dn; - unsigned int *di; + uint32_t *di; int bnc, dnc, dic; int i; - Id lastdid = 0; - unsigned int lastdii = -1; + Id did; + uint32_t lastdii = -1; int lastfiltered = 0; if (!data) @@ -783,17 +959,16 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags) adddudata(data, handle, rpmhead, dn, di, bnc, dnc); + did = -1; for (i = 0; i < bnc; i++) { - Id did; char *b = bn[i]; - if (di[i] == lastdii) - did = lastdid; - else + if (did < 0 || di[i] != lastdii) { if (di[i] >= dnc) continue; /* corrupt entry */ + did = 0; lastdii = di[i]; if ((flags & RPM_ADD_FILTERED_FILELIST) != 0) { @@ -801,18 +976,17 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags) if (lastfiltered == 1) continue; } - did = repodata_str2dir(data, dn[lastdii], 1); - if (!did) - did = repodata_str2dir(data, "/", 1); - lastdid = did; + if (dn[lastdii][0] != '/') + did = repodata_str2dir_rooted(data, dn[lastdii], 1); + else + did = repodata_str2dir(data, dn[lastdii], 1); } - if (b && *b == '/') /* work around rpm bug */ + if (!b) + continue; + if (*b == '/') /* work around rpm bug */ b++; - if (lastfiltered) - { - if (lastfiltered != 2 || strcmp(b, "sendmail")) - continue; - } + if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail"))) + continue; repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b); } solv_free(bn); @@ -825,8 +999,8 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead) { char **cn; char **cx; - unsigned int *ct; - int i, cnc, cxc, ctc; + uint32_t *ct; + int i, cnc, cxc, ctc = 0; Queue hq; ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc); @@ -904,11 +1078,13 @@ set_description_author(Repodata *data, Id handle, char *str) } static int -rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) +rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) { char *name; char *evr; char *sourcerpm; + Queue ignq; + Id ignqbuf[64]; name = headstring(rpmhead, TAG_NAME); if (!name) @@ -916,11 +1092,11 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, pool_error(pool, 0, "package has no name"); return 0; } - if (!strcmp(name, "gpg-pubkey")) + if (!(flags & RPMDB_KEEP_GPG_PUBKEY) && !strcmp(name, "gpg-pubkey")) return 0; s->name = pool_str2id(pool, name, 1); sourcerpm = headstring(rpmhead, TAG_SOURCERPM); - if (sourcerpm || (rpmhead->forcebinary && !headexists(rpmhead, TAG_SOURCEPACKAGE))) + if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead))) s->arch = pool_str2id(pool, headstring(rpmhead, TAG_ARCH), 1); else { @@ -933,22 +1109,28 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, s->arch = ARCH_NOARCH; evr = headtoevr(rpmhead); s->evr = pool_str2id(pool, evr, 1); + solv_free(evr); s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1); - s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0); + queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf)); + + s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0); if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags); - s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0); - s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0); + s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq); + s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0); + s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0); - s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0); - s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0); - s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0); - s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0); + s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0); + s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0); + s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0); + s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0); - s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); - s->conflicts = repo_fix_conflicts(repo, s->conflicts); + repo_rewrite_suse_deps(s, 0); + + if (data && ignq.count) + repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq); + queue_free(&ignq); if (data) { @@ -1014,52 +1196,27 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, repodata_set_sourcepkg(data, handle, sourcerpm); if ((flags & RPM_ADD_TRIGGERS) != 0) { - Id id, lastid; - unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0); - - lastid = 0; - for (; (id = repo->idarraydata[ida]) != 0; ida++) - { - /* we currently do not support rel ids in incore data, so - * strip off versioning information */ - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - id = rd->name; - } - if (id == lastid) - continue; + unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0); + Id id, lastid = 0; + for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id) + if (id != lastid) repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id); - lastid = id; - } } if ((flags & RPM_ADD_NO_FILELIST) == 0) addfilelist(data, handle, rpmhead, flags); if ((flags & RPM_ADD_WITH_CHANGELOG) != 0) addchangelog(data, handle, rpmhead); } - solv_free(evr); return 1; } +static inline unsigned int +getu32(const unsigned char *dp) +{ + return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3]; +} -/******************************************************************/ -/* Rpm Database stuff - */ - -struct rpmdbstate { - Pool *pool; - char *rootdir; - - RpmHead *rpmhead; /* header storage space */ - int rpmheadsize; - - int dbopened; - DB_ENV *dbenv; /* database environment */ - DB *db; /* packages database */ - int byteswapped; /* endianess of packages database */ - int is_ostree; /* read-only db that lives in /usr/share/rpm */ -}; +#ifdef ENABLE_RPMDB struct rpmdbentry { Id rpmdbid; @@ -1069,371 +1226,117 @@ struct rpmdbentry { #define ENTRIES_BLOCK 255 #define NAMEDATA_BLOCK 1023 - -static inline Id db2rpmdbid(unsigned char *db, int byteswapped) -{ -#ifdef RPM5 - return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; -#else -# if defined(WORDS_BIGENDIAN) - if (!byteswapped) +# ifdef ENABLE_RPMDB_LIBRPM +# include "repo_rpmdb_librpm.h" # else - if (byteswapped) +# include "repo_rpmdb_bdb.h" # endif - return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; - else - return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0]; -#endif -} -static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped) -{ -#ifdef RPM5 - db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; #else -# if defined(WORDS_BIGENDIAN) - if (!byteswapped) -# else - if (byteswapped) -# endif - db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; - else - db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id; -#endif -} -#ifdef FEDORA -int -serialize_dbenv_ops(struct rpmdbstate *state) -{ - char lpath[PATH_MAX]; - mode_t oldmask; - int fd; - struct flock fl; - - snprintf(lpath, PATH_MAX, "%s/var/lib/rpm/.dbenv.lock", state->rootdir ? state->rootdir : ""); - oldmask = umask(022); - fd = open(lpath, (O_RDWR|O_CREAT), 0644); - umask(oldmask); - if (fd < 0) - return -1; - memset(&fl, 0, sizeof(fl)); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - for (;;) - { - if (fcntl(fd, F_SETLKW, &fl) != -1) - return fd; - if (errno != EINTR) - break; - } - close(fd); - return -1; -} -#endif +/* dummy state just to store pool/rootdir and header data */ +struct rpmdbstate { + Pool *pool; + char *rootdir; -/* should look in /usr/lib/rpm/macros instead, but we want speed... */ -static int -opendbenv(struct rpmdbstate *state) -{ - const char *rootdir = state->rootdir; - char dbpath[PATH_MAX]; - DB_ENV *dbenv = 0; - int r; + RpmHead *rpmhead; /* header storage space */ + int rpmheadsize; +}; - if (db_env_create(&dbenv, 0)) - return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno)); -#if defined(FEDORA) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)) - dbenv->set_thread_count(dbenv, 8); -#endif - snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir ? rootdir : ""); - if (access(dbpath, W_OK) == -1) - { - snprintf(dbpath, PATH_MAX, "%s/usr/share/rpm/Packages", rootdir ? rootdir : ""); - if (access(dbpath, R_OK) == 0) - state->is_ostree = 1; - snprintf(dbpath, PATH_MAX, "%s%s", rootdir ? rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); - } - else - { -#ifdef FEDORA - int serialize_fd = serialize_dbenv_ops(state); - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0644); - if (serialize_fd >= 0) - close(serialize_fd); -#else - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); #endif - } - if (r) - { - pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno)); - dbenv->close(dbenv, 0); - return 0; - } - state->dbenv = dbenv; - return 1; -} -static void -closedbenv(struct rpmdbstate *state) -{ -#ifdef FEDORA - uint32_t eflags = 0; -#endif - if (!state->dbenv) - return; -#ifdef FEDORA - (void)state->dbenv->get_open_flags(state->dbenv, &eflags); - if (!(eflags & DB_PRIVATE)) - { - int serialize_fd = serialize_dbenv_ops(state); - state->dbenv->close(state->dbenv, 0); - if (serialize_fd >= 0) - close(serialize_fd); - } - else - state->dbenv->close(state->dbenv, 0); -#else - state->dbenv->close(state->dbenv, 0); -#endif - state->dbenv = 0; -} +#ifndef ENABLE_RPMPKG_LIBRPM static int -openpkgdb(struct rpmdbstate *state) +headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2) { - if (state->dbopened) - return state->dbopened > 0 ? 1 : 0; - state->dbopened = -1; - if (!state->dbenv && !opendbenv(state)) - return 0; - if (db_create(&state->db, state->dbenv, 0)) - { - pool_error(state->pool, 0, "db_create: %s", strerror(errno)); - state->db = 0; - closedbenv(state); - return 0; - } - if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno)); - state->db->close(state->db, 0); - state->db = 0; - closedbenv(state); - return 0; - } - if (state->db->get_byteswapped(state->db, &state->byteswapped)) + RpmHead *rpmhead; + unsigned int len = 16 * cnt + dsize + pad; + if (len + 1 > state->rpmheadsize) { - pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno)); - state->db->close(state->db, 0); - state->db = 0; - closedbenv(state); - return 0; + state->rpmheadsize = len + 128; + state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); } - state->dbopened = 1; + rpmhead = state->rpmhead; + if (fread(rpmhead->data, len, 1, fp) != 1) + return pool_error(state->pool, 0, "%s: unexpected EOF", name); + if (chk1) + solv_chksum_add(chk1, rpmhead->data, len); + if (chk2) + solv_chksum_add(chk2, rpmhead->data, len); + rpmhead->data[len] = 0; + rpmhead->cnt = cnt; + rpmhead->dcnt = dsize; + rpmhead->dp = rpmhead->data + cnt * 16; return 1; } -/* get the rpmdbids of all installed packages from the Name index database. - * This is much faster then querying the big Packages database */ -static struct rpmdbentry * -getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap) +#if defined(ENABLE_RPMDB_BYRPMHEADER) +static void +headfromblob(struct rpmdbstate *state, const unsigned char *blob, unsigned int cnt, unsigned int dsize) { - DB_ENV *dbenv = 0; - DB *db = 0; - DBC *dbc = 0; - int byteswapped; - DBT dbkey; - DBT dbdata; - unsigned char *dp; - int dl; - Id nameoff; - - char *namedata = 0; - int namedatal = 0; - struct rpmdbentry *entries = 0; - int nentries = 0; - - *nentriesp = 0; - if (namedatap) - *namedatap = 0; - - if (!state->dbenv && !opendbenv(state)) - return 0; - dbenv = state->dbenv; - if (db_create(&db, dbenv, 0)) - { - pool_error(state->pool, 0, "db_create: %s", strerror(errno)); - return 0; - } - if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno)); - db->close(db, 0); - return 0; - } - if (db->get_byteswapped(db, &byteswapped)) - { - pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno)); - db->close(db, 0); - return 0; - } - if (db->cursor(db, NULL, &dbc, 0)) - { - pool_error(state->pool, 0, "db->cursor: %s", strerror(errno)); - db->close(db, 0); - return 0; - } - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - if (match) + RpmHead *rpmhead; + unsigned int len = 16 * cnt + dsize; + if (len + 1 > state->rpmheadsize) { - dbkey.data = (void *)match; - dbkey.size = strlen(match); + state->rpmheadsize = len + 128; + state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); } - while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0) - { - if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10)) - continue; - dl = dbdata.size; - dp = dbdata.data; - nameoff = namedatal; - if (namedatap) - { - namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK); - memcpy(namedata + namedatal, dbkey.data, dbkey.size); - namedata[namedatal + dbkey.size] = 0; - namedatal += dbkey.size + 1; - } - while(dl >= RPM_INDEX_SIZE) - { - entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK); - entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped); - entries[nentries].nameoff = nameoff; - nentries++; - dp += RPM_INDEX_SIZE; - dl -= RPM_INDEX_SIZE; - } - if (match) - break; - } - dbc->c_close(dbc); - db->close(db, 0); - /* make sure that enteries is != 0 if there was no error */ - if (!entries) - entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK); - *nentriesp = nentries; - if (namedatap) - *namedatap = namedata; - return entries; + rpmhead = state->rpmhead; + memcpy(rpmhead->data, blob, len); + rpmhead->data[len] = 0; + rpmhead->cnt = cnt; + rpmhead->dcnt = dsize; + rpmhead->dp = rpmhead->data + cnt * 16; } +#endif + +#else -/* retrive header by rpmdbid */ static int -getrpmdbid(struct rpmdbstate *state, Id rpmdbid) +headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2) { - unsigned char buf[16]; - DBT dbkey; - DBT dbdata; - RpmHead *rpmhead; - - if (!rpmdbid) - { - pool_error(state->pool, 0, "illegal rpmdbid"); - return -1; - } - if (state->dbopened != 1 && !openpkgdb(state)) - return -1; - rpmdbid2db(buf, rpmdbid, state->byteswapped); - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - dbkey.data = buf; - dbkey.size = 4; - dbdata.data = 0; - dbdata.size = 0; - if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0)) - return 0; - if (dbdata.size < 8) - { - pool_error(state->pool, 0, "corrupt rpm database (size)"); - return -1; - } - if (dbdata.size > state->rpmheadsize) - { - state->rpmheadsize = dbdata.size + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(buf, dbdata.data, 8); - rpmhead->forcebinary = 1; - rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; - rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; - if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size) - { - pool_error(state->pool, 0, "corrupt rpm database (data size)"); - return -1; - } - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; + unsigned int len = 16 * cnt + dsize + pad; + char *buf = solv_malloc(8 + len); + Header h; + memcpy(buf, lead + 8, 8); + if (fread(buf + 8, len, 1, fp) != 1) + { + solv_free(buf); + return pool_error(state->pool, 0, "%s: unexpected EOF", name); + } + if (chk1) + solv_chksum_add(chk1, buf + 8, len); + if (chk2) + solv_chksum_add(chk2, buf + 8, len); + h = headerImport(buf, 8 + len - pad, HEADERIMPORT_FAST); + if (!h) + { + solv_free(buf); + return pool_error(state->pool, 0, "%s: headerImport error", name); + } + if (state->rpmhead) + headfree(state->rpmhead); + state->rpmhead = h; return 1; } -/* retrive header by berkeleydb cursor */ -static Id -getrpmcursor(struct rpmdbstate *state, DBC *dbc) -{ - unsigned char buf[16]; - DBT dbkey; - DBT dbdata; - RpmHead *rpmhead; - Id dbid; - - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) - { - if (dbkey.size != 4) - return pool_error(state->pool, -1, "corrupt Packages database (key size)"); - dbid = db2rpmdbid(dbkey.data, state->byteswapped); - if (dbid == 0) /* the join key */ - continue; - if (dbdata.size < 8) - return pool_error(state->pool, -1, "corrupt rpm database (size %u)\n", dbdata.size); - if (dbdata.size > state->rpmheadsize) - { - state->rpmheadsize = dbdata.size + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(buf, dbdata.data, 8); - rpmhead->forcebinary = 1; - rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; - rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; - if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size) - return pool_error(state->pool, -1, "corrupt rpm database (data size)\n"); - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return dbid; - } - return 0; -} +#endif static void freestate(struct rpmdbstate *state) { /* close down */ - if (!state) - return; - if (state->db) - state->db->close(state->db, 0); - if (state->dbenv) +#ifdef ENABLE_RPMDB + if (state->pkgdbopened) + closepkgdb(state); + if (state->dbenvopened) closedbenv(state); +#endif if (state->rootdir) solv_free(state->rootdir); - solv_free(state->rpmhead); + headfree(state->rpmhead); } void * @@ -1450,50 +1353,14 @@ rpm_state_create(Pool *pool, const char *rootdir) void * rpm_state_free(void *state) { - freestate(state); + if (state) + freestate(state); return solv_free(state); } -static int -count_headers(struct rpmdbstate *state) -{ - Pool *pool = state->pool; - char dbpath[PATH_MAX]; - struct stat statbuf; - DB *db = 0; - DBC *dbc = 0; - int count = 0; - DBT dbkey; - DBT dbdata; - - snprintf(dbpath, PATH_MAX, "%s%s/Name", state->rootdir ? state->rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); - if (stat(dbpath, &statbuf)) - return 0; - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - if (db_create(&db, state->dbenv, 0)) - { - pool_error(pool, 0, "db_create: %s", strerror(errno)); - return 0; - } - if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - pool_error(pool, 0, "db->open Name: %s", strerror(errno)); - db->close(db, 0); - return 0; - } - if (db->cursor(db, NULL, &dbc, 0)) - { - db->close(db, 0); - pool_error(pool, 0, "db->cursor: %s", strerror(errno)); - return 0; - } - while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) - count += dbdata.size / RPM_INDEX_SIZE; - dbc->c_close(dbc); - db->close(db, 0); - return count; -} + +#ifdef ENABLE_RPMDB + /******************************************************************/ @@ -1518,36 +1385,6 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo) return ido; } -#define COPYDIR_DIRCACHE_SIZE 512 - -static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache); - -static inline Id -copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache) -{ - if (cache && cache[did & 255] == did) - return cache[(did & 255) + 256]; - return copydir_complex(pool, data, fromdata, did, cache); -} - -static Id -copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache) -{ - Id parent = dirpool_parent(&fromdata->dirpool, did); - Id compid = dirpool_compid(&fromdata->dirpool, did); - if (parent) - parent = copydir(pool, data, fromdata, parent, cache); - if (data->localpool || fromdata->localpool) - compid = repodata_translate_id(data, fromdata, compid, 1); - compid = dirpool_add_dir(&data->dirpool, parent, compid, 1); - if (cache) - { - cache[did & 255] = did; - cache[(did & 255) + 256] = compid; - } - return compid; -} - struct solvable_copy_cbdata { Repodata *data; Id handle; @@ -1559,84 +1396,49 @@ static int solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv) { struct solvable_copy_cbdata *cbdata = vcbdata; - Id id, keyname; Repodata *data = cbdata->data; Id handle = cbdata->handle; - Pool *pool = data->repo->pool; - keyname = key->name; - switch(key->type) + switch (key->type) { case REPOKEY_TYPE_ID: case REPOKEY_TYPE_CONSTANTID: case REPOKEY_TYPE_IDARRAY: /* used for triggers */ - id = kv->id; if (data->localpool || fromdata->localpool) - id = repodata_translate_id(data, fromdata, id, 1); - if (key->type == REPOKEY_TYPE_ID) - repodata_set_id(data, handle, keyname, id); - else if (key->type == REPOKEY_TYPE_CONSTANTID) - repodata_set_constantid(data, handle, keyname, id); - else - repodata_add_idarray(data, handle, keyname, id); - break; - case REPOKEY_TYPE_STR: - repodata_set_str(data, handle, keyname, kv->str); - break; - case REPOKEY_TYPE_VOID: - repodata_set_void(data, handle, keyname); - break; - case REPOKEY_TYPE_NUM: - repodata_set_num(data, handle, keyname, SOLV_KV_NUM64(kv)); - break; - case REPOKEY_TYPE_CONSTANT: - repodata_set_constant(data, handle, keyname, kv->num); + kv->id = repodata_translate_id(data, fromdata, kv->id, 1); break; case REPOKEY_TYPE_DIRNUMNUMARRAY: - id = kv->id; - id = copydir(pool, data, fromdata, id, cbdata->dircache); - repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2); - break; case REPOKEY_TYPE_DIRSTRARRAY: - id = kv->id; - id = copydir(pool, data, fromdata, id, cbdata->dircache); - repodata_add_dirstr(data, handle, keyname, id, kv->str); + kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0); break; + case REPOKEY_TYPE_FIXARRAY: + cbdata->handle = repodata_new_handle(data); + repodata_add_fixarray(data, handle, key->name, cbdata->handle); + repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata); + cbdata->handle = handle; + return 0; case REPOKEY_TYPE_FLEXARRAY: - if (kv->eof == 2) - { - assert(cbdata->subhandle); - cbdata->handle = cbdata->subhandle; - cbdata->subhandle = 0; - break; - } - if (!kv->entry) - { - assert(!cbdata->subhandle); - cbdata->subhandle = cbdata->handle; - } cbdata->handle = repodata_new_handle(data); - repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle); - break; + repodata_add_flexarray(data, handle, key->name, cbdata->handle); + repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata); + cbdata->handle = handle; + return 0; default: - if (solv_chksum_len(key->type)) - { - repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str); - break; - } break; } + repodata_set_kv(data, handle, key->name, key->type, kv); return 0; } static void -solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) +solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip) { int p, i; Repo *repo = s->repo; Pool *pool = repo->pool; Repo *fromrepo = r->repo; struct solvable_copy_cbdata cbdata; + Id *keyskip; /* copy solvable data */ s->name = r->name; @@ -1653,23 +1455,26 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) s->enhances = copydeps(pool, repo, r->enhances, fromrepo); /* copy all attributes */ - if (!data) + if (!data || fromrepo->nrepodata < 2) return; cbdata.data = data; cbdata.handle = s - pool->solvables; cbdata.subhandle = 0; cbdata.dircache = dircache; p = r - fromrepo->pool->solvables; -#if 0 - repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata); -#else + if (fromrepo->nrepodata == 2) + { + Repodata *fromdata = repo_id2repodata(fromrepo, 1); + if (p >= fromdata->start && p < fromdata->end) + repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata); + return; + } + keyskip = repo_create_keyskip(repo, p, oldkeyskip); FOR_REPODATAS(fromrepo, i, data) { if (p >= data->start && p < data->end) - repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata); - cbdata.dircache = 0; /* only for first repodata */ + repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata); } -#endif } /* used to sort entries by package name that got returned in some database order */ @@ -1750,7 +1555,6 @@ int repo_add_rpmdb(Repo *repo, Repo *ref, int flags) { Pool *pool = repo->pool; - char dbpath[PATH_MAX]; struct stat packagesstat; unsigned char newcookie[32]; const unsigned char *oldcookie = 0; @@ -1784,10 +1588,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) } /* XXX: should get ro lock of Packages database! */ - snprintf(dbpath, PATH_MAX, "%s%s/Packages", state.rootdir ? state.rootdir : "", state.is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); - if (stat(dbpath, &packagesstat)) + if (stat_database(&state, "Packages", &packagesstat, 1)) { - pool_error(pool, -1, "%s: %s", dbpath, strerror(errno)); freestate(&state); return -1; } @@ -1800,7 +1602,6 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) { int solvstart = 0, solvend = 0; Id dbid; - DBC *dbc = 0; if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0) repo_empty(ref, 1); /* get it out of the way */ @@ -1811,18 +1612,18 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) freestate(&state); return -1; } - if (state.db->cursor(state.db, NULL, &dbc, 0)) + if (pkgdb_cursor_open(&state)) { freestate(&state); - return pool_error(pool, -1, "db->cursor failed"); + return -1; } i = 0; s = 0; - while ((dbid = getrpmcursor(&state, dbc)) != 0) + while ((dbid = pkgdb_cursor_getrpm(&state)) != 0) { if (dbid == -1) { - dbc->c_close(dbc); + pkgdb_cursor_close(&state); freestate(&state); return -1; } @@ -1836,7 +1637,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; - if (rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS)) + if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS)) { i++; s = 0; @@ -1856,13 +1657,12 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count); } } - dbc->c_close(dbc); + pkgdb_cursor_close(&state); if (s) { /* oops, could not reuse. free it instead */ - repo_free_solvable(repo, s - pool->solvables, 1); + s = solvable_free(s, 1); solvend--; - s = 0; } /* now sort all solvables in the new solvstart..solvend block */ if (solvend - solvstart > 1) @@ -1885,7 +1685,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) } else { - Id dircache[COPYDIR_DIRCACHE_SIZE]; /* see copydir */ + Id *dircache; + Id *oldkeyskip = 0; struct rpmdbentry *entries = 0, *rp; int nentries = 0; char *namedata = 0; @@ -1893,10 +1694,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) Id id, *refhash; int res; - memset(dircache, 0, sizeof(dircache)); - /* get ids of installed rpms */ - entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata); + entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY); if (!entries) { freestate(&state); @@ -1949,10 +1748,11 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); + dircache = repodata_create_dirtranscache(data); for (i = 0, rp = entries; i < nentries; i++, rp++, s++) { Id dbid = rp->rpmdbid; - repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->rpmdbid; + repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; if (refhash) { h = dbid & refmask; @@ -1967,12 +1767,12 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) Solvable *r = ref->pool->solvables + ref->start + (id - 1); if (r->repo == ref) { - solvable_copy(s, r, data, dircache); + solvable_copy(s, r, data, dircache, &oldkeyskip); continue; } } } - res = getrpmdbid(&state, dbid); + res = getrpm_dbid(&state, dbid); if (res <= 0) { if (!res) @@ -1981,9 +1781,10 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) solv_free(entries); solv_free(namedata); solv_free(refhash); + dircache = repodata_free_dirtranscache(dircache); return -1; } - rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS); + rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS); if ((flags & RPMDB_REPORT_PROGRESS) != 0) { if (done < count) @@ -1992,7 +1793,9 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count); } } + dircache = repodata_free_dirtranscache(dircache); + solv_free(oldkeyskip); solv_free(entries); solv_free(namedata); solv_free(refhash); @@ -2038,21 +1841,15 @@ repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags) return res; } -static inline unsigned int -getu32(const unsigned char *dp) -{ - return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3]; -} - +#endif /* ENABLE_RPMDB */ Id repo_add_rpm(Repo *repo, const char *rpm, int flags) { - unsigned int sigdsize, sigcnt, l; + unsigned int sigdsize, sigcnt, sigpad, l; Pool *pool = repo->pool; Solvable *s; - RpmHead *rpmhead = 0; - int rpmheadsize = 0; + struct rpmdbstate state; char *payloadformat; FILE *fp; unsigned char lead[4096]; @@ -2066,7 +1863,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) Id chksumtype = 0; Chksum *chksumh = 0; Chksum *leadsigchksumh = 0; - int forcebinary = 0; data = repo_add_repodata(repo, flags); @@ -2075,6 +1871,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0) chksumtype = REPOKEY_TYPE_SHA1; + /* open rpm */ if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0) { pool_error(pool, -1, "%s: %s", rpm, strerror(errno)); @@ -2086,6 +1883,12 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) fclose(fp); return 0; } + + /* setup state */ + memset(&state, 0, sizeof(state)); + state.pool = pool; + + /* process lead */ if (chksumtype) chksumh = solv_chksum_create(chksumtype); if ((flags & RPM_ADD_WITH_LEADSIGID) != 0) @@ -2096,11 +1899,12 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) fclose(fp); return 0; } - forcebinary = lead[6] != 0 || lead[7] != 1; if (chksumh) solv_chksum_add(chksumh, lead, 96 + 16); if (leadsigchksumh) solv_chksum_add(leadsigchksumh, lead, 96 + 16); + + /* process signature header */ if (lead[78] != 0 || lead[79] != 5) { pool_error(pool, -1, "%s: not a rpm v5 header", rpm); @@ -2115,43 +1919,27 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } sigcnt = getu32(lead + 96 + 8); sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x100000) + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) { pool_error(pool, -1, "%s: bad signature header", rpm); fclose(fp); return 0; } - sigdsize += sigcnt * 16; - sigdsize = (sigdsize + 7) & ~7; - headerstart = 96 + 16 + sigdsize; + sigpad = sigdsize & 7 ? 8 - (sigdsize & 7) : 0; + headerstart = 96 + 16 + sigcnt * 16 + sigdsize + sigpad; pkgidtype = leadsigidtype = hdridtype = 0; if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0) { - /* extract pkgid or hdrid from the signature header */ - if (sigdsize > rpmheadsize) + if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh)) { - rpmheadsize = sigdsize + 128; - rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - if (fread(rpmhead->data, sigdsize, 1, fp) != 1) - { - pool_error(pool, -1, "%s: unexpected EOF", rpm); fclose(fp); return 0; } - if (chksumh) - solv_chksum_add(chksumh, rpmhead->data, sigdsize); - if (leadsigchksumh) - solv_chksum_add(leadsigchksumh, rpmhead->data, sigdsize); - rpmhead->forcebinary = 0; - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize - sigcnt * 16; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; if ((flags & RPM_ADD_WITH_PKGID) != 0) { unsigned char *chksum; unsigned int chksumsize; - chksum = headbinary(rpmhead, SIGTAG_MD5, &chksumsize); + chksum = headbinary(state.rpmhead, SIGTAG_MD5, &chksumsize); if (chksum && chksumsize == 16) { pkgidtype = REPOKEY_TYPE_MD5; @@ -2160,7 +1948,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } if ((flags & RPM_ADD_WITH_HDRID) != 0) { - const char *str = headstring(rpmhead, TAG_SHA1HEADER); + const char *str = headstring(state.rpmhead, TAG_SHA1HEADER); if (str && strlen(str) == 40) { if (solv_hex2bin(&str, hdrid, 20) == 20) @@ -2176,9 +1964,10 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) else { /* just skip the signature header */ - while (sigdsize) + unsigned int len = sigcnt * 16 + sigdsize + sigpad; + while (len) { - l = sigdsize > 4096 ? 4096 : sigdsize; + l = len > 4096 ? 4096 : len; if (fread(lead, l, 1, fp) != 1) { pool_error(pool, -1, "%s: unexpected EOF", rpm); @@ -2189,7 +1978,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) solv_chksum_add(chksumh, lead, l); if (leadsigchksumh) solv_chksum_add(leadsigchksumh, lead, l); - sigdsize -= l; + len -= l; } } if (leadsigchksumh) @@ -2197,6 +1986,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid); leadsigidtype = REPOKEY_TYPE_MD5; } + + /* process main header */ if (fread(lead, 16, 1, fp) != 1) { pool_error(pool, -1, "%s: unexpected EOF", rpm); @@ -2213,48 +2004,36 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } sigcnt = getu32(lead + 8); sigdsize = getu32(lead + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x2000000) + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) { pool_error(pool, -1, "%s: bad header", rpm); fclose(fp); return 0; } - l = sigdsize + sigcnt * 16; - headerend = headerstart + 16 + l; - if (l > rpmheadsize) - { - rpmheadsize = l + 128; - rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - if (fread(rpmhead->data, l, 1, fp) != 1) + headerend = headerstart + 16 + sigdsize + sigcnt * 16; + + if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0)) { - pool_error(pool, -1, "%s: unexpected EOF", rpm); fclose(fp); return 0; } - if (chksumh) - solv_chksum_add(chksumh, rpmhead->data, l); - rpmhead->forcebinary = forcebinary; - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - if (headexists(rpmhead, TAG_PATCHESNAME)) + if (headexists(state.rpmhead, TAG_PATCHESNAME)) { /* this is a patch rpm, ignore */ pool_error(pool, -1, "%s: is patch rpm", rpm); fclose(fp); solv_chksum_free(chksumh, 0); - solv_free(rpmhead); + headfree(state.rpmhead); return 0; } - payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT); + payloadformat = headstring(state.rpmhead, TAG_PAYLOADFORMAT); if (payloadformat && !strcmp(payloadformat, "drpm")) { /* this is a delta rpm */ pool_error(pool, -1, "%s: is delta rpm", rpm); fclose(fp); solv_chksum_free(chksumh, 0); - solv_free(rpmhead); + headfree(state.rpmhead); return 0; } if (chksumh) @@ -2262,11 +2041,11 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) solv_chksum_add(chksumh, lead, l); fclose(fp); s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!rpm2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID))) + if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID))) { - repo_free_solvable(repo, s - pool->solvables, 1); + s = solvable_free(s, 1); solv_chksum_free(chksumh, 0); - solv_free(rpmhead); + headfree(state.rpmhead); return 0; } if (!(flags & REPO_NO_LOCATION)) @@ -2285,7 +2064,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0)); chksumh = solv_chksum_free(chksumh, 0); } - solv_free(rpmhead); + headfree(state.rpmhead); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); return s - pool->solvables; @@ -2314,9 +2093,9 @@ repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags) return 0; } s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!rpm2solv(pool, repo, data, s, rpmhead, flags)) + if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags)) { - repo_free_solvable(repo, s - pool->solvables, 1); + s = solvable_free(s, 1); return 0; } if (!(flags & REPO_NO_INTERNALIZE)) @@ -2345,12 +2124,12 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * char **dn; char **md = 0; char **lt = 0; - unsigned int *di, diidx; - unsigned int *co = 0; - unsigned int *ff = 0; + uint32_t *di, diidx; + uint32_t *co = 0; + uint32_t *ff = 0; + uint16_t *fm; unsigned int lastdir; int lastdirl; - unsigned int *fm; int cnt, dcnt, cnt2; int i, l1, l; char *space = 0; @@ -2407,7 +2186,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0) { co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2); - if (!co || cnt != cnt2) + if (co && cnt != cnt2) { solv_free(co); solv_free(md); @@ -2485,8 +2264,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * info.digest = md5; } } - if (co) - info.color = co[i]; + info.color = co ? co[i] : 0; (*cb)(cbdata, space, &info); } solv_free(space); @@ -2511,12 +2289,12 @@ rpm_query(void *rpmhandle, Id what) r = 0; switch (what) { - case 0: + case 0: /* return canonical name of rpm */ name = headstring(rpmhead, TAG_NAME); if (!name) name = ""; sourcerpm = headstring(rpmhead, TAG_SOURCERPM); - if (sourcerpm || (rpmhead->forcebinary && !headexists(rpmhead, TAG_SOURCEPACKAGE))) + if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead))) arch = headstring(rpmhead, TAG_ARCH); else { @@ -2567,13 +2345,15 @@ rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound) return notfound; } +#ifdef ENABLE_RPMDB + int rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq) { struct rpmdbentry *entries; int nentries, i; - entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0); + entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0, 0); if (rpmdbidq) { queue_empty(rpmdbidq); @@ -2590,33 +2370,33 @@ rpm_byrpmdbid(void *rpmstate, Id rpmdbid) struct rpmdbstate *state = rpmstate; int r; - r = getrpmdbid(state, rpmdbid); + r = getrpm_dbid(state, rpmdbid); if (!r) pool_error(state->pool, 0, "header #%d not in database", rpmdbid); return r <= 0 ? 0 : state->rpmhead; } +#endif /* ENABLE_RPMDB */ + void * rpm_byfp(void *rpmstate, FILE *fp, const char *name) { struct rpmdbstate *state = rpmstate; - /* int headerstart, headerend; */ - RpmHead *rpmhead; unsigned int sigdsize, sigcnt, l; unsigned char lead[4096]; - int forcebinary = 0; if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb) { pool_error(state->pool, 0, "%s: not a rpm", name); return 0; } - forcebinary = lead[6] != 0 || lead[7] != 1; if (lead[78] != 0 || lead[79] != 5) { pool_error(state->pool, 0, "%s: not a V5 header", name); return 0; } + + /* skip signature header */ if (getu32(lead + 96) != 0x8eade801) { pool_error(state->pool, 0, "%s: bad signature header", name); @@ -2624,14 +2404,13 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) } sigcnt = getu32(lead + 96 + 8); sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x100000) + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) { pool_error(state->pool, 0, "%s: bad signature header", name); return 0; } sigdsize += sigcnt * 16; sigdsize = (sigdsize + 7) & ~7; - /* headerstart = 96 + 16 + sigdsize; */ while (sigdsize) { l = sigdsize > 4096 ? 4096 : sigdsize; @@ -2642,6 +2421,7 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) } sigdsize -= l; } + if (fread(lead, 16, 1, fp) != 1) { pool_error(state->pool, 0, "%s: unexpected EOF", name); @@ -2654,41 +2434,28 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) } sigcnt = getu32(lead + 8); sigdsize = getu32(lead + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x2000000) + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) { pool_error(state->pool, 0, "%s: bad header", name); return 0; } - l = sigdsize + sigcnt * 16; - /* headerend = headerstart + 16 + l; */ - if (l > state->rpmheadsize) - { - state->rpmheadsize = l + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - if (fread(rpmhead->data, l, 1, fp) != 1) - { - pool_error(state->pool, 0, "%s: unexpected EOF", name); - return 0; - } - rpmhead->forcebinary = forcebinary; - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return rpmhead; + if (!headfromfp(state, name, fp, lead, sigcnt, sigdsize, 0, 0, 0)) + return 0; + return state->rpmhead; } -#ifdef ENABLE_RPMDB_BYRPMHEADER +#if defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) void * rpm_byrpmh(void *rpmstate, Header h) { struct rpmdbstate *state = rpmstate; +#ifndef ENABLE_RPMPKG_LIBRPM const unsigned char *uh; - unsigned int sigdsize, sigcnt, l; - RpmHead *rpmhead; + unsigned int dsize, cnt; + if (!h) + return 0; #ifndef RPM5 uh = headerUnload(h); #else @@ -2696,23 +2463,24 @@ rpm_byrpmh(void *rpmstate, Header h) #endif if (!uh) return 0; - sigcnt = getu32(uh); - sigdsize = getu32(uh + 4); - l = sigdsize + sigcnt * 16; - if (l > state->rpmheadsize) + cnt = getu32(uh); + dsize = getu32(uh + 4); + if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE) { - state->rpmheadsize = l + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); + free((void *)uh); + return 0; } - rpmhead = state->rpmhead; - memcpy(rpmhead->data, uh + 8, l - 8); + headfromblob(state, uh + 8, cnt, dsize); free((void *)uh); - rpmhead->forcebinary = 0; - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return rpmhead; +#else + if (!h) + return 0; + if (state->rpmhead) + headfree(state->rpmhead); + state->rpmhead = headerLink(h); +#endif + return state->rpmhead; } -#endif +#endif /* defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) */ diff --git a/libsolv-0.6.15/ext/repo_rpmdb.h b/libsolv-0.7.2/ext/repo_rpmdb.h similarity index 98% rename from libsolv-0.6.15/ext/repo_rpmdb.h rename to libsolv-0.7.2/ext/repo_rpmdb.h index 9e3bd0d..554d48a 100644 --- a/libsolv-0.6.15/ext/repo_rpmdb.h +++ b/libsolv-0.7.2/ext/repo_rpmdb.h @@ -25,6 +25,7 @@ extern Id repo_add_rpm(Repo *repo, const char *rpm, int flags); #define RPM_ADD_WITH_LEADSIGID (1 << 16) #define RPM_ADD_WITH_CHANGELOG (1 << 17) #define RPM_ADD_FILTERED_FILELIST (1 << 18) +#define RPMDB_KEEP_GPG_PUBKEY (1 << 19) #define RPMDB_EMPTY_REFREPO (1 << 30) /* internal */ diff --git a/libsolv-0.7.2/ext/repo_rpmdb_bdb.h b/libsolv-0.7.2/ext/repo_rpmdb_bdb.h new file mode 100644 index 0000000..ed82a69 --- /dev/null +++ b/libsolv-0.7.2/ext/repo_rpmdb_bdb.h @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2018 SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repo_rpmdb_bdb.h + * + * Use BerkeleyDB to access the rpm database + * + */ + + +#if !defined(DB_CREATE) && !defined(ENABLE_RPMDB_LIBRPM) +# if defined(SUSE) || defined(HAVE_RPM_DB_H) +# include +# else +# include +# endif +#endif + +#ifdef RPM5 +# define RPM_INDEX_SIZE 4 /* just the rpmdbid */ +#else +# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */ +#endif + + +/******************************************************************/ +/* Rpm Database stuff + */ + +struct rpmdbstate { + Pool *pool; + char *rootdir; + + RpmHead *rpmhead; /* header storage space */ + int rpmheadsize; + + int dbenvopened; /* database environment opened */ + int pkgdbopened; /* package database openend */ + int is_ostree; /* read-only db that lives in /usr/share/rpm */ + + DB_ENV *dbenv; /* database environment */ + DB *db; /* packages database */ + int byteswapped; /* endianess of packages database */ + DBC *dbc; /* iterator over packages database */ +}; + + +static int +stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror) +{ + char *dbpath; + dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname); + if (stat(dbpath, statbuf)) + { + if (seterror) + pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno)); + free(dbpath); + return -1; + } + free(dbpath); + return 0; +} + + +static inline Id +db2rpmdbid(unsigned char *db, int byteswapped) +{ +#ifdef RPM5 + return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; +#else +# if defined(WORDS_BIGENDIAN) + if (!byteswapped) +# else + if (byteswapped) +# endif + return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; + else + return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0]; +#endif +} + +static inline void +rpmdbid2db(unsigned char *db, Id id, int byteswapped) +{ +#ifdef RPM5 + db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; +#else +# if defined(WORDS_BIGENDIAN) + if (!byteswapped) +# else + if (byteswapped) +# endif + db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; + else + db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id; +#endif +} + +#if defined(FEDORA) || defined(MAGEIA) +static int +serialize_dbenv_ops(struct rpmdbstate *state) +{ + char *lpath; + mode_t oldmask; + int fd; + struct flock fl; + + lpath = solv_dupjoin(state->rootdir, "/var/lib/rpm/.dbenv.lock", 0); + oldmask = umask(022); + fd = open(lpath, (O_RDWR|O_CREAT), 0644); + free(lpath); + umask(oldmask); + if (fd < 0) + return -1; + memset(&fl, 0, sizeof(fl)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + for (;;) + { + if (fcntl(fd, F_SETLKW, &fl) != -1) + return fd; + if (errno != EINTR) + break; + } + close(fd); + return -1; +} + +#endif + +/* should look in /usr/lib/rpm/macros instead, but we want speed... */ +static int +opendbenv(struct rpmdbstate *state) +{ + const char *rootdir = state->rootdir; + char *dbpath; + DB_ENV *dbenv = 0; + int r; + + if (db_env_create(&dbenv, 0)) + return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno)); +#if (defined(FEDORA) || defined(MAGEIA)) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)) + dbenv->set_thread_count(dbenv, 8); +#endif + dbpath = solv_dupjoin(rootdir, "/var/lib/rpm", 0); + if (access(dbpath, W_OK) == -1) + { + free(dbpath); + dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0); + if (access(dbpath, R_OK) == 0) + state->is_ostree = 1; + free(dbpath); + dbpath = solv_dupjoin(rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm", 0); + r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); + } + else + { +#if defined(FEDORA) || defined(MAGEIA) + int serialize_fd = serialize_dbenv_ops(state); + int eflags = DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL; + r = dbenv->open(dbenv, dbpath, eflags, 0644); + /* see rpm commit 2822ccbcdf3e898b960fafb23c4d571e26cef0a4 */ + if (r == DB_VERSION_MISMATCH) + { + eflags |= DB_PRIVATE; + dbenv->errx(dbenv, "warning: DB_VERSION_MISMATCH, retrying with DB_PRIVATE"); + r = dbenv->open(dbenv, dbpath, eflags, 0644); + } + if (serialize_fd >= 0) + close(serialize_fd); +#else + r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); +#endif + } + if (r) + { + pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno)); + free(dbpath); + dbenv->close(dbenv, 0); + return 0; + } + free(dbpath); + state->dbenv = dbenv; + state->dbenvopened = 1; + return 1; +} + +static void +closedbenv(struct rpmdbstate *state) +{ +#if defined(FEDORA) || defined(MAGEIA) + uint32_t eflags = 0; +#endif + + if (!state->dbenv) + return; +#if defined(FEDORA) || defined(MAGEIA) + (void)state->dbenv->get_open_flags(state->dbenv, &eflags); + if (!(eflags & DB_PRIVATE)) + { + int serialize_fd = serialize_dbenv_ops(state); + state->dbenv->close(state->dbenv, 0); + if (serialize_fd >= 0) + close(serialize_fd); + } + else + state->dbenv->close(state->dbenv, 0); +#else + state->dbenv->close(state->dbenv, 0); +#endif + state->dbenv = 0; + state->dbenvopened = 0; +} + +static int +openpkgdb(struct rpmdbstate *state) +{ + if (state->pkgdbopened) + return state->pkgdbopened > 0 ? 1 : 0; + state->pkgdbopened = -1; + if (state->dbenvopened != 1 && !opendbenv(state)) + return 0; + if (db_create(&state->db, state->dbenv, 0)) + { + pool_error(state->pool, 0, "db_create: %s", strerror(errno)); + state->db = 0; + closedbenv(state); + return 0; + } + if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) + { + pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno)); + state->db->close(state->db, 0); + state->db = 0; + closedbenv(state); + return 0; + } + if (state->db->get_byteswapped(state->db, &state->byteswapped)) + { + pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno)); + state->db->close(state->db, 0); + state->db = 0; + closedbenv(state); + return 0; + } + state->pkgdbopened = 1; + return 1; +} + +static void +closepkgdb(struct rpmdbstate *state) +{ + if (!state->db) + return; + state->db->close(state->db, 0); + state->db = 0; + state->pkgdbopened = 0; +} + +/* get the rpmdbids of all installed packages from the Name index database. + * This is much faster then querying the big Packages database */ +static struct rpmdbentry * +getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey) +{ + DB_ENV *dbenv = 0; + DB *db = 0; + DBC *dbc = 0; + int byteswapped; + DBT dbkey; + DBT dbdata; + unsigned char *dp; + int dl; + Id nameoff; + + char *namedata = 0; + int namedatal = 0; + struct rpmdbentry *entries = 0; + int nentries = 0; + + *nentriesp = 0; + if (namedatap) + *namedatap = 0; + + if (state->dbenvopened != 1 && !opendbenv(state)) + return 0; + dbenv = state->dbenv; + if (db_create(&db, dbenv, 0)) + { + pool_error(state->pool, 0, "db_create: %s", strerror(errno)); + return 0; + } + if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664)) + { + pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno)); + db->close(db, 0); + return 0; + } + if (db->get_byteswapped(db, &byteswapped)) + { + pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno)); + db->close(db, 0); + return 0; + } + if (db->cursor(db, NULL, &dbc, 0)) + { + pool_error(state->pool, 0, "db->cursor: %s", strerror(errno)); + db->close(db, 0); + return 0; + } + memset(&dbkey, 0, sizeof(dbkey)); + memset(&dbdata, 0, sizeof(dbdata)); + if (match) + { + dbkey.data = (void *)match; + dbkey.size = strlen(match); + } + while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0) + { + if (!match && !keep_gpg_pubkey && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10)) + continue; + dl = dbdata.size; + dp = dbdata.data; + nameoff = namedatal; + if (namedatap) + { + namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK); + memcpy(namedata + namedatal, dbkey.data, dbkey.size); + namedata[namedatal + dbkey.size] = 0; + namedatal += dbkey.size + 1; + } + while(dl >= RPM_INDEX_SIZE) + { + entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK); + entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped); + entries[nentries].nameoff = nameoff; + nentries++; + dp += RPM_INDEX_SIZE; + dl -= RPM_INDEX_SIZE; + } + if (match) + break; + } + dbc->c_close(dbc); + db->close(db, 0); + /* make sure that enteries is != 0 if there was no error */ + if (!entries) + entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK); + *nentriesp = nentries; + if (namedatap) + *namedatap = namedata; + return entries; +} + +/* common code, return dbid on success, -1 on error */ +static int +getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid) +{ + unsigned int dsize, cnt, l; + RpmHead *rpmhead; + + if (dbdata->size < 8) + return pool_error(state->pool, -1, "corrupt rpm database (size)"); + cnt = getu32((const unsigned char *)dbdata->data); + dsize = getu32((const unsigned char *)dbdata->data + 4); + if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE) + return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)"); + l = cnt * 16 + dsize; + if (8 + l > dbdata->size) + return pool_error(state->pool, -1, "corrupt rpm database (data size)"); + if (l + 1 > state->rpmheadsize) + { + state->rpmheadsize = l + 128; + state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize); + } + rpmhead = state->rpmhead; + rpmhead->cnt = cnt; + rpmhead->dcnt = dsize; + memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l); + rpmhead->data[l] = 0; + rpmhead->dp = rpmhead->data + cnt * 16; + return dbid; +} + +/* retrive header by rpmdbid, returns 0 if not found, -1 on error */ +static int +getrpm_dbid(struct rpmdbstate *state, Id dbid) +{ + unsigned char buf[4]; + DBT dbkey; + DBT dbdata; + + if (dbid <= 0) + return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid); + if (state->pkgdbopened != 1 && !openpkgdb(state)) + return -1; + rpmdbid2db(buf, dbid, state->byteswapped); + memset(&dbkey, 0, sizeof(dbkey)); + memset(&dbdata, 0, sizeof(dbdata)); + dbkey.data = buf; + dbkey.size = 4; + dbdata.data = 0; + dbdata.size = 0; + if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0)) + return 0; + return getrpm_dbdata(state, &dbdata, dbid); +} + +static int +count_headers(struct rpmdbstate *state) +{ + Pool *pool = state->pool; + struct stat statbuf; + DB *db = 0; + DBC *dbc = 0; + int count = 0; + DBT dbkey; + DBT dbdata; + + if (stat_database(state, "Name", &statbuf, 0)) + return 0; + memset(&dbkey, 0, sizeof(dbkey)); + memset(&dbdata, 0, sizeof(dbdata)); + if (db_create(&db, state->dbenv, 0)) + { + pool_error(pool, 0, "db_create: %s", strerror(errno)); + return 0; + } + if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664)) + { + pool_error(pool, 0, "db->open Name: %s", strerror(errno)); + db->close(db, 0); + return 0; + } + if (db->cursor(db, NULL, &dbc, 0)) + { + db->close(db, 0); + pool_error(pool, 0, "db->cursor: %s", strerror(errno)); + return 0; + } + while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) + count += dbdata.size / RPM_INDEX_SIZE; + dbc->c_close(dbc); + db->close(db, 0); + return count; +} + +static int +pkgdb_cursor_open(struct rpmdbstate *state) +{ + if (state->db->cursor(state->db, NULL, &state->dbc, 0)) + return pool_error(state->pool, -1, "db->cursor failed"); + return 0; +} + +static void +pkgdb_cursor_close(struct rpmdbstate *state) +{ + state->dbc->c_close(state->dbc); + state->dbc = 0; +} + +/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */ +static Id +pkgdb_cursor_getrpm(struct rpmdbstate *state) +{ + DBT dbkey; + DBT dbdata; + Id dbid; + + memset(&dbkey, 0, sizeof(dbkey)); + memset(&dbdata, 0, sizeof(dbdata)); + while (state->dbc->c_get(state->dbc, &dbkey, &dbdata, DB_NEXT) == 0) + { + if (dbkey.size != 4) + return pool_error(state->pool, -1, "corrupt Packages database (key size)"); + dbid = db2rpmdbid(dbkey.data, state->byteswapped); + if (dbid) /* ignore join key */ + return getrpm_dbdata(state, &dbdata, dbid); + } + return 0; /* no more entries */ +} + diff --git a/libsolv-0.7.2/ext/repo_rpmdb_librpm.h b/libsolv-0.7.2/ext/repo_rpmdb_librpm.h new file mode 100644 index 0000000..79983d3 --- /dev/null +++ b/libsolv-0.7.2/ext/repo_rpmdb_librpm.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2018, SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repo_rpmdb_librpm.h + * + * Use librpm to access the rpm database + * + */ + +#include +#include + +struct rpmdbstate { + Pool *pool; + char *rootdir; + + RpmHead *rpmhead; /* header storage space */ + int rpmheadsize; + + int dbenvopened; /* database environment opened */ + int pkgdbopened; /* package database openend */ + int is_ostree; /* read-only db that lives in /usr/share/rpm */ + + rpmts ts; + rpmdbMatchIterator mi; /* iterator over packages database */ +}; + +static int +stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror) +{ + char *dbpath; + dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname); + if (stat(dbpath, statbuf)) + { + if (seterror) + pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno)); + free(dbpath); + return -1; + } + free(dbpath); + return 0; +} + +static int +opendbenv(struct rpmdbstate *state) +{ + const char *rootdir = state->rootdir; + rpmts ts; + char *dbpath; + dbpath = solv_dupjoin("_dbpath ", rootdir, "/var/lib/rpm"); + if (access(dbpath + 8, W_OK) == -1) + { + free(dbpath); + dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0); + if (access(dbpath, R_OK) == 0) + state->is_ostree = 1; + free(dbpath); + dbpath = solv_dupjoin("_dbpath ", rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); + } + rpmDefineMacro(NULL, dbpath, 0); + solv_free(dbpath); + ts = rpmtsCreate(); + if (!ts) + { + pool_error(state->pool, 0, "rpmtsCreate failed"); + delMacro(NULL, "_dbpath"); + return 0; + } + if (rpmtsOpenDB(ts, O_RDONLY)) + { + pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno)); + rpmtsFree(ts); + delMacro(NULL, "_dbpath"); + return 0; + } + delMacro(NULL, "_dbpath"); + rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER); + state->ts = ts; + state->dbenvopened = 1; + state->pkgdbopened = 1; + return 1; +} + +static void +closedbenv(struct rpmdbstate *state) +{ + if (state->ts) + rpmtsFree(state->ts); + state->ts = 0; + state->pkgdbopened = 0; + state->dbenvopened = 0; +} + +static int +openpkgdb(struct rpmdbstate *state) +{ + /* already done in opendbenv */ + return 1; +} + +static void +closepkgdb(struct rpmdbstate *state) +{ +} + +/* get the rpmdbids of all installed packages from the Name index database. + * This is much faster then querying the big Packages database */ +static struct rpmdbentry * +getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey) +{ + const void * key; + size_t keylen, matchl = 0; + Id nameoff; + + char *namedata = 0; + int namedatal = 0; + struct rpmdbentry *entries = 0; + int nentries = 0; + + rpmdbIndexIterator ii; + int i; + + *nentriesp = 0; + if (namedatap) + *namedatap = 0; + + if (state->dbenvopened != 1 && !opendbenv(state)) + return 0; + + if (match) + matchl = strlen(match); + ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME); + + while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0) + { + if (match) + { + if (keylen != matchl || memcmp(key, match, keylen) != 0) + continue; + } + else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10)) + continue; + nameoff = namedatal; + if (namedatap) + { + namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK); + memcpy(namedata + namedatal, key, keylen); + namedata[namedatal + keylen] = 0; + namedatal += keylen + 1; + } + for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) + { + entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK); + entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i); + entries[nentries].nameoff = nameoff; + nentries++; + } + } + rpmdbIndexIteratorFree(ii); + /* make sure that enteries is != 0 if there was no error */ + if (!entries) + entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK); + *nentriesp = nentries; + if (namedatap) + *namedatap = namedata; + return entries; +} + +/* retrive header by rpmdbid, returns 0 if not found, -1 on error */ +static int +getrpm_dbid(struct rpmdbstate *state, Id rpmdbid) +{ + Header h; + rpmdbMatchIterator mi; + unsigned int offset = rpmdbid; + + if (state->dbenvopened != 1 && !opendbenv(state)) + return -1; + mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, &offset, sizeof(offset)); + h = rpmdbNextIterator(mi); + if (!h) + { + rpmdbFreeIterator(mi); + return 0; + } + if (!rpm_byrpmh(state, h)) + { + rpmdbFreeIterator(mi); + return -1; + } + mi = rpmdbFreeIterator(mi); + return 1; +} + +static int +count_headers(struct rpmdbstate *state) +{ + int count; + rpmdbMatchIterator mi; + + if (state->dbenvopened != 1 && !opendbenv(state)) + return 0; + mi = rpmtsInitIterator(state->ts, RPMDBI_NAME, NULL, 0); + count = rpmdbGetIteratorCount(mi); + rpmdbFreeIterator(mi); + return count; +} + +static int +pkgdb_cursor_open(struct rpmdbstate *state) +{ + state->mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, NULL, 0); + return 0; +} + +static void +pkgdb_cursor_close(struct rpmdbstate *state) +{ + rpmdbFreeIterator(state->mi); + state->mi = 0; +} + +static Id +pkgdb_cursor_getrpm(struct rpmdbstate *state) +{ + Header h; + while ((h = rpmdbNextIterator(state->mi))) + { + Id dbid = rpmdbGetIteratorOffset(state->mi); + if (!rpm_byrpmh(state, h)) + continue; + return dbid; + } + return 0; +} + diff --git a/libsolv-0.6.15/ext/repo_rpmmd.c b/libsolv-0.7.2/ext/repo_rpmmd.c similarity index 64% rename from libsolv-0.6.15/ext/repo_rpmmd.c rename to libsolv-0.7.2/ext/repo_rpmmd.c index 4272b6f..9bb50a0 100644 --- a/libsolv-0.6.15/ext/repo_rpmmd.c +++ b/libsolv-0.7.2/ext/repo_rpmmd.c @@ -6,12 +6,9 @@ */ #include -#include -#include #include #include #include -#include #include "pool.h" #include "repo.h" @@ -19,9 +16,11 @@ #include "tools_util.h" #include "repo_rpmmd.h" #include "chksum.h" +#include "solv_xmlparser.h" #ifdef ENABLE_COMPLEX_DEPS #include "pool_parserpmrichdep.h" #endif +#include "repodata_diskusage.h" enum state { STATE_START, @@ -85,8 +84,7 @@ enum state { STATE_OPTIONALURL, STATE_FLAG, - /* rpm-md dependencies inside the - format tag */ + /* rpm-md dependencies inside the format tag */ STATE_PROVIDES, STATE_REQUIRES, STATE_OBSOLETES, @@ -117,18 +115,13 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - -static struct stateswitch stateswitches[] = { - /** fake tag used to enclose 2 different xml files in one **/ +static struct solv_xmlparser_element stateswitches[] = { + /** fake tag used to enclose multiple xml files in one **/ { STATE_START, "rpmmd", STATE_START, 0 }, - /** tags for different package data, we just ignore the tag **/ + /** tags for different package data, just ignore them **/ + { STATE_START, "patterns", STATE_START, 0 }, + { STATE_START, "products", STATE_START, 0 }, { STATE_START, "metadata", STATE_START, 0 }, { STATE_START, "otherdata", STATE_START, 0 }, { STATE_START, "filelists", STATE_START, 0 }, @@ -140,6 +133,8 @@ static struct stateswitch stateswitches[] = { { STATE_START, "patch", STATE_SOLVABLE, 0 }, { STATE_START, "package", STATE_SOLVABLE, 0 }, + { STATE_SOLVABLE, "format", STATE_SOLVABLE, 0 }, + { STATE_SOLVABLE, "name", STATE_NAME, 1 }, { STATE_SOLVABLE, "arch", STATE_ARCH, 1 }, { STATE_SOLVABLE, "version", STATE_VERSION, 0 }, @@ -230,25 +225,16 @@ struct parsedata { Repo *repo; Repodata *data; char *kind; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Solvable *solvable; Offset freshens; - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; + + struct solv_xmlparser xmlp; struct joindata jd; /* temporal to store attribute tag language */ const char *tmplang; Id chksumtype; Id handle; - XML_Parser *parser; - Id (*dirs)[3]; /* dirid, size, nfiles */ - int ndirs; + Queue diskusageq; const char *language; /* default language */ Id langcache[ID_NUM_INTERNAL]; /* cache for the default language */ @@ -258,12 +244,15 @@ struct parsedata { Id changelog_handle; - /** Hash to maps checksums to solv */ - Stringpool cspool; - /** Cache of known checksums to solvable id */ - Id *cscache; - /* the current longest index in the table */ - int ncscache; + int extending; /* are we extending an existing solvable? */ + int first; /* first solvable we added */ + int cshash_filled; /* hash is filled with data */ + + Hashtable cshash; /* checksum hash -> offset into csdata */ + Hashval cshashm; /* hash mask */ + int ncshash; /* entries used */ + unsigned char *csdata; /* [len, checksum, id] */ + int ncsdata; /* used bytes */ }; static Id @@ -284,74 +273,6 @@ langtag(struct parsedata *pd, Id tag, const char *language) return pd->langcache[tag]; } -static int -id3_cmp (const void *v1, const void *v2, void *dp) -{ - Id *i1 = (Id*)v1; - Id *i2 = (Id*)v2; - return i1[0] - i2[0]; -} - -static void -commit_diskusage (struct parsedata *pd, Id handle) -{ - int i; - Dirpool *dp = &pd->data->dirpool; - /* Now sort in dirid order. This ensures that parents come before - their children. */ - if (pd->ndirs > 1) - solv_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0); - /* Substract leaf numbers from all parents to make the numbers - non-cumulative. This must be done post-order (i.e. all leafs - adjusted before parents). We ensure this by starting at the end of - the array moving to the start, hence seeing leafs before parents. */ - for (i = pd->ndirs; i--;) - { - Id p = dirpool_parent(dp, pd->dirs[i][0]); - int j = i; - for (; p; p = dirpool_parent(dp, p)) - { - for (; j--;) - if (pd->dirs[j][0] == p) - break; - if (j >= 0) - { - if (pd->dirs[j][1] < pd->dirs[i][1]) - pd->dirs[j][1] = 0; - else - pd->dirs[j][1] -= pd->dirs[i][1]; - if (pd->dirs[j][2] < pd->dirs[i][2]) - pd->dirs[j][2] = 0; - else - pd->dirs[j][2] -= pd->dirs[i][2]; - } - else - /* Haven't found this parent in the list, look further if - we maybe find the parents parent. */ - j = i; - } - } -#if 0 - char sbuf[1024]; - char *buf = sbuf; - unsigned slen = sizeof (sbuf); - for (i = 0; i < pd->ndirs; i++) - { - dir2str (attr, pd->dirs[i][0], &buf, &slen); - fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf); - } - if (buf != sbuf) - free (buf); -#endif - for (i = 0; i < pd->ndirs; i++) - if (pd->dirs[i][1] || pd->dirs[i][2]) - { - repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]); - } - pd->ndirs = 0; -} - - /* * makeevr_atts * parse 'epoch', 'ver' and 'rel', return evr Id @@ -362,7 +283,7 @@ static Id makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) { const char *e, *v, *r, *v2; - char *c; + char *c, *space; int l; e = v = r = 0; @@ -391,12 +312,7 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) l += strlen(v); if (r) l += strlen(r) + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content; + c = space = solv_xmlparser_contentspace(&pd->xmlp, l); if (e) { strcpy(c, e); @@ -415,33 +331,12 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) c += strlen(c); } *c = 0; - if (!*pd->content) + if (!*space) return 0; #if 0 - fprintf(stderr, "evr: %s\n", pd->content); + fprintf(stderr, "evr: %s\n", space); #endif - return pool_str2id(pool, pd->content, 1); -} - - -/* - * find_attr - * find value for xml attribute - * I: txt, name of attribute - * I: atts, list of key/value attributes - * O: pointer to value of matching key, or NULL - * - */ - -static inline const char * -find_attr(const char *txt, const char **atts) -{ - for (; *atts; atts += 2) - { - if (!strcmp(*atts, txt)) - return atts[1]; - } - return 0; + return pool_str2id(pool, space, 1); } @@ -492,13 +387,9 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts if (k) { int l = strlen(k) + 1 + strlen(n) + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - sprintf(pd->content, "%s:%s", k, n); - id = pool_str2id(pool, pd->content, 1); + char *space = solv_xmlparser_contentspace(&pd->xmlp, l); + sprintf(space, "%s:%s", k, n); + id = pool_str2id(pool, space, 1); } #ifdef ENABLE_COMPLEX_DEPS else if (!f && n[0] == '(') @@ -577,67 +468,177 @@ set_description_author(Repodata *data, Id handle, char *str, struct parsedata *p /*-----------------------------------------------*/ -/* XML callbacks */ - -/* - * startElement - * XML callback +/* checksum hash functions + * + * used to look up a solvable with the checksum for solvable extension purposes. * */ -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +init_cshash(struct parsedata *pd) +{ +} + +static void +free_cshash(struct parsedata *pd) { - struct parsedata *pd = userData; - Pool *pool = pd->pool; - Solvable *s = pd->solvable; - struct stateswitch *sw; - const char *str; - Id handle = pd->handle; - const char *pkgid; + pd->cshash = solv_free(pd->cshash); + pd->ncshash = 0; + pd->cshashm = 0; + pd->csdata = solv_free(pd->csdata); + pd->ncsdata = 0; +} - /* fprintf(stderr, "into %s, from %d, depth %d, statedepth %d\n", name, pd->state, pd->depth, pd->statedepth); */ +static inline Hashval +hashkey(const unsigned char *key, int keyl) +{ + return key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; +} - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } +static void +rebuild_cshash(struct parsedata *pd) +{ + Hashval h, hh, hm; + Hashtable ht; + unsigned char *d, *de; - if (pd->state == STATE_START && !strcmp(name, "patterns")) - return; - if (pd->state == STATE_START && !strcmp(name, "products")) - return; + hm = pd->cshashm; #if 0 - if (pd->state == STATE_START && !strcmp(name, "metadata")) - return; + fprintf(stderr, "rebuild cshash with mask 0x%x\n", hm); #endif - if (pd->state == STATE_SOLVABLE && !strcmp(name, "format")) - return; + solv_free(pd->cshash); + ht = pd->cshash = (Hashtable)solv_calloc(hm + 1, sizeof(Id)); + d = pd->csdata; + de = d + pd->ncsdata; + while (d != de) + { + h = hashkey(d + 1, d[0] + 1) & hm; + hh = HASHCHAIN_START; + while (ht[h]) + h = HASHCHAIN_NEXT(h, hh, hm); + ht[h] = d + 1 - pd->csdata; + d += 2 + d[0] + sizeof(Id); + } +} + +static void +put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id) +{ + Hashtable ht; + Hashval h, hh, hm; + unsigned char *d; - pd->depth++; - if (!pd->swtab[pd->state]) + if (keyl < 4 || keyl > 256) return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) - if (!strcmp(sw->ename, name)) - break; - if (sw->from != pd->state) + ht = pd->cshash; + hm = pd->cshashm; + h = hashkey(key, keyl) & hm; + hh = HASHCHAIN_START; + if (ht) { -#if 0 - fprintf(stderr, "into unknown: %s\n", name); -#endif - return; + while (ht[h]) + { + unsigned char *d = pd->csdata + ht[h]; + if (d[-1] == keyl - 1 && !memcmp(key, d, keyl)) + return; /* XXX: first id wins... */ + h = HASHCHAIN_NEXT(h, hh, hm); + } + } + /* a new entry. put in csdata */ + pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1 + keyl + sizeof(Id), 1, 4095); + d = pd->csdata + pd->ncsdata; + d[0] = keyl - 1; + memcpy(d + 1, key, keyl); + memcpy(d + 1 + keyl, &id, sizeof(Id)); + pd->ncsdata += 1 + keyl + sizeof(Id); + if ((Hashval)++pd->ncshash * 2 > hm) + { + pd->cshashm = pd->cshashm ? (2 * pd->cshashm + 1) : 4095; + rebuild_cshash(pd); + } + else + ht[h] = pd->ncsdata - (keyl + sizeof(Id)); +} + +static Id +lookup_cshash(struct parsedata *pd, const unsigned char *key, int keyl) +{ + Hashtable ht; + Hashval h, hh, hm; + + if (keyl < 4 || keyl > 256) + return 0; + ht = pd->cshash; + if (!ht) + return 0; + hm = pd->cshashm; + h = hashkey(key, keyl) & hm; + hh = HASHCHAIN_START; + while (ht[h]) + { + unsigned char *d = pd->csdata + ht[h]; + if (d[-1] == keyl - 1 && !memcmp(key, d, keyl)) + { + Id id; + memcpy(&id, d + keyl, sizeof(Id)); + return id; + } + h = HASHCHAIN_NEXT(h, hh, hm); + } + return 0; +} + +static void +fill_cshash_from_repo(struct parsedata *pd) +{ + Dataiterator di; + /* setup join data */ + dataiterator_init(&di, pd->pool, pd->repo, 0, SOLVABLE_CHECKSUM, 0, 0); + while (dataiterator_step(&di)) + put_in_cshash(pd, (const unsigned char *)di.kv.str, solv_chksum_len(di.key->type), di.solvid); + dataiterator_free(&di); +} + +static void +fill_cshash_from_new_solvables(struct parsedata *pd) +{ + Pool *pool = pd->pool; + int i, l; + KeyValue kv; + Repokey *key; + + for (i = pd->first; i < pool->nsolvables; i++) + { + if (pool->solvables[i].repo != pd->repo) + continue; + if ((key = repodata_lookup_kv_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &kv)) == 0) + continue; + if ((l = solv_chksum_len(key->type)) != 0) + put_in_cshash(pd, (const unsigned char *)kv.str, l, i); } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; +} + +/*-----------------------------------------------*/ +/* XML callbacks */ + +/* + * startElement + */ - if (!s && pd->state != STATE_SOLVABLE) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) +{ + struct parsedata *pd = xmlp->userdata; + Pool *pool = pd->pool; + Solvable *s = pd->solvable; + Id handle = pd->handle; + const char *str; + const char *pkgid; + + if (!s && state != STATE_SOLVABLE) return; - switch(pd->state) + switch(state) { case STATE_SOLVABLE: pd->kind = 0; @@ -664,30 +665,49 @@ startElement(void *userData, const char *name, const char **atts) a new solvable but just append the attributes to the existing one. */ - if ((pkgid = find_attr("pkgid", atts)) != NULL) + pd->extending = 0; + if ((pkgid = solv_xmlparser_find_attr("pkgid", atts)) != NULL) { + unsigned char chk[256]; + int l; + const char *str = pkgid; + if (!pd->cshash_filled) + { + pd->cshash_filled = 1; + fill_cshash_from_new_solvables(pd); + } + handle = 0; + /* convert into bin checksum */ + l = solv_hex2bin(&str, chk, sizeof(chk)); /* look at the checksum cache */ - Id index = stringpool_str2id(&pd->cspool, pkgid, 0); - if (!index || index >= pd->ncscache || !pd->cscache[index]) + if (l >= 4 && !pkgid[2 * l]) + handle = lookup_cshash(pd, chk, l); +#if 0 + fprintf(stderr, "Lookup %s -> %d\n", pkgid, handle); +#endif + if (!handle) { pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid); - pd->solvable = 0; pd->handle = 0; + pd->solvable = 0; break; } - pd->solvable = pool_id2solvable(pool, pd->cscache[index]); + pd->extending = 1; } else { /* this is a new package */ - pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); + handle = repo_add_solvable(pd->repo); + if (!pd->first) + pd->first = handle; pd->freshens = 0; } - pd->handle = handle = pd->solvable - pool->solvables; + pd->handle = handle; + pd->solvable = pool_id2solvable(pool, handle); if (pd->kind && pd->kind[1] == 'r') { /* products can have a type */ - const char *type = find_attr("type", atts); + const char *type = solv_xmlparser_find_attr("type", atts); if (type && *type) repodata_set_str(pd->data, handle, PRODUCT_TYPE, type); } @@ -697,6 +717,8 @@ startElement(void *userData, const char *name, const char **atts) break; case STATE_VERSION: + if (pd->extending && s->evr) + break; /* ignore version tag repetition in extend data */ s->evr = makeevr_atts(pool, pd, atts); break; case STATE_PROVIDES: @@ -757,55 +779,65 @@ startElement(void *userData, const char *name, const char **atts) case STATE_SUMMARY: case STATE_CATEGORY: case STATE_DESCRIPTION: - pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts)); + pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts)); break; case STATE_USERVISIBLE: repodata_set_void(pd->data, handle, SOLVABLE_ISVISIBLE); break; case STATE_INCLUDESENTRY: - str = find_attr("pattern", atts); + str = solv_xmlparser_find_attr("pattern", atts); if (str) repodata_add_poolstr_array(pd->data, handle, SOLVABLE_INCLUDES, join2(&pd->jd, "pattern", ":", str)); break; case STATE_EXTENDSENTRY: - str = find_attr("pattern", atts); + str = solv_xmlparser_find_attr("pattern", atts); if (str) repodata_add_poolstr_array(pd->data, handle, SOLVABLE_EXTENDS, join2(&pd->jd, "pattern", ":", str)); break; case STATE_LOCATION: - str = find_attr("href", atts); + str = solv_xmlparser_find_attr("href", atts); if (str) { - repodata_set_location(pd->data, handle, 0, 0, str); - str = find_attr("xml:base", atts); - if (str) - repodata_set_poolstr(pd->data, handle, SOLVABLE_MEDIABASE, str); + int medianr = 0; + const char *base = solv_xmlparser_find_attr("xml:base", atts); + if (base && !strncmp(base, "media:", 6)) + { + /* check for the media number in the fragment */ + int l = strlen(base); + while (l && base[l - 1] >= '0' && base[l - 1] <= '9') + l--; + if (l && base[l - 1] == '#' && base[l]) + medianr = atoi(base + l); + } + repodata_set_location(pd->data, handle, medianr, 0, str); + if (base) + repodata_set_poolstr(pd->data, handle, SOLVABLE_MEDIABASE, base); } break; case STATE_CHECKSUM: - str = find_attr("type", atts); + str = solv_xmlparser_find_attr("type", atts); pd->chksumtype = str && *str ? solv_chksum_str2type(str) : 0; if (!pd->chksumtype) - pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), str ? str : "NULL"); + pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), str ? str : "NULL"); break; case STATE_TIME: { unsigned int t; - str = find_attr("build", atts); + str = solv_xmlparser_find_attr("build", atts); if (str && (t = atoi(str)) != 0) repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t); break; } case STATE_SIZE: - if ((str = find_attr("installed", atts)) != 0) + if ((str = solv_xmlparser_find_attr("installed", atts)) != 0) repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, strtoull(str, 0, 10)); - if ((str = find_attr("package", atts)) != 0) + if ((str = solv_xmlparser_find_attr("package", atts)) != 0) repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(str, 0, 10)); break; case STATE_HEADERRANGE: { unsigned int end; - str = find_attr("end", atts); + str = solv_xmlparser_find_attr("end", atts); if (str && (end = atoi(str)) != 0) repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end); break; @@ -829,32 +861,43 @@ startElement(void *userData, const char *name, const char **atts) case STATE_DIR: { long filesz = 0, filenum = 0; - Id dirid; - if ((str = find_attr("name", atts)) != 0) - dirid = repodata_str2dir(pd->data, str, 1); - else - { + Id did; + + if ((str = solv_xmlparser_find_attr("name", atts)) == 0) + { pd->ret = pool_error(pool, -1, " tag without 'name' attribute"); break; - } - if (!dirid) - dirid = repodata_str2dir(pd->data, "/", 1); - if ((str = find_attr("size", atts)) != 0) + } + if (*str != '/') + { + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) + str = "/usr/src"; + else + { + int l = strlen(str) + 2; + char *space = solv_xmlparser_contentspace(xmlp, l); + space[0] = '/'; + memcpy(space + 1, str, l - 1); + str = space; + } + } + did = repodata_str2dir(pd->data, str, 1); + if ((str = solv_xmlparser_find_attr("size", atts)) != 0) filesz = strtol(str, 0, 0); - if ((str = find_attr("count", atts)) != 0) + if ((str = solv_xmlparser_find_attr("count", atts)) != 0) filenum = strtol(str, 0, 0); - pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31); - pd->dirs[pd->ndirs][0] = dirid; - pd->dirs[pd->ndirs][1] = filesz; - pd->dirs[pd->ndirs][2] = filenum; - pd->ndirs++; + if (filesz || filenum) + { + queue_push(&pd->diskusageq, did); + queue_push2(&pd->diskusageq, filesz, filenum); + } break; } case STATE_CHANGELOG: pd->changelog_handle = repodata_new_handle(pd->data); - if ((str = find_attr("date", atts)) != 0) + if ((str = solv_xmlparser_find_attr("date", atts)) != 0) repodata_set_num(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TIME, strtoull(str, 0, 10)); - if ((str = find_attr("author", atts)) != 0) + if ((str = solv_xmlparser_find_attr("author", atts)) != 0) repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_AUTHOR, str); break; default: @@ -865,14 +908,12 @@ startElement(void *userData, const char *name, const char **atts) /* * endElement - * XML callback - * */ -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; Repo *repo = pd->repo; @@ -880,39 +921,17 @@ endElement(void *userData, const char *name) Id id; char *p; - if (pd->depth != pd->statedepth) - { - pd->depth--; - /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */ - return; - } - - /* ignore patterns & metadata */ - if (pd->state == STATE_START && !strcmp(name, "patterns")) - return; - if (pd->state == STATE_START && !strcmp(name, "products")) - return; -#if 0 - if (pd->state == STATE_START && !strcmp(name, "metadata")) - return; -#endif - if (pd->state == STATE_SOLVABLE && !strcmp(name, "format")) - return; - - pd->depth--; - pd->statedepth--; - - if (!s) - { - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - return; - } + return; - switch (pd->state) + switch (state) { case STATE_SOLVABLE: + if (pd->extending) + { + pd->solvable = 0; + break; + } if (pd->kind && !s->name) /* add namespace in case of NULL name */ s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", 0), 1); if (!s->arch) @@ -921,201 +940,159 @@ endElement(void *userData, const char *name) s->evr = ID_EMPTY; /* some patterns have this */ if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, pd->freshens); - s->conflicts = repo_fix_conflicts(repo, s->conflicts); + repo_rewrite_suse_deps(s, pd->freshens); pd->freshens = 0; pd->kind = 0; - pd->solvable = s = 0; + pd->solvable = 0; break; case STATE_NAME: if (pd->kind) - s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", pd->content), 1); + s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", content), 1); else - s->name = pool_str2id(pool, pd->content, 1); + s->name = pool_str2id(pool, content, 1); break; case STATE_ARCH: - s->arch = pool_str2id(pool, pd->content, 1); + s->arch = pool_str2id(pool, content, 1); break; case STATE_VENDOR: - s->vendor = pool_str2id(pool, pd->content, 1); + s->vendor = pool_str2id(pool, content, 1); break; case STATE_RPM_GROUP: - repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, pd->content); + repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, content); break; case STATE_RPM_LICENSE: - repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, pd->content); + repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, content); break; case STATE_CHECKSUM: { - Id index; - - if (!pd->chksumtype) + unsigned char chk[256]; + int l = solv_chksum_len(pd->chksumtype); + const char *str = content; + if (!l || l > sizeof(chk)) break; - if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype)) + if (solv_hex2bin(&str, chk, l) != l || content[2 * l]) { - pd->ret = pool_error(pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype)); + pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype)); break; } - repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, pd->content); - /* we save the checksum to solvable id relationship for extended - metadata */ - index = stringpool_str2id(&pd->cspool, pd->content, 1 /* create it */); - if (index >= pd->ncscache) - { - pd->cscache = solv_zextend(pd->cscache, pd->ncscache, index + 1 - pd->ncscache, sizeof(Id), 255); - pd->ncscache = index + 1; - } - /* add the checksum to the cache */ - pd->cscache[index] = s - pool->solvables; + repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk); + /* we save the checksum to solvable id relationship for extending metadata */ + if (pd->cshash_filled) + put_in_cshash(pd, chk, l, s - pool->solvables); break; } case STATE_FILE: -#if 0 - id = pool_str2id(pool, pd->content, 1); - s->provides = repo_addid_dep(repo, s->provides, id, SOLVABLE_FILEMARKER); -#endif - if ((p = strrchr(pd->content, '/')) != 0) + if ((p = strrchr(content, '/')) != 0) { *p++ = 0; - if (pd->lastdir && !strcmp(pd->lastdirstr, pd->content)) + if (pd->lastdir && !strcmp(pd->lastdirstr, content)) { id = pd->lastdir; } else { - int l; - id = repodata_str2dir(pd->data, pd->content, 1); - l = strlen(pd->content) + 1; - if (l > pd->lastdirstrl) + int l = p - content; + if (l + 1 > pd->lastdirstrl) /* + 1 for the possible leading / we need to insert */ { pd->lastdirstrl = l + 128; pd->lastdirstr = solv_realloc(pd->lastdirstr, pd->lastdirstrl); } - strcpy(pd->lastdirstr, pd->content); + if (content[0] != '/') + { + pd->lastdirstr[0] = '/'; + memcpy(pd->lastdirstr + 1, content, l); + id = repodata_str2dir(pd->data, pd->lastdirstr, 1); + } + else + id = repodata_str2dir(pd->data, content, 1); pd->lastdir = id; + memcpy(pd->lastdirstr, content, l); } } else { - p = pd->content; - id = 0; + p = content; + id = repodata_str2dir(pd->data, "/", 1); } - if (!id) - id = repodata_str2dir(pd->data, "/", 1); repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p); break; case STATE_SUMMARY: - repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content); + repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), content); break; case STATE_DESCRIPTION: - set_description_author(pd->data, handle, pd->content, pd); + set_description_author(pd->data, handle, content, pd); break; case STATE_CATEGORY: - repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), pd->content); + repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), content); break; case STATE_DISTRIBUTION: - repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, pd->content); + repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, content); break; case STATE_URL: - if (pd->content[0]) - repodata_set_str(pd->data, handle, SOLVABLE_URL, pd->content); + if (*content) + repodata_set_str(pd->data, handle, SOLVABLE_URL, content); break; case STATE_PACKAGER: - if (pd->content[0]) - repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, pd->content); + if (*content) + repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, content); break; case STATE_SOURCERPM: - if (pd->content[0]) - repodata_set_sourcepkg(pd->data, handle, pd->content); + if (*content) + repodata_set_sourcepkg(pd->data, handle, content); break; case STATE_RELNOTESURL: - if (pd->content[0]) + if (*content) { - repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content); + repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content); repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "releasenotes", 1)); } break; case STATE_UPDATEURL: - if (pd->content[0]) + if (*content) { - repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content); + repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content); repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "update", 1)); } break; case STATE_OPTIONALURL: - if (pd->content[0]) + if (*content) { - repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content); + repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content); repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "optional", 1)); } break; case STATE_FLAG: - if (pd->content[0]) - repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, pd->content); + if (*content) + repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, content); break; case STATE_EULA: - if (pd->content[0]) - repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), pd->content); + if (*content) + repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), content); break; case STATE_KEYWORD: - if (pd->content[0]) - repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, pd->content); + if (*content) + repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, content); break; case STATE_DISKUSAGE: - if (pd->ndirs) - commit_diskusage(pd, handle); + if (pd->diskusageq.count) + repodata_add_diskusage(pd->data, handle, &pd->diskusageq); break; case STATE_ORDER: - if (pd->content[0]) - repodata_set_str(pd->data, handle, SOLVABLE_ORDER, pd->content); + if (*content) + repodata_set_str(pd->data, handle, SOLVABLE_ORDER, content); break; case STATE_CHANGELOG: - repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, pd->content); + repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, content); repodata_add_flexarray(pd->data, handle, SOLVABLE_CHANGELOG, pd->changelog_handle); pd->changelog_handle = 0; break; default: break; } - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; - /* fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */ -} - - -/* - * characterData - * XML callback - * - */ - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - - if (!pd->docontent) - return; - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = solv_realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; } /*-----------------------------------------------*/ -/* 'main' */ - -#define BUFF_SIZE 8192 /* * repo_add_rpmmd @@ -1128,84 +1105,55 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags) { Pool *pool = repo->pool; struct parsedata pd; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; Repodata *data; unsigned int now; - XML_Parser parser; now = solv_timems(0); data = repo_add_repodata(repo, flags); memset(&pd, 0, sizeof(pd)); - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } pd.pool = pool; pd.repo = repo; pd.data = data; - pd.content = solv_malloc(256); - pd.acontent = 256; - pd.lcontent = 0; pd.kind = 0; pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0; + queue_init(&pd.diskusageq); - /* initialize the string pool where we will store - the package checksums we know about, to get an Id - we can use in a cache */ - stringpool_init_empty(&pd.cspool); + init_cshash(&pd); if ((flags & REPO_EXTEND_SOLVABLES) != 0) { /* setup join data */ - Dataiterator di; - dataiterator_init(&di, pool, repo, 0, SOLVABLE_CHECKSUM, 0, 0); - while (dataiterator_step(&di)) - { - const char *str; - int index; - - if (!solv_chksum_len(di.key->type)) - continue; - str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str); - index = stringpool_str2id(&pd.cspool, str, 1); - if (index >= pd.ncscache) - { - pd.cscache = solv_zextend(pd.cscache, pd.ncscache, index + 1 - pd.ncscache, sizeof(Id), 255); - pd.ncscache = index + 1; - } - pd.cscache[index] = di.solvid; - } - dataiterator_free(&di); + pd.cshash_filled = 1; + fill_cshash_from_repo(&pd); } - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - pd.parser = &parser; - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); + + solv_free(pd.lastdirstr); + join_freemem(&pd.jd); + free_cshash(&pd); + repodata_free_dircache(data); + queue_free(&pd.diskusageq); + + if ((flags & REPO_EXTEND_SOLVABLES) != 0) + { + /* is this a filelist extension? */ + if (repodata_has_keyname(data, SOLVABLE_FILELIST)) + repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION); + } + else { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) + /* is this a primary with a filtered filelist? */ + if (data->end > data->start) { - pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; + repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED); + repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST); } - if (l == 0) - break; } - XML_ParserFree(parser); - solv_free(pd.content); - solv_free(pd.lastdirstr); - join_freemem(&pd.jd); - stringpool_free(&pd.cspool); - solv_free(pd.cscache); - repodata_free_dircache(data); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); diff --git a/libsolv-0.6.15/ext/repo_rpmmd.h b/libsolv-0.7.2/ext/repo_rpmmd.h similarity index 100% rename from libsolv-0.6.15/ext/repo_rpmmd.h rename to libsolv-0.7.2/ext/repo_rpmmd.h diff --git a/libsolv-0.6.15/ext/repo_susetags.c b/libsolv-0.7.2/ext/repo_susetags.c similarity index 70% rename from libsolv-0.6.15/ext/repo_susetags.c rename to libsolv-0.7.2/ext/repo_susetags.c index a96ba97..561c789 100644 --- a/libsolv-0.6.15/ext/repo_susetags.c +++ b/libsolv-0.7.2/ext/repo_susetags.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -21,6 +19,7 @@ #ifdef ENABLE_COMPLEX_DEPS #include "pool_parserpmrichdep.h" #endif +#include "repodata_diskusage.h" struct datashare { Id name; @@ -38,8 +37,7 @@ struct parsedata { int last_found_source; struct datashare *share_with; int nshare; - Id (*dirs)[3]; /* dirid, size, nfiles */ - int ndirs; + Queue diskusageq; struct joindata jd; char *language; /* the default language */ Id langcache[ID_NUM_INTERNAL]; /* cache for the default language */ @@ -180,39 +178,6 @@ add_source(struct parsedata *pd, char *line, Solvable *s, Id handle) repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch); } -/* - * add_dirline - * add a line with directory information - * - */ - -static void -add_dirline(struct parsedata *pd, char *line) -{ - char *sp[6]; - long filesz; - long filenum; - Id dirid; - if (split(line, sp, 6) != 5) - return; - pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31); - filesz = strtol(sp[1], 0, 0); - filesz += strtol(sp[2], 0, 0); - filenum = strtol(sp[3], 0, 0); - filenum += strtol(sp[4], 0, 0); - /* hack: we know that there's room for a / */ - if (*sp[0] != '/') - *--sp[0] = '/'; - dirid = repodata_str2dir(pd->data, sp[0], 1); -#if 0 -fprintf(stderr, "%s -> %d\n", sp[0], dirid); -#endif - pd->dirs[pd->ndirs][0] = dirid; - pd->dirs[pd->ndirs][1] = filesz; - pd->dirs[pd->ndirs][2] = filenum; - pd->ndirs++; -} - static void set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *line) { @@ -238,86 +203,6 @@ set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char * } -/* - * id3_cmp - * compare - * - */ - -static int -id3_cmp(const void *v1, const void *v2, void *dp) -{ - Id *i1 = (Id*)v1; - Id *i2 = (Id*)v2; - return i1[0] - i2[0]; -} - - -/* - * commit_diskusage - * - */ - -static void -commit_diskusage(struct parsedata *pd, Id handle) -{ - int i; - Dirpool *dp = &pd->data->dirpool; - /* Now sort in dirid order. This ensures that parents come before - their children. */ - if (pd->ndirs > 1) - solv_sort(pd->dirs, pd->ndirs, sizeof(pd->dirs[0]), id3_cmp, 0); - /* Substract leaf numbers from all parents to make the numbers - non-cumulative. This must be done post-order (i.e. all leafs - adjusted before parents). We ensure this by starting at the end of - the array moving to the start, hence seeing leafs before parents. */ - for (i = pd->ndirs; i--;) - { - Id p = dirpool_parent(dp, pd->dirs[i][0]); - int j = i; - for (; p; p = dirpool_parent(dp, p)) - { - for (; j--;) - if (pd->dirs[j][0] == p) - break; - if (j >= 0) - { - if (pd->dirs[j][1] < pd->dirs[i][1]) - pd->dirs[j][1] = 0; - else - pd->dirs[j][1] -= pd->dirs[i][1]; - if (pd->dirs[j][2] < pd->dirs[i][2]) - pd->dirs[j][2] = 0; - else - pd->dirs[j][2] -= pd->dirs[i][2]; - } - else - /* Haven't found this parent in the list, look further if - we maybe find the parents parent. */ - j = i; - } - } -#if 0 - char sbuf[1024]; - char *buf = sbuf; - unsigned slen = sizeof(sbuf); - for (i = 0; i < pd->ndirs; i++) - { - dir2str(attr, pd->dirs[i][0], &buf, &slen); - fprintf(stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf); - } - if (buf != sbuf) - free (buf); -#endif - for (i = 0; i < pd->ndirs; i++) - if (pd->dirs[i][1] || pd->dirs[i][2]) - { - repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]); - } - pd->ndirs = 0; -} - - /* Unfortunately "a"[0] is no constant expression in the C languages, so we need to pass the four characters individually :-/ */ #define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \ @@ -330,7 +215,7 @@ commit_diskusage(struct parsedata *pd, Id handle) * */ -static inline unsigned +static inline unsigned int tag_from_string(char *cs) { unsigned char *s = (unsigned char *)cs; @@ -385,17 +270,13 @@ finish_solvable(struct parsedata *pd, Solvable *s, Offset freshens) } pd->nfilelist = 0; } - /* A self provide, except for source packages. This is harmless + /* Add self provide, except for source packages. This is harmless to do twice (in case we see the same package twice). */ if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) - s->provides = repo_addid_dep(pd->repo, s->provides, - pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - /* XXX This uses repo_addid_dep internally, so should also be - harmless to do twice. */ - s->supplements = repo_fix_supplements(pd->repo, s->provides, s->supplements, freshens); - s->conflicts = repo_fix_conflicts(pd->repo, s->conflicts); - if (pd->ndirs) - commit_diskusage(pd, handle); + s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); + repo_rewrite_suse_deps(s, freshens); + if (pd->diskusageq.count) + repodata_add_diskusage(pd->data, handle, &pd->diskusageq); } static Hashtable @@ -452,7 +333,16 @@ lookup_shared_id(Repodata *data, Id p, Id keyname, Id voidid, int uninternalized return r; } if (uninternalized) - return repodata_lookup_id_uninternalized(data, p, keyname, voidid); + { + KeyValue kv; + Repokey *key = repodata_lookup_kv_uninternalized(data, p, keyname, &kv); + if (!key) + return 0; + if (key->type == REPOKEY_TYPE_VOID) + return voidid; + if (key->type == REPOKEY_TYPE_ID) + return kv.id; + } return 0; } @@ -464,6 +354,77 @@ toevr(Pool *pool, struct parsedata *pd, const char *version, const char *release } +static inline void record_share(struct parsedata *pd, Id handle, Id name, Id evr, Id arch) +{ + Repo *repo = pd->repo; + int i = handle - repo->start; + if (i >= pd->nshare) + { + pd->share_with = solv_realloc2(pd->share_with, i + 256, sizeof(*pd->share_with)); + memset(pd->share_with + pd->nshare, 0, (i + 256 - pd->nshare) * sizeof(*pd->share_with)); + pd->nshare = i + 256; + } + pd->share_with[i].name = name; + pd->share_with[i].evr = evr; + pd->share_with[i].arch = arch; +} + +static void process_shares(struct parsedata *pd) +{ + Pool *pool = pd->pool; + Repo *repo = pd->repo; + Repodata *data = pd->data; + int i, last_found; + Map keyidmap; + + map_init(&keyidmap, data->nkeys); + for (i = 1; i < data->nkeys; i++) + { + Id keyname = data->keys[i].name; + if (keyname == SOLVABLE_INSTALLSIZE || keyname == SOLVABLE_DISKUSAGE || keyname == SOLVABLE_FILELIST) + continue; + if (keyname == SOLVABLE_MEDIADIR || keyname == SOLVABLE_MEDIAFILE || keyname == SOLVABLE_MEDIANR) + continue; + if (keyname == SOLVABLE_DOWNLOADSIZE || keyname == SOLVABLE_CHECKSUM) + continue; + if (keyname == SOLVABLE_SOURCENAME || keyname == SOLVABLE_SOURCEARCH || keyname == SOLVABLE_SOURCEEVR) + continue; + if (keyname == SOLVABLE_PKGID || keyname == SOLVABLE_HDRID || keyname == SOLVABLE_LEADSIGID) + continue; + if (keyname == SUSETAGS_SHARE_NAME || keyname == SUSETAGS_SHARE_EVR || keyname == SUSETAGS_SHARE_ARCH) + continue; + MAPSET(&keyidmap, i); + } + last_found = 0; + for (i = 0; i < pd->nshare; i++) + { + unsigned int n, nn; + Solvable *found = 0; + if (!pd->share_with[i].name) + continue; + for (n = repo->start, nn = repo->start + last_found; n < repo->end; n++, nn++) + { + if (nn >= repo->end) + nn = repo->start; + found = pool->solvables + nn; + if (found->repo == repo + && found->name == pd->share_with[i].name + && found->evr == pd->share_with[i].evr + && found->arch == pd->share_with[i].arch) + { + last_found = nn - repo->start; + break; + } + } + if (n != repo->end) + repodata_merge_some_attrs(data, repo->start + i, repo->start + last_found, &keyidmap, 0); + } + pd->share_with = solv_free(pd->share_with); + pd->nshare = 0; + map_free(&keyidmap); +} + + /* * parse susetags * @@ -482,12 +443,13 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int Solvable *s; Offset freshens; int intag = 0; + int intag_linestart = 0; int cummulate = 0; - int indesc = 0; + int notfound = 0; int indelta = 0; int last_found_pack = 0; Id first_new_pkg = 0; - char *sp[5]; + char *sp[6]; struct parsedata pd; Repodata *data = 0; Id handle = 0; @@ -498,7 +460,6 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int if ((flags & (SUSETAGS_EXTEND|REPO_EXTEND_SOLVABLES)) != 0 && repo->nrepodata) { joinhash = joinhash_init(repo, &joinhashm); - indesc = 1; } data = repo_add_repodata(repo, flags); @@ -512,6 +473,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int pd.data = data; pd.flags = flags; pd.language = language && *language ? solv_strdup(language) : 0; + queue_init(&pd.diskusageq); linep = line; s = 0; @@ -540,15 +502,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int arch = lookup_shared_id(sdata, p, SUSETAGS_SHARE_ARCH, pool->solvables[p].arch, sdata == data); if (!arch) continue; - if (p - repo->start >= pd.nshare) - { - pd.share_with = solv_realloc2(pd.share_with, p - repo->start + 256, sizeof(*pd.share_with)); - memset(pd.share_with + pd.nshare, 0, (p - repo->start + 256 - pd.nshare) * sizeof(*pd.share_with)); - pd.nshare = p - repo->start + 256; - } - pd.share_with[p - repo->start].name = name; - pd.share_with[p - repo->start].evr = evr; - pd.share_with[p - repo->start].arch = arch; + record_share(&pd, p, name, evr, arch); } } } @@ -562,10 +516,9 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int for (;;) { - unsigned tag; - char *olinep; /* old line pointer */ + unsigned int tag; char line_lang[6]; - int keylen = 3; + int keylen; if (pd.ret) break; @@ -578,84 +531,86 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int } if (!fgets(linep, aline - (linep - line), fp)) /* read line */ break; - olinep = linep; linep += strlen(linep); if (linep == line || linep[-1] != '\n') continue; pd.lineno++; *--linep = 0; - if (linep == olinep) - continue; if (intag) { - /* check for multi-line value tags (+Key:/-Key:) */ - - int is_end = (linep[-intag - keylen + 1] == '-') - && (linep[-1] == ':') - && (linep == line + 1 + intag + 1 + 1 + 1 + intag + 1 || linep[-intag - keylen] == '\n'); - if (is_end - && strncmp(linep - 1 - intag, line + 1, intag)) - { - pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%s' %d\n", pd.lineno, linep - 1 - intag, line + 1, intag); - } - if (cummulate && !is_end) + /* in multi-line value tags (+Key:/-Key:), check for end, cummulate */ + int is_end = line[intag_linestart] == '-' && linep[-1] == ':' && linep - line == intag_linestart + intag + 2; + if (is_end && strncmp(linep - 1 - intag, line + 1, intag)) { - *linep++ = '\n'; - continue; + pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%.*s'\n", pd.lineno, linep - 1 - intag, intag, line + 1); } - if (cummulate && is_end) + if (!is_end) { - linep[-intag - keylen + 1] = 0; - if (linep[-intag - keylen] == '\n') - linep[-intag - keylen] = 0; - linep = line; - intag = 0; + if (cummulate) + { + *linep++ = '\n'; + intag_linestart = linep - line; + continue; + } + intag_linestart = intag + 3; + linep = line + intag_linestart; + if (!*linep) + continue; /* ignore empty lines, bnc#381828 */ } - if (!cummulate && is_end) + else { intag = 0; linep = line; - continue; + if (!cummulate) + continue; + line[intag_linestart] = 0; + if (line[intag_linestart - 1] == '\n') + line[intag_linestart - 1] = 0; /* strip trailing newline */ } - if (!cummulate && !is_end) - linep = line + intag + keylen; } else linep = line; - if (!intag && line[0] == '+' && line[1] && line[1] != ':') /* start of +Key:/-Key: tag */ + /* ignore comments and empty lines */ + if (!*line || *line == '#') + continue; + + /* ignore malformed lines */ + if (!(line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.'))) + continue; + + if (!intag && line[0] == '+' && line[1] != ':') /* start of +Key:/-Key: tag */ { char *tagend = strchr(line, ':'); - if (!tagend) + if (!tagend || tagend - line > 100) { pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line); break; } - intag = tagend - (line + 1); + intag = tagend - (line + 1); /* set to tagsize */ cummulate = 0; - switch (tag_from_string(line)) /* check if accumulation is needed */ + switch (tag_from_string(line)) /* check if accumulation is needed */ { case CTAG('+', 'D', 'e', 's'): case CTAG('+', 'E', 'u', 'l'): case CTAG('+', 'I', 'n', 's'): case CTAG('+', 'D', 'e', 'l'): case CTAG('+', 'A', 'u', 't'): - if (line[4] == ':' || line[4] == '.') - cummulate = 1; + cummulate = 1; break; default: break; } - line[0] = '='; /* handle lines between +Key:/-Key: as =Key: */ - line[intag + keylen - 1] = ' '; - linep = line + intag + keylen; + line[0] = '='; /* handle lines between +Key:/-Key: as =Key: */ + line[intag + 2] = ' '; + intag_linestart = intag + 3; + linep = line + intag_linestart; continue; } - if (*line == '#' || !*line) - continue; - if (! (line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.'))) - continue; + + /* support language suffix */ + keylen = 3; line_lang[0] = 0; if (line[4] == '.') { @@ -671,130 +626,90 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int line_lang[langsize] = 0; } } - tag = tag_from_string(line); - if (indelta) - { - /* Example: - =Dlt: subversion 1.6.16 1.3.1 i586 - =Dsq: subversion 1.6.15 4.2 i586 d57b3fc86e7a2f73796e8e35b96fa86212c910 - =Cks: SHA1 14a8410cf741856a5d70d89dab62984dba6a1ca7 - =Loc: 1 subversion-1.6.15_1.6.16-4.2_1.3.1.i586.delta.rpm - =Siz: 81558 - */ - switch (tag) - { - case CTAG('=', 'D', 's', 'q'): - { - Id evr; - if (split(line + 5, sp, 5) != 5) - continue; - repodata_set_id(data, handle, DELTA_SEQ_NAME, pool_str2id(pool, sp[0], 1)); - evr = toevr(pool, &pd, sp[1], sp[2]); - repodata_set_id(data, handle, DELTA_SEQ_EVR, evr); - /* repodata_set_id(data, handle, DELTA_SEQ_ARCH, pool_str2id(pool, sp[3], 1)); */ - repodata_set_str(data, handle, DELTA_SEQ_NUM, sp[4]); - repodata_set_id(data, handle, DELTA_BASE_EVR, evr); - continue; - } - case CTAG('=', 'C', 'k', 's'): - set_checksum(&pd, data, handle, DELTA_CHECKSUM, line + 6); - continue; - case CTAG('=', 'L', 'o', 'c'): - { - int i = split(line + 6, sp, 3); - if (i != 2 && i != 3) - { - pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line); - continue; - } - repodata_set_deltalocation(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]); - continue; - } - case CTAG('=', 'S', 'i', 'z'): - if (split(line + 6, sp, 3) == 2) - repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, strtoull(sp[0], 0, 10)); - continue; - case CTAG('=', 'P', 'k', 'g'): - case CTAG('=', 'P', 'a', 't'): - case CTAG('=', 'D', 'l', 't'): - handle = 0; - indelta = 0; - break; - default: - pool_debug(pool, SOLV_ERROR, "susetags: unknown line: %d: %s\n", pd.lineno, line); - continue; - } - } + tag = tag_from_string(line); - /* - * start of (next) package or pattern or delta - * - * =Pkg: - * (=Pat: ...) - */ - if (tag == CTAG('=', 'D', 'l', 't')) - { + /* handle global tags and tags that start a new section */ + switch (tag) + { + case CTAG('=', 'V', 'e', 'r'): + /* start of a new file */ if (s) finish_solvable(&pd, s, freshens); s = 0; - pd.kind = 0; - if (split(line + 5, sp, 5) != 4) + handle = 0; + freshens = 0; + indelta = 0; + notfound = 0; + last_found_pack = 0; + if (createdpkgs) { - pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line); - break; + solv_free(joinhash); + joinhash = joinhash_init(repo, &joinhashm); + createdpkgs = 0; } - handle = repodata_new_handle(data); - repodata_set_id(data, handle, DELTA_PACKAGE_NAME, pool_str2id(pool, sp[0], 1)); - repodata_set_id(data, handle, DELTA_PACKAGE_EVR, toevr(pool, &pd, sp[1], sp[2])); - repodata_set_id(data, handle, DELTA_PACKAGE_ARCH, pool_str2id(pool, sp[3], 1)); - repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DELTAINFO, handle); - indelta = 1; continue; - } - if (tag == CTAG('=', 'P', 'k', 'g') - || tag == CTAG('=', 'P', 'a', 't')) - { - /* If we have an old solvable, complete it by filling in some - default stuff. */ + + case CTAG('=', 'L', 'a', 'n'): + /* define language of the following material */ + pd.language = solv_free(pd.language); + memset(pd.langcache, 0, sizeof(pd.langcache)); + if (line[6]) + pd.language = solv_strdup(line + 6); + continue; + + case CTAG('=', 'P', 'k', 'g'): /* start of a package */ + case CTAG('=', 'P', 'a', 't'): /* start of a pattern */ + case CTAG('=', 'D', 'l', 't'): /* start of a delta */ + /* =Pkg: */ + /* If we have an old solvable, complete it by filling in some default stuff. */ if (s) finish_solvable(&pd, s, freshens); + s = 0; + handle = 0; + freshens = 0; + indelta = 0; + notfound = 0; - /* - * define kind - */ - + /* define kind */ pd.kind = 0; - if (line[3] == 't') + if (tag == CTAG('=', 'P', 'a', 't')) pd.kind = "pattern"; - /* - * parse nevra - */ - + /* parse nevra */ if (split(line + 5, sp, 5) != 4) { pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line); break; } - s = 0; - freshens = 0; + + if (tag == CTAG('=', 'D', 'l', 't')) + { + /* start new delta */ + handle = repodata_new_handle(data); + repodata_set_id(data, handle, DELTA_PACKAGE_NAME, pool_str2id(pool, sp[0], 1)); + repodata_set_id(data, handle, DELTA_PACKAGE_EVR, toevr(pool, &pd, sp[1], sp[2])); + repodata_set_id(data, handle, DELTA_PACKAGE_ARCH, pool_str2id(pool, sp[3], 1)); + repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DELTAINFO, handle); + indelta = 1; + continue; + } if (joinhash) { /* data join operation. find solvable matching name/arch/evr and * add data to it */ - Id name, evr, arch; + Id name, arch; /* we don't use the create flag here as a simple pre-check for existance */ if (pd.kind) name = pool_str2id(pool, join2(&pd.jd, pd.kind, ":", sp[0]), 0); else name = pool_str2id(pool, sp[0], 0); - evr = toevr(pool, &pd, sp[1], sp[2]); arch = pool_str2id(pool, sp[3], 0); if (name && arch) { Id start = (flags & REPO_EXTEND_SOLVABLES) ? 0 : first_new_pkg; + Id evr = toevr(pool, &pd, sp[1], sp[2]); if (repo->start + last_found_pack + 1 >= start && repo->start + last_found_pack + 1 < repo->end) { s = pool->solvables + repo->start + last_found_pack + 1; @@ -806,7 +721,10 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int } /* do not create new packages in EXTEND_SOLVABLES mode */ if (!s && (flags & REPO_EXTEND_SOLVABLES) != 0) - continue; + { + notfound = 1; + continue; + } /* fallthrough to package creation */ } if (!s) @@ -824,21 +742,74 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int first_new_pkg = s - pool->solvables; createdpkgs = 1; } + handle = s - pool->solvables; last_found_pack = (s - pool->solvables) - repo->start; - if (data) - handle = s - pool->solvables; + continue; + + default: + break; } - /* If we have no current solvable to add to, ignore all further lines - for it. Probably invalid input data in the second set of - solvables. */ - if (indesc >= 2 && !s) - { + /* handle delta tags */ + if (indelta) + { + /* Example: + =Dlt: subversion 1.6.16 1.3.1 i586 + =Dsq: subversion 1.6.15 4.2 i586 d57b3fc86e7a2f73796e8e35b96fa86212c910 + =Cks: SHA1 14a8410cf741856a5d70d89dab62984dba6a1ca7 + =Loc: 1 subversion-1.6.15_1.6.16-4.2_1.3.1.i586.delta.rpm + =Siz: 81558 + */ + switch (tag) + { + case CTAG('=', 'D', 's', 'q'): + { + Id evr; + if (split(line + 5, sp, 5) != 5) + continue; + repodata_set_id(data, handle, DELTA_SEQ_NAME, pool_str2id(pool, sp[0], 1)); + evr = toevr(pool, &pd, sp[1], sp[2]); + repodata_set_id(data, handle, DELTA_SEQ_EVR, evr); + /* repodata_set_id(data, handle, DELTA_SEQ_ARCH, pool_str2id(pool, sp[3], 1)); */ + repodata_set_str(data, handle, DELTA_SEQ_NUM, sp[4]); + repodata_set_id(data, handle, DELTA_BASE_EVR, evr); + continue; + } + case CTAG('=', 'C', 'k', 's'): + set_checksum(&pd, data, handle, DELTA_CHECKSUM, line + 6); + continue; + case CTAG('=', 'L', 'o', 'c'): + { + int i = split(line + 6, sp, 3); + if (i != 2 && i != 3) + { + pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line); + continue; + } + repodata_set_deltalocation(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]); + continue; + } + case CTAG('=', 'S', 'i', 'z'): + if (split(line + 6, sp, 3) == 2) + repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, strtoull(sp[0], 0, 10)); + continue; + default: + pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line); + continue; + } + } + + /* we need a solvable for all other tags */ + if (!s) + { + if (notfound) + continue; /* did not find the solvable to extend */ #if 0 - pool_debug(pool, SOLV_ERROR, "susetags: huh %d: %s?\n", pd.lineno, line); + pool_debug(pool, SOLV_WARN, "susetags: stray line: %d: %s\n", pd.lineno, line); #endif continue; } + switch (tag) { case CTAG('=', 'P', 'r', 'v'): /* provides */ @@ -869,11 +840,9 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int continue; case CTAG('=', 'P', 'r', 'q'): /* pre-requires / packages required */ if (pd.kind) - { - s->requires = adddep(pool, &pd, s->requires, line, 0, 0); /* patterns: a required package */ - } + s->requires = adddep(pool, &pd, s->requires, line, 0, 0); /* pattern: package requires */ else - s->requires = adddep(pool, &pd, s->requires, line, SOLVABLE_PREREQMARKER, 0); /* package: pre-requires */ + s->requires = adddep(pool, &pd, s->requires, line, SOLVABLE_PREREQMARKER, 0); /* pre-requires */ continue; case CTAG('=', 'O', 'b', 's'): /* obsoletes */ s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, pd.kind); @@ -917,17 +886,6 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int case CTAG('=', 'P', 'e', 'n'): /* pattern: package enhances */ s->enhances = adddep(pool, &pd, s->enhances, line, 0, 0); continue; - case CTAG('=', 'V', 'e', 'r'): /* - version - */ - last_found_pack = 0; - handle = 0; - indesc++; - if (createdpkgs) - { - solv_free(joinhash); - joinhash = joinhash_init(repo, &joinhashm); - createdpkgs = 0; - } - continue; case CTAG('=', 'V', 'n', 'd'): /* vendor */ s->vendor = pool_str2id(pool, line + 6, 1); continue; @@ -995,8 +953,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int k = atoi(line + 6); if (k || !strcasecmp(line + 6, "true")) repodata_set_void(data, handle, SOLVABLE_ISVISIBLE); + continue; } - continue; case CTAG('=', 'S', 'h', 'r'): { Id name, evr, arch; @@ -1008,15 +966,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int name = pool_str2id(pool, sp[0], 1); evr = toevr(pool, &pd, sp[1], sp[2]); arch = pool_str2id(pool, sp[3], 1); - if (last_found_pack >= pd.nshare) - { - pd.share_with = solv_realloc2(pd.share_with, last_found_pack + 256, sizeof(*pd.share_with)); - memset(pd.share_with + pd.nshare, 0, (last_found_pack + 256 - pd.nshare) * sizeof(*pd.share_with)); - pd.nshare = last_found_pack + 256; - } - pd.share_with[last_found_pack].name = name; - pd.share_with[last_found_pack].evr = evr; - pd.share_with[last_found_pack].arch = arch; + record_share(&pd, handle, name, evr, arch); if ((flags & SUSETAGS_RECORD_SHARES) != 0) { if (s->name == name) @@ -1035,8 +985,22 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int continue; } case CTAG('=', 'D', 'i', 'r'): - add_dirline(&pd, line + 6); - continue; + if (split(line + 6, sp, 6) == 5) + { + long filesz, filenum; + Id did; + + filesz = strtol(sp[1], 0, 0); + filesz += strtol(sp[2], 0, 0); + filenum = strtol(sp[3], 0, 0); + filenum += strtol(sp[4], 0, 0); + if (*sp[0] != '/') + *--sp[0] = '/'; /* hack: we know that there's room for a / */ + did = repodata_str2dir(data, sp[0], 1); + queue_push(&pd.diskusageq, did); + queue_push2(&pd.diskusageq, (Id)filesz, (Id)filenum); + } + break; case CTAG('=', 'C', 'a', 't'): repodata_set_poolstr(data, handle, langtag(&pd, SOLVABLE_CATEGORY, line_lang), line + 3 + keylen); break; @@ -1057,36 +1021,25 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int case CTAG('=', 'C', 'k', 's'): set_checksum(&pd, data, handle, SOLVABLE_CHECKSUM, line + 6); break; - case CTAG('=', 'L', 'a', 'n'): - pd.language = solv_free(pd.language); - memset(pd.langcache, 0, sizeof(pd.langcache)); - if (line[6]) - pd.language = solv_strdup(line + 6); - break; case CTAG('=', 'F', 'l', 's'): { - char *p = strrchr(line + 6, '/'); + char *p, *file = line + 6; Id did; - /* strip trailing slash */ - if (p && p != line + 6 && !p[1]) + + if (*file != '/') + *--file = '/'; /* hack: we know there is room */ + p = strrchr(file, '/'); + /* strip trailing slashes */ + while (p != file && !p[1]) { *p = 0; - p = strrchr(line + 6, '/'); - } - if (p) - { - *p++ = 0; - did = repodata_str2dir(data, line + 6, 1); - } - else - { - p = line + 6; - did = 0; + p = strrchr(file, '/'); } - if (!did) - did = repodata_str2dir(data, "/", 1); + *p++ = 0; + did = repodata_str2dir(data, *file ? file : "/", 1); repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, p); + line[5] = ' '; break; } case CTAG('=', 'H', 'd', 'r'): @@ -1100,84 +1053,47 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int } break; - case CTAG('=', 'P', 'a', 't'): - case CTAG('=', 'P', 'k', 'g'): - break; - default: #if 0 pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line); #endif break; } - } if (s) finish_solvable(&pd, s, freshens); solv_free(pd.filelist); - /* Shared attributes - * (e.g. multiple binaries built from same source) - */ + /* process shared attributes (e.g. multiple binaries built from same source) */ if (pd.nshare) - { - int i, last_found; - Map keyidmap; + process_shares(&pd); + + solv_free(joinhash); + repodata_free_dircache(data); - map_init(&keyidmap, data->nkeys); - for (i = 1; i < data->nkeys; i++) + if ((flags & REPO_EXTEND_SOLVABLES) != 0) + { + /* is this a filelist extension? */ + if (repodata_has_keyname(data, SOLVABLE_FILELIST)) + repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION); + } + else + { + /* is this a primary with a filtered filelist? */ + if (data->end > data->start) { - Id keyname = data->keys[i].name; - if (keyname == SOLVABLE_INSTALLSIZE || keyname == SOLVABLE_DISKUSAGE || keyname == SOLVABLE_FILELIST) - continue; - if (keyname == SOLVABLE_MEDIADIR || keyname == SOLVABLE_MEDIAFILE || keyname == SOLVABLE_MEDIANR) - continue; - if (keyname == SOLVABLE_DOWNLOADSIZE || keyname == SOLVABLE_CHECKSUM) - continue; - if (keyname == SOLVABLE_SOURCENAME || keyname == SOLVABLE_SOURCEARCH || keyname == SOLVABLE_SOURCEEVR) - continue; - if (keyname == SOLVABLE_PKGID || keyname == SOLVABLE_HDRID || keyname == SOLVABLE_LEADSIGID) - continue; - if (keyname == SUSETAGS_SHARE_NAME || keyname == SUSETAGS_SHARE_EVR || keyname == SUSETAGS_SHARE_ARCH) - continue; - MAPSET(&keyidmap, i); + repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED); + repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST); } - last_found = 0; - for (i = 0; i < pd.nshare; i++) - { - unsigned int n, nn; - Solvable *found = 0; - if (!pd.share_with[i].name) - continue; - for (n = repo->start, nn = repo->start + last_found; n < repo->end; n++, nn++) - { - if (nn >= repo->end) - nn = repo->start; - found = pool->solvables + nn; - if (found->repo == repo - && found->name == pd.share_with[i].name - && found->evr == pd.share_with[i].evr - && found->arch == pd.share_with[i].arch) - { - last_found = nn - repo->start; - break; - } - } - if (n != repo->end) - repodata_merge_some_attrs(data, repo->start + i, repo->start + last_found, &keyidmap, 0); - } - free(pd.share_with); - map_free(&keyidmap); - } + } - solv_free(joinhash); - repodata_free_dircache(data); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); solv_free(pd.language); solv_free(line); join_freemem(&pd.jd); + queue_free(&pd.diskusageq); return pd.ret; } diff --git a/libsolv-0.6.15/ext/repo_susetags.h b/libsolv-0.7.2/ext/repo_susetags.h similarity index 100% rename from libsolv-0.6.15/ext/repo_susetags.h rename to libsolv-0.7.2/ext/repo_susetags.h diff --git a/libsolv-0.6.15/ext/repo_updateinfoxml.c b/libsolv-0.7.2/ext/repo_updateinfoxml.c similarity index 65% rename from libsolv-0.6.15/ext/repo_updateinfoxml.c rename to libsolv-0.7.2/ext/repo_updateinfoxml.c index 6af74f2..ff84d32 100644 --- a/libsolv-0.6.15/ext/repo_updateinfoxml.c +++ b/libsolv-0.7.2/ext/repo_updateinfoxml.c @@ -8,16 +8,14 @@ #define _GNU_SOURCE #define _XOPEN_SOURCE /* glibc2 needs this */ #include -#include -#include #include #include #include -#include #include #include "pool.h" #include "repo.h" +#include "solv_xmlparser.h" #include "repo_updateinfoxml.h" #define DISABLE_SPLIT #include "tools_util.h" @@ -75,16 +73,7 @@ enum state { NUMSTATES }; -struct stateswitch { - enum state from; - char *ename; - enum state to; - int docontent; -}; - - -/* !! must be sorted by first column !! */ -static struct stateswitch stateswitches[] = { +static struct solv_xmlparser_element stateswitches[] = { { STATE_START, "updates", STATE_UPDATES, 0 }, { STATE_START, "update", STATE_UPDATE, 0 }, { STATE_UPDATES, "update", STATE_UPDATE, 0 }, @@ -112,13 +101,6 @@ static struct stateswitch stateswitches[] = { struct parsedata { int ret; - int depth; - enum state state; - int statedepth; - char *content; - int lcontent; - int acontent; - int docontent; Pool *pool; Repo *repo; Repodata *data; @@ -126,10 +108,8 @@ struct parsedata { Solvable *solvable; time_t buildtime; Id collhandle; + struct solv_xmlparser xmlp; struct joindata jd; - - struct stateswitch *swtab[NUMSTATES]; - enum state sbtab[NUMSTATES]; }; /* @@ -161,7 +141,7 @@ static Id makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) { const char *e, *v, *r, *v2; - char *c; + char *c, *space; int l; e = v = r = 0; @@ -190,12 +170,8 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) l += strlen(v); if (r) l += strlen(r) + 1; - if (l > pd->acontent) - { - pd->content = realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content; + + c = space = solv_xmlparser_contentspace(&pd->xmlp, l); if (e) { strcpy(c, e); @@ -214,60 +190,25 @@ makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts) c += strlen(c); } *c = 0; - if (!*pd->content) + if (!*space) return 0; #if 0 - fprintf(stderr, "evr: %s\n", pd->content); + fprintf(stderr, "evr: %s\n", space); #endif - return pool_str2id(pool, pd->content, 1); + return pool_str2id(pool, space, 1); } -static void XMLCALL -startElement(void *userData, const char *name, const char **atts) +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *solvable = pd->solvable; - struct stateswitch *sw; - /*const char *str; */ - -#if 0 - fprintf(stderr, "start: [%d]%s\n", pd->state, name); -#endif - if (pd->depth != pd->statedepth) - { - pd->depth++; - return; - } - - pd->depth++; - if (!pd->swtab[pd->state]) - return; - for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++) /* find name in statetable */ - if (!strcmp(sw->ename, name)) - break; - - if (sw->from != pd->state) - { -#if 0 - fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state); -#endif - return; - } - pd->state = sw->to; - pd->docontent = sw->docontent; - pd->statedepth = pd->depth; - pd->lcontent = 0; - *pd->content = 0; - switch(pd->state) + switch(state) { - case STATE_START: - break; - case STATE_UPDATES: - break; /* * buildtime = (time_t)0; } break; - /* FEDORA-2007-4594 */ - case STATE_ID: - break; - /* imlib-1.9.15-6.fc8 */ - case STATE_TITLE: - break; - /* Fedora 8 */ - case STATE_RELEASE: - break; - /* - */ + case STATE_ISSUED: case STATE_UPDATED: { - const char *date = 0; - for (; *atts; atts += 2) - { - if (!strcmp(*atts, "date")) - date = atts[1]; - } + const char *date = solv_xmlparser_find_attr("date", atts); if (date) { time_t t = datestr2timestamp(date); @@ -325,13 +251,7 @@ startElement(void *userData, const char *name, const char **atts) } } break; - case STATE_REFERENCES: - break; - /* - */ + case STATE_REFERENCE: { const char *href = 0, *id = 0, *title = 0, *type = 0; @@ -359,20 +279,7 @@ startElement(void *userData, const char *name, const char **atts) repodata_add_flexarray(pd->data, pd->handle, UPDATE_REFERENCE, refhandle); } break; - /* This update ... */ - case STATE_DESCRIPTION: - break; - /* This update ... */ - case STATE_MESSAGE: - break; - case STATE_PKGLIST: - break; - /* Fedora 8 */ - case STATE_NAME: - break; + /* @@ -414,19 +321,7 @@ startElement(void *userData, const char *name, const char **atts) repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a); break; } - /* libntlm-0.4.2-1.fc8.x86_64.rpm */ - /* libntlm-0.4.2-1.fc8.x86_64.rpm */ - case STATE_FILENAME: - break; - /* True */ - case STATE_REBOOT: - break; - /* True */ - case STATE_RESTART: - break; - /* True */ - case STATE_RELOGIN: - break; + default: break; } @@ -434,34 +329,16 @@ startElement(void *userData, const char *name, const char **atts) } -static void XMLCALL -endElement(void *userData, const char *name) +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) { - struct parsedata *pd = userData; + struct parsedata *pd = xmlp->userdata; Pool *pool = pd->pool; Solvable *s = pd->solvable; Repo *repo = pd->repo; -#if 0 - fprintf(stderr, "end: %s\n", name); -#endif - if (pd->depth != pd->statedepth) + switch (state) { - pd->depth--; -#if 0 - fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); -#endif - return; - } - - pd->depth--; - pd->statedepth--; - switch (pd->state) - { - case STATE_START: - break; - case STATE_UPDATES: - break; case STATE_UPDATE: s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); if (pd->buildtime) @@ -470,80 +347,75 @@ endElement(void *userData, const char *name) pd->buildtime = (time_t)0; } break; + case STATE_ID: - s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", pd->content), 1); + s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", content), 1); break; + /* imlib-1.9.15-6.fc8 */ case STATE_TITLE: - while (pd->lcontent > 0 && pd->content[pd->lcontent - 1] == '\n') - pd->content[--pd->lcontent] = 0; - repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content); + /* strip trailing newlines */ + while (pd->xmlp.lcontent > 0 && content[pd->xmlp.lcontent - 1] == '\n') + content[--pd->xmlp.lcontent] = 0; + repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content); break; + case STATE_SEVERITY: - repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, pd->content); + repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, content); break; + case STATE_RIGHTS: - repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, pd->content); - break; - /* - * Fedora 8 - */ - case STATE_RELEASE: - break; - case STATE_ISSUED: - break; - case STATE_REFERENCES: - break; - case STATE_REFERENCE: + repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, content); break; + /* * This update ... */ case STATE_DESCRIPTION: - repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->content); + repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, content); break; + /* * Warning! ... */ case STATE_MESSAGE: - repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, pd->content); - break; - case STATE_PKGLIST: - break; - case STATE_COLLECTION: - break; - case STATE_NAME: + repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, content); break; + case STATE_PACKAGE: repodata_add_flexarray(pd->data, pd->handle, UPDATE_COLLECTION, pd->collhandle); pd->collhandle = 0; break; + /* libntlm-0.4.2-1.fc8.x86_64.rpm */ /* libntlm-0.4.2-1.fc8.x86_64.rpm */ case STATE_FILENAME: - repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content); + repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, content); break; + /* True */ case STATE_REBOOT: - if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1') + if (content[0] == 'T' || content[0] == 't'|| content[0] == '1') { /* FIXME: this is per-package, the global flag should be computed at runtime */ repodata_set_void(pd->data, pd->handle, UPDATE_REBOOT); repodata_set_void(pd->data, pd->collhandle, UPDATE_REBOOT); } break; + /* True */ case STATE_RESTART: - if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1') + if (content[0] == 'T' || content[0] == 't'|| content[0] == '1') { /* FIXME: this is per-package, the global flag should be computed at runtime */ repodata_set_void(pd->data, pd->handle, UPDATE_RESTART); repodata_set_void(pd->data, pd->collhandle, UPDATE_RESTART); } break; + /* True */ case STATE_RELOGIN: - if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1') + if (content[0] == 'T' || content[0] == 't'|| content[0] == '1') { /* FIXME: this is per-package, the global flag should be computed at runtime */ repodata_set_void(pd->data, pd->handle, UPDATE_RELOGIN); @@ -553,86 +425,25 @@ endElement(void *userData, const char *name) default: break; } - - pd->state = pd->sbtab[pd->state]; - pd->docontent = 0; } - -static void XMLCALL -characterData(void *userData, const XML_Char *s, int len) -{ - struct parsedata *pd = userData; - int l; - char *c; - - if (!pd->docontent) - { -#if 0 - fprintf(stderr, "Content: [%d]'%.*s'\n", pd->state, len, s); -#endif - return; - } - l = pd->lcontent + len + 1; - if (l > pd->acontent) - { - pd->content = realloc(pd->content, l + 256); - pd->acontent = l + 256; - } - c = pd->content + pd->lcontent; - pd->lcontent += len; - while (len-- > 0) - *c++ = *s++; - *c = 0; -} - - -#define BUFF_SIZE 8192 - int repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags) { Pool *pool = repo->pool; - struct parsedata pd; - char buf[BUFF_SIZE]; - int i, l; - struct stateswitch *sw; Repodata *data; - XML_Parser parser; + struct parsedata pd; data = repo_add_repodata(repo, flags); memset(&pd, 0, sizeof(pd)); - for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++) - { - if (!pd.swtab[sw->from]) - pd.swtab[sw->from] = sw; - pd.sbtab[sw->to] = sw->from; - } pd.pool = pool; pd.repo = repo; pd.data = data; - - pd.content = malloc(256); - pd.acontent = 256; - pd.lcontent = 0; - parser = XML_ParserCreate(NULL); - XML_SetUserData(parser, &pd); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterData); - for (;;) - { - l = fread(buf, 1, sizeof(buf), fp); - if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR) - { - pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser)); - break; - } - if (l == 0) - break; - } - XML_ParserFree(parser); - free(pd.content); + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + solv_xmlparser_free(&pd.xmlp); join_freemem(&pd.jd); if (!(flags & REPO_NO_INTERNALIZE)) diff --git a/libsolv-0.6.15/ext/repo_updateinfoxml.h b/libsolv-0.7.2/ext/repo_updateinfoxml.h similarity index 100% rename from libsolv-0.6.15/ext/repo_updateinfoxml.h rename to libsolv-0.7.2/ext/repo_updateinfoxml.h diff --git a/libsolv-0.7.2/ext/repo_zyppdb.c b/libsolv-0.7.2/ext/repo_zyppdb.c new file mode 100644 index 0000000..f6e2bfa --- /dev/null +++ b/libsolv-0.7.2/ext/repo_zyppdb.c @@ -0,0 +1,200 @@ +/* + * repo_zyppdb.c + * + * Parses legacy /var/lib/zypp/db/products/... files. + * They are old (pre Code11) product descriptions. See bnc#429177 + * + * Copyright (c) 2008, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "solv_xmlparser.h" +#define DISABLE_SPLIT +#include "tools_util.h" +#include "repo_zyppdb.h" + + +enum state { + STATE_START, + STATE_PRODUCT, + STATE_NAME, + STATE_VERSION, + STATE_ARCH, + STATE_SUMMARY, + STATE_VENDOR, + STATE_INSTALLTIME, + NUMSTATES +}; + +static struct solv_xmlparser_element stateswitches[] = { + { STATE_START, "product", STATE_PRODUCT, 0 }, + { STATE_PRODUCT, "name", STATE_NAME, 1 }, + { STATE_PRODUCT, "version", STATE_VERSION, 0 }, + { STATE_PRODUCT, "arch", STATE_ARCH, 1 }, + { STATE_PRODUCT, "summary", STATE_SUMMARY, 1 }, + { STATE_PRODUCT, "install-time", STATE_INSTALLTIME, 1 }, + { STATE_PRODUCT, "vendor", STATE_VENDOR, 1 }, + { NUMSTATES } +}; + +struct parsedata { + Pool *pool; + Repo *repo; + Repodata *data; + const char *filename; + const char *tmplang; + Solvable *solvable; + Id handle; + struct solv_xmlparser xmlp; + struct joindata jd; +}; + + + +static void +startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts) +{ + struct parsedata *pd = xmlp->userdata; + Pool *pool = pd->pool; + Solvable *s = pd->solvable; + + switch(state) + { + case STATE_PRODUCT: + { + /* parse 'type' */ + const char *type = solv_xmlparser_find_attr("type", atts); + s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo)); + pd->handle = s - pool->solvables; + if (type) + repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, type); + } + break; + case STATE_VERSION: + { + const char *ver = solv_xmlparser_find_attr("ver", atts); + const char *rel = solv_xmlparser_find_attr("rel", atts); + /* const char *epoch = solv_xmlparser_find_attr("epoch", atts); ignored */ + s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel)); + } + break; + case STATE_SUMMARY: /* ... */ + pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts)); + break; + default: + break; + } +} + + +static void +endElement(struct solv_xmlparser *xmlp, int state, char *content) +{ + struct parsedata *pd = xmlp->userdata; + Solvable *s = pd->solvable; + + switch (state) + { + case STATE_PRODUCT: + if (!s->arch) + s->arch = ARCH_NOARCH; + if (!s->evr) + s->evr = ID_EMPTY; + if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0); + pd->solvable = 0; + break; + case STATE_NAME: + s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1); + break; + case STATE_ARCH: + s->arch = pool_str2id(pd->pool, content, 1); + break; + case STATE_SUMMARY: + repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content); + break; + case STATE_VENDOR: + s->vendor = pool_str2id(pd->pool, content, 1); + break; + case STATE_INSTALLTIME: + repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(content)); + default: + break; + } +} + + +/* + * read all installed products + * + * parse each one as a product + */ + +int +repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags) +{ + struct parsedata pd; + struct dirent *entry; + char *fullpath; + DIR *dir; + FILE *fp; + Repodata *data; + + data = repo_add_repodata(repo, flags); + memset(&pd, 0, sizeof(pd)); + pd.repo = repo; + pd.pool = repo->pool; + pd.data = data; + solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement); + + if (flags & REPO_USE_ROOTDIR) + dirpath = pool_prepend_rootdir(repo->pool, dirpath); + dir = opendir(dirpath); + if (dir) + { + while ((entry = readdir(dir))) + { + if (entry->d_name[0] == '.') + continue; /* skip dot files */ + fullpath = join2(&pd.jd, dirpath, "/", entry->d_name); + if ((fp = fopen(fullpath, "r")) == 0) + { + pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno)); + continue; + } + pd.filename = entry->d_name; + if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK) + { + pool_debug(pd.pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column); + pd.solvable = solvable_free(pd.solvable, 1); + } + fclose(fp); + } + } + closedir(dir); + + solv_xmlparser_free(&pd.xmlp); + join_freemem(&pd.jd); + if (flags & REPO_USE_ROOTDIR) + solv_free((char *)dirpath); + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return 0; +} + +/* EOF */ diff --git a/libsolv-0.6.15/ext/repo_zyppdb.h b/libsolv-0.7.2/ext/repo_zyppdb.h similarity index 100% rename from libsolv-0.6.15/ext/repo_zyppdb.h rename to libsolv-0.7.2/ext/repo_zyppdb.h diff --git a/libsolv-0.7.2/ext/repodata_diskusage.c b/libsolv-0.7.2/ext/repodata_diskusage.c new file mode 100644 index 0000000..fd9c5cc --- /dev/null +++ b/libsolv-0.7.2/ext/repodata_diskusage.c @@ -0,0 +1,78 @@ +/* + * repodata_diskusage.c + * + * Small helper to convert diskusage data from sustags or rpmmd + * + * Copyright (c) 2017, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "repodata_diskusage.h" + +/* The queue contains (dirid, kbytes, inodes) triplets */ + +static int +add_diskusage_sortfn(const void *ap, const void *bp, void *dp) +{ + return *(Id *)ap - *(Id *)bp; +} + +void +repodata_add_diskusage(Repodata *data, Id handle, Queue *q) +{ + int i, j; + Dirpool *dp = &data->dirpool; + + /* Sort in dirid order. This ensures that parents come before + * their children. */ + if (q->count > 3) + solv_sort(q->elements, q->count / 3, 3 * sizeof(Id), add_diskusage_sortfn, 0); + for (i = 3; i < q->count; i += 3) + { + /* subtract data from parent */ + Id did = q->elements[i]; + if (i + 3 < q->count && q->elements[i + 3] == did) + { + /* identical directory entry! zero this one */ + q->elements[i + 1] = 0; + q->elements[i + 2] = 0; + continue; + } + while (did) + { + did = dirpool_parent(dp, did); + for (j = i - 3; j >= 0; j -= 3) + if (q->elements[j] == did) + break; + if (j >= 0) + { + if ((unsigned int)q->elements[j + 1] > (unsigned int)q->elements[i + 1]) + q->elements[j + 1] -= q->elements[i + 1]; + else + q->elements[j + 1] = 0; + if ((unsigned int)q->elements[j + 2] > (unsigned int)q->elements[i + 2]) + q->elements[j + 2] -= q->elements[i + 2]; + else + q->elements[j + 2] = 0; + break; + } + } + } + /* now commit data */ + for (i = 0; i < q->count; i += 3) + if (q->elements[i + 1] || q->elements[i + 2]) + repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, q->elements[i], q->elements[i + 1], q->elements[i + 2]); + /* empty queue */ + queue_empty(q); +} + diff --git a/libsolv-0.7.2/ext/repodata_diskusage.h b/libsolv-0.7.2/ext/repodata_diskusage.h new file mode 100644 index 0000000..1beafea --- /dev/null +++ b/libsolv-0.7.2/ext/repodata_diskusage.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2017, SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +extern void repodata_add_diskusage(Repodata *data, Id handle, Queue *q); + + diff --git a/libsolv-0.7.2/ext/solv_jsonparser.c b/libsolv-0.7.2/ext/solv_jsonparser.c new file mode 100644 index 0000000..053ee6f --- /dev/null +++ b/libsolv-0.7.2/ext/solv_jsonparser.c @@ -0,0 +1,294 @@ +/* + * solv_jsonparser.c + * + * Simple JSON stream parser + * + * Copyright (c) 2018, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include + +#include "util.h" +#include "solv_jsonparser.h" + +struct solv_jsonparser * +jsonparser_init(struct solv_jsonparser *jp, FILE *fp) +{ + memset(jp, 0, sizeof(*jp)); + jp->fp = fp; + jp->state = JP_START; + jp->line = jp->nextline = 1; + jp->nextc = ' '; + queue_init(&jp->stateq); + return jp; +} + +struct solv_jsonparser * +jsonparser_free(struct solv_jsonparser *jp) +{ + queue_free(&jp->stateq); + return 0; +} + +static void +savec(struct solv_jsonparser *jp, char c) +{ + if (jp->nspace == jp->aspace) + { + jp->aspace += 256; + jp->space = solv_realloc(jp->space, jp->aspace); + } + jp->space[jp->nspace++] = c; +} + +static void +saveutf8(struct solv_jsonparser *jp, int c) +{ + int i; + if (c < 0x80) + { + savec(jp, c); + return; + } + i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3; + savec(jp, (0x1f80 >> i) | (c >> (6 * i))); + while (--i >= 0) + savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f)); +} + +static inline int +nextc(struct solv_jsonparser *jp) +{ + int c = getc(jp->fp); + if (c == '\n') + jp->nextline++; + return c; +} + +static int +skipspace(struct solv_jsonparser *jp) +{ + int c = jp->nextc; + while (c == ' ' || c == '\t' || c == '\r' || c == '\n') + c = nextc(jp); + jp->line = jp->nextline; + return (jp->nextc = c); +} + +static int +parseliteral(struct solv_jsonparser *jp) +{ + size_t nspace = jp->nspace; + int c; + savec(jp, jp->nextc); + for (;;) + { + c = nextc(jp); + if (c < 'a' || c > 'z') + break; + savec(jp, c); + } + jp->nextc = c; + savec(jp, 0); + if (!strcmp(jp->space + nspace, "true")) + return JP_BOOL; + if (!strcmp(jp->space + nspace, "false")) + return JP_BOOL; + if (!strcmp(jp->space + nspace, "null")) + return JP_NULL; + return JP_ERROR; +} + +static int +parsenumber(struct solv_jsonparser *jp) +{ + int c; + savec(jp, jp->nextc); + for (;;) + { + c = nextc(jp); + if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E') + break; + savec(jp, c); + } + jp->nextc = c; + savec(jp, 0); + return JP_NUMBER; +} + +static int +parseutf8(struct solv_jsonparser *jp, int surrogate) +{ + int c, i, r = 0; + /* parse 4-digit hex */ + for (i = 0; i < 4; i++) + { + c = nextc(jp); + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else + return -1; + r = (r << 4) | c; + } + if (!surrogate && r >= 0xd800 && r < 0xdc00) + { + /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */ + int r2; + if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000) + return -1; + r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff)); + } + return r; +} + +static int +parsestring(struct solv_jsonparser *jp) +{ + int c; + for (;;) + { + if ((c = nextc(jp)) < 32) + return JP_ERROR; + if (c == '"') + break; + if (c == '\\') + { + switch (c = nextc(jp)) + { + case '"': + case '\\': + case '/': + case '\n': + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'u': + if ((c = parseutf8(jp, 0)) < 0) + return JP_ERROR; + saveutf8(jp, c); + continue; + default: + return JP_ERROR; + } + } + savec(jp, c); + } + jp->nextc = ' '; + savec(jp, 0); + return JP_STRING; +} + +static int +parsevalue(struct solv_jsonparser *jp) +{ + int c = skipspace(jp); + if (c == '"') + return parsestring(jp); + if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.') + return parsenumber(jp); + if ((c >= 'a' && c <= 'z')) + return parseliteral(jp); + jp->nextc = ' '; + if (c == '[') + return JP_ARRAY; + if (c == '{') + return JP_OBJECT; + if (c == ']') + return JP_ARRAY_END; + if (c == '}') + return JP_OBJECT_END; + return JP_ERROR; +} + +int +jsonparser_parse(struct solv_jsonparser *jp) +{ + int type; + size_t nspace; + + jp->depth = jp->stateq.count; + jp->key = jp->value = 0; + jp->keylen = jp->valuelen = 0; + nspace = jp->nspace = 0; + + if (jp->state == JP_END) + return JP_END; + if (jp->state == JP_START) + jp->state = JP_END; + type = parsevalue(jp); + if (type <= 0) + return JP_ERROR; + if (type == JP_OBJECT_END || type == JP_ARRAY_END) + { + if (jp->state != type - 1) + return JP_ERROR; + jp->state = queue_pop(&jp->stateq); + } + else if (jp->state == JP_OBJECT) + { + nspace = jp->nspace; + if (type != JP_STRING) + return JP_ERROR; + if (skipspace(jp) != ':') + return JP_ERROR; + jp->nextc = ' '; + type = parsevalue(jp); + if (type == JP_OBJECT_END || type == JP_ARRAY_END) + return JP_ERROR; + jp->key = jp->space; + jp->keylen = nspace - 1; + } + if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL) + { + jp->value = jp->space + nspace; + jp->valuelen = jp->nspace - nspace - 1; + } + if (type == JP_ARRAY || type == JP_OBJECT) + { + queue_push(&jp->stateq, jp->state); + jp->state = type; + } + else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY) + { + int c = skipspace(jp); + if (c == ',') + jp->nextc = ' '; + else if (c != (jp->state == JP_OBJECT ? '}' : ']')) + return JP_ERROR; + } + return type; +} + +int +jsonparser_skip(struct solv_jsonparser *jp, int type) +{ + if (type == JP_ARRAY || type == JP_OBJECT) + { + int depth = jp->depth + 1, endtype = type + 1; + while (type > 0 && (type != endtype || jp->depth != depth)) + type = jsonparser_parse(jp); + } + return type; +} + diff --git a/libsolv-0.7.2/ext/solv_jsonparser.h b/libsolv-0.7.2/ext/solv_jsonparser.h new file mode 100644 index 0000000..d58d9e3 --- /dev/null +++ b/libsolv-0.7.2/ext/solv_jsonparser.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#ifndef SOLV_JSONPARSER_H +#define SOLV_JSONPARSER_H + +#include "queue.h" + +struct solv_jsonparser { + FILE *fp; + int line; + int depth; + + char *key; + size_t keylen; + char *value; + size_t valuelen; + + int state; + Queue stateq; + int nextc; + int nextline; + char *space; + size_t nspace; + size_t aspace; +}; + +#define JP_ERROR -1 +#define JP_END 0 +#define JP_START 1 +#define JP_STRING 2 +#define JP_NUMBER 3 +#define JP_BOOL 4 +#define JP_NULL 5 +#define JP_OBJECT 6 +#define JP_OBJECT_END 7 +#define JP_ARRAY 8 +#define JP_ARRAY_END 9 + +struct solv_jsonparser *jsonparser_init(struct solv_jsonparser *jp, FILE *fp); +struct solv_jsonparser *jsonparser_free(struct solv_jsonparser *jp); +int jsonparser_parse(struct solv_jsonparser *jp); +int jsonparser_skip(struct solv_jsonparser *jp, int type); + +#endif /* SOLV_JSONPARSER_H */ diff --git a/libsolv-0.6.15/ext/solv_pgpvrfy.c b/libsolv-0.7.2/ext/solv_pgpvrfy.c similarity index 100% rename from libsolv-0.6.15/ext/solv_pgpvrfy.c rename to libsolv-0.7.2/ext/solv_pgpvrfy.c diff --git a/libsolv-0.6.15/ext/solv_pgpvrfy.h b/libsolv-0.7.2/ext/solv_pgpvrfy.h similarity index 100% rename from libsolv-0.6.15/ext/solv_pgpvrfy.h rename to libsolv-0.7.2/ext/solv_pgpvrfy.h diff --git a/libsolv-0.6.15/ext/solv_xfopen.c b/libsolv-0.7.2/ext/solv_xfopen.c similarity index 59% rename from libsolv-0.6.15/ext/solv_xfopen.c rename to libsolv-0.7.2/ext/solv_xfopen.c index b0421bf..343aed8 100644 --- a/libsolv-0.6.15/ext/solv_xfopen.c +++ b/libsolv-0.7.2/ext/solv_xfopen.c @@ -10,30 +10,12 @@ #include #include #include -#include #include #include "solv_xfopen.h" #include "util.h" -/* Evil hack for Haiku: fopencookie() is implemented internally, but not - exported by a header. */ -#ifdef __HAIKU__ - -typedef struct { - ssize_t (*read)(void*, char*, size_t); - ssize_t (*write)(void*, const char*, size_t); - int (*seek)(off_t*, int); - int (*close)(void*); -} cookie_io_functions_t; - - -FILE *fopencookie(void*, const char*, cookie_io_functions_t); - -#endif /* __HAIKU__ */ - - static FILE *cookieopen(void *cookie, const char *mode, ssize_t (*cread)(void *, char *, size_t), ssize_t (*cwrite)(void *, const char *, size_t), @@ -66,8 +48,12 @@ static FILE *cookieopen(void *cookie, const char *mode, } +#ifdef ENABLE_ZLIB_COMPRESSION + /* gzip compression */ +#include + static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes) { return gzread((gzFile)cookie, buf, nbytes); @@ -95,12 +81,15 @@ static inline FILE *mygzfdopen(int fd, const char *mode) return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose); } -#ifdef ENABLE_BZIP2_COMPRESSION +#endif -#include + +#ifdef ENABLE_BZIP2_COMPRESSION /* bzip2 compression */ +#include + static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes) { return BZ2_bzread((BZFILE *)cookie, buf, nbytes); @@ -134,10 +123,10 @@ static inline FILE *mybzfdopen(int fd, const char *mode) #ifdef ENABLE_LZMA_COMPRESSION -#include - /* lzma code written by me in 2008 for rpm's rpmio.c */ +#include + typedef struct lzfile { unsigned char buf[1 << 15]; lzma_stream strm; @@ -327,6 +316,292 @@ static inline FILE *mylzfdopen(int fd, const char *mode) #endif /* ENABLE_LZMA_COMPRESSION */ +#ifdef ENABLE_ZSTD_COMPRESSION + +#include + +typedef struct zstdfile { + ZSTD_CStream *cstream; + ZSTD_DStream *dstream; + FILE *file; + int encoding; + int eof; + ZSTD_inBuffer in; + ZSTD_outBuffer out; + unsigned char buf[1 << 15]; +} ZSTDFILE; + +static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd) +{ + int level = 7; + int encoding = 0; + FILE *fp; + ZSTDFILE *zstdfile; + + if (!path && fd < 0) + return 0; + for (; *mode; mode++) + { + if (*mode == 'w') + encoding = 1; + else if (*mode == 'r') + encoding = 0; + else if (*mode >= '1' && *mode <= '9') + level = *mode - '0'; + } + if (fd != -1) + fp = fdopen(fd, encoding ? "w" : "r"); + else + fp = fopen(path, encoding ? "w" : "r"); + if (!fp) + return 0; + zstdfile = solv_calloc(1, sizeof(*zstdfile)); + zstdfile->encoding = encoding; + if (encoding) + { + zstdfile->cstream = ZSTD_createCStream(); + zstdfile->encoding = 1; + if (!zstdfile->cstream) + { + solv_free(zstdfile); + fclose(fp); + return 0; + } + if (ZSTD_isError(ZSTD_initCStream(zstdfile->cstream, level))) + { + ZSTD_freeCStream(zstdfile->cstream); + solv_free(zstdfile); + fclose(fp); + return 0; + } + zstdfile->out.dst = zstdfile->buf; + zstdfile->out.pos = 0; + zstdfile->out.size = sizeof(zstdfile->buf); + } + else + { + zstdfile->dstream = ZSTD_createDStream(); + if (ZSTD_isError(ZSTD_initDStream(zstdfile->dstream))) + { + ZSTD_freeDStream(zstdfile->dstream); + solv_free(zstdfile); + fclose(fp); + return 0; + } + zstdfile->in.src = zstdfile->buf; + zstdfile->in.pos = 0; + zstdfile->in.size = 0; + } + zstdfile->file = fp; + return zstdfile; +} + +static int zstdclose(void *cookie) +{ + ZSTDFILE *zstdfile = cookie; + int rc; + + if (!zstdfile) + return -1; + if (zstdfile->encoding) + { + for (;;) + { + size_t ret; + zstdfile->out.pos = 0; + ret = ZSTD_endStream(zstdfile->cstream, &zstdfile->out); + if (ZSTD_isError(ret)) + return -1; + if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos) + return -1; + if (ret == 0) + break; + } + ZSTD_freeCStream(zstdfile->cstream); + } + else + { + ZSTD_freeDStream(zstdfile->dstream); + } + rc = fclose(zstdfile->file); + free(zstdfile); + return rc; +} + +static ssize_t zstdread(void *cookie, char *buf, size_t len) +{ + ZSTDFILE *zstdfile = cookie; + int eof = 0; + size_t ret = 0; + if (!zstdfile || zstdfile->encoding) + return -1; + if (zstdfile->eof) + return 0; + zstdfile->out.dst = buf; + zstdfile->out.pos = 0; + zstdfile->out.size = len; + for (;;) + { + if (!eof && zstdfile->in.pos == zstdfile->in.size) + { + zstdfile->in.pos = 0; + zstdfile->in.size = fread(zstdfile->buf, 1, sizeof(zstdfile->buf), zstdfile->file); + if (!zstdfile->in.size) + eof = 1; + } + if (ret || !eof) + ret = ZSTD_decompressStream(zstdfile->dstream, &zstdfile->out, &zstdfile->in); + if (ret == 0 && eof) + { + zstdfile->eof = 1; + return zstdfile->out.pos; + } + if (ZSTD_isError(ret)) + return -1; + if (zstdfile->out.pos == len) + return len; + } +} + +static ssize_t zstdwrite(void *cookie, const char *buf, size_t len) +{ + ZSTDFILE *zstdfile = cookie; + if (!zstdfile || !zstdfile->encoding) + return -1; + if (!len) + return 0; + zstdfile->in.src = buf; + zstdfile->in.pos = 0; + zstdfile->in.size = len; + + for (;;) + { + size_t ret; + zstdfile->out.pos = 0; + ret = ZSTD_compressStream(zstdfile->cstream, &zstdfile->out, &zstdfile->in); + if (ZSTD_isError(ret)) + return -1; + if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos) + return -1; + if (zstdfile->in.pos == len) + return len; + } +} + +static inline FILE *myzstdfopen(const char *fn, const char *mode) +{ + ZSTDFILE *zstdfile = zstdopen(fn, mode, -1); + return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose); +} + +static inline FILE *myzstdfdopen(int fd, const char *mode) +{ + ZSTDFILE *zstdfile = zstdopen(0, mode, fd); + return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose); +} + +#endif + +#ifdef ENABLE_ZCHUNK_COMPRESSION + +#ifdef WITH_SYSTEM_ZCHUNK +/* use the system's zchunk library that supports reading and writing of zchunk files */ + +#include + +static ssize_t cookie_zckread(void *cookie, char *buf, size_t nbytes) +{ + return zck_read((zckCtx *)cookie, buf, nbytes); +} + +static ssize_t cookie_zckwrite(void *cookie, const char *buf, size_t nbytes) +{ + return zck_write((zckCtx *)cookie, buf, nbytes); +} + +static int cookie_zckclose(void *cookie) +{ + zckCtx *zck = (zckCtx *)cookie; + int fd = zck_get_fd(zck); + if (fd != -1) + close(fd); + zck_free(&zck); + return 0; +} + +static void *zchunkopen(const char *path, const char *mode, int fd) +{ + zckCtx *f; + + if (!path && fd < 0) + return 0; + if (fd == -1) + { + if (*mode != 'w') + fd = open(path, O_RDONLY); + else + fd = open(path, O_WRONLY | O_CREAT, 0666); + if (fd == -1) + return 0; + } + f = zck_create(); + if (!f) + { + close(fd); + return 0; + } + if (*mode != 'w') + { + if(!zck_init_read(f, fd)) + return 0; + } + else + { + if(!zck_init_write(f, fd)) + return 0; + } + return cookieopen(f, mode, cookie_zckread, cookie_zckwrite, cookie_zckclose); +} + +#else + +#include "solv_zchunk.h" +/* use the libsolv's limited zchunk implementation that only supports reading of zchunk files */ + +static void *zchunkopen(const char *path, const char *mode, int fd) +{ + FILE *fp; + void *f; + if (!path && fd < 0) + return 0; + if (fd != -1) + fp = fdopen(fd, mode); + else + fp = fopen(path, mode); + if (!fp) + return 0; + if (strcmp(mode, "r") != 0) + return 0; + f = solv_zchunk_open(fp, 1); + if (!f) + fclose(fp); + return cookieopen(f, mode, (ssize_t (*)(void *, char *, size_t))solv_zchunk_read, 0, (int (*)(void *))solv_zchunk_close); +} + +#endif + +static inline FILE *myzchunkfopen(const char *fn, const char *mode) +{ + return zchunkopen(fn, mode, -1); +} + +static inline FILE *myzchunkfdopen(int fd, const char *mode) +{ + return zchunkopen(0, mode, fd); +} + +#endif /* ENABLE_ZCHUNK_COMPRESSION */ + FILE * solv_xfopen(const char *fn, const char *mode) @@ -338,8 +613,13 @@ solv_xfopen(const char *fn, const char *mode) if (!mode) mode = "r"; suf = strrchr(fn, '.'); +#ifdef ENABLE_ZLIB_COMPRESSION if (suf && !strcmp(suf, ".gz")) return mygzfopen(fn, mode); +#else + if (suf && !strcmp(suf, ".gz")) + return 0; +#endif #ifdef ENABLE_LZMA_COMPRESSION if (suf && !strcmp(suf, ".xz")) return myxzfopen(fn, mode); @@ -358,6 +638,20 @@ solv_xfopen(const char *fn, const char *mode) if (suf && !strcmp(suf, ".bz2")) return 0; #endif +#ifdef ENABLE_ZSTD_COMPRESSION + if (suf && !strcmp(suf, ".zst")) + return myzstdfopen(fn, mode); +#else + if (suf && !strcmp(suf, ".zst")) + return 0; +#endif +#ifdef ENABLE_ZCHUNK_COMPRESSION + if (suf && !strcmp(suf, ".zck")) + return myzchunkfopen(fn, mode); +#else + if (suf && !strcmp(suf, ".zck")) + return 0; +#endif return fopen(fn, mode); } @@ -384,8 +678,13 @@ solv_xfopen_fd(const char *fn, int fd, const char *mode) else mode = simplemode = "r"; } +#ifdef ENABLE_ZLIB_COMPRESSION if (suf && !strcmp(suf, ".gz")) return mygzfdopen(fd, simplemode); +#else + if (suf && !strcmp(suf, ".gz")) + return 0; +#endif #ifdef ENABLE_LZMA_COMPRESSION if (suf && !strcmp(suf, ".xz")) return myxzfdopen(fd, simplemode); @@ -404,6 +703,20 @@ solv_xfopen_fd(const char *fn, int fd, const char *mode) if (suf && !strcmp(suf, ".bz2")) return 0; #endif +#ifdef ENABLE_ZSTD_COMPRESSION + if (suf && !strcmp(suf, ".zst")) + return myzstdfdopen(fd, simplemode); +#else + if (suf && !strcmp(suf, ".zst")) + return 0; +#endif +#ifdef ENABLE_ZCHUNK_COMPRESSION + if (suf && !strcmp(suf, ".zck")) + return myzchunkfdopen(fd, simplemode); +#else + if (suf && !strcmp(suf, ".zck")) + return 0; +#endif return fdopen(fd, mode); } @@ -413,8 +726,12 @@ solv_xfopen_iscompressed(const char *fn) const char *suf = fn ? strrchr(fn, '.') : 0; if (!suf) return 0; +#ifdef ENABLE_ZLIB_COMPRESSION if (!strcmp(suf, ".gz")) return 1; +#else + return -1; +#endif if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma")) #ifdef ENABLE_LZMA_COMPRESSION return 1; @@ -427,6 +744,18 @@ solv_xfopen_iscompressed(const char *fn) #else return -1; #endif + if (!strcmp(suf, ".zst")) +#ifdef ENABLE_ZSTD_COMPRESSION + return 1; +#else + return -1; +#endif + if (!strcmp(suf, ".zck")) +#ifdef ENABLE_ZCHUNK_COMPRESSION + return 1; +#else + return -1; +#endif return 0; } diff --git a/libsolv-0.6.15/ext/solv_xfopen.h b/libsolv-0.7.2/ext/solv_xfopen.h similarity index 100% rename from libsolv-0.6.15/ext/solv_xfopen.h rename to libsolv-0.7.2/ext/solv_xfopen.h diff --git a/libsolv-0.7.2/ext/solv_xmlparser.c b/libsolv-0.7.2/ext/solv_xmlparser.c new file mode 100644 index 0000000..6292663 --- /dev/null +++ b/libsolv-0.7.2/ext/solv_xmlparser.c @@ -0,0 +1,334 @@ +/* + * solv_xmlparser.c + * + * XML parser abstraction + * + * Copyright (c) 2017, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include + +#ifdef WITH_LIBXML2 +#include +#else +#include +#endif + +#include "util.h" +#include "queue.h" +#include "solv_xmlparser.h" + +static inline void +add_contentspace(struct solv_xmlparser *xmlp, int l) +{ + l += xmlp->lcontent + 1; /* plus room for trailing zero */ + if (l > xmlp->acontent) + { + xmlp->acontent = l + 256; + xmlp->content = solv_realloc(xmlp->content, xmlp->acontent); + } +} + + +#ifdef WITH_LIBXML2 +static void +character_data(void *userData, const xmlChar *s, int len) +#else +static void XMLCALL +character_data(void *userData, const XML_Char *s, int len) +#endif +{ + struct solv_xmlparser *xmlp = userData; + + if (!xmlp->docontent || !len) + return; + add_contentspace(xmlp, len); + memcpy(xmlp->content + xmlp->lcontent, s, len); + xmlp->lcontent += len; +} + +#ifdef WITH_LIBXML2 +static void +start_element(void *userData, const xmlChar *name, const xmlChar **atts) +#else +static void XMLCALL +start_element(void *userData, const char *name, const char **atts) +#endif +{ + struct solv_xmlparser *xmlp = userData; + struct solv_xmlparser_element *elements; + Id *elementhelper; + struct solv_xmlparser_element *el; + int i, oldstate; + + if (xmlp->unknowncnt) + { + xmlp->unknowncnt++; + return; + } + elementhelper = xmlp->elementhelper; + elements = xmlp->elements; + oldstate = xmlp->state; + for (i = elementhelper[xmlp->nelements + oldstate]; i; i = elementhelper[i - 1]) + if (!strcmp(elements[i - 1].element, (char *)name)) + break; + if (!i) + { +#if 0 + fprintf(stderr, "into unknown: %s\n", name); +#endif + xmlp->unknowncnt++; + return; + } + el = xmlp->elements + i - 1; + queue_push(&xmlp->elementq, xmlp->state); + xmlp->state = el->tostate; + xmlp->docontent = el->docontent; + xmlp->lcontent = 0; +#ifdef WITH_LIBXML2 + if (!atts) + { + static const char *nullattr; + atts = (const xmlChar **)&nullattr; + } +#endif + if (xmlp->state != oldstate) + xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts); +} + +#ifdef WITH_LIBXML2 +static void +end_element(void *userData, const xmlChar *name) +#else +static void XMLCALL +end_element(void *userData, const char *name) +#endif +{ + struct solv_xmlparser *xmlp = userData; + + if (xmlp->unknowncnt) + { + xmlp->unknowncnt--; + xmlp->lcontent = 0; + xmlp->docontent = 0; + return; + } + xmlp->content[xmlp->lcontent] = 0; + if (xmlp->elementq.count && xmlp->state != xmlp->elementq.elements[xmlp->elementq.count - 1]) + xmlp->endelement(xmlp, xmlp->state, xmlp->content); + xmlp->state = queue_pop(&xmlp->elementq); + xmlp->docontent = 0; + xmlp->lcontent = 0; +} + +void +solv_xmlparser_init(struct solv_xmlparser *xmlp, + struct solv_xmlparser_element *elements, + void *userdata, + void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts), + void (*endelement)(struct solv_xmlparser *, int state, char *content)) +{ + int i, nstates, nelements; + struct solv_xmlparser_element *el; + Id *elementhelper; + + memset(xmlp, 0, sizeof(*xmlp)); + nstates = 0; + nelements = 0; + for (el = elements; el->element; el++) + { + nelements++; + if (el->fromstate > nstates) + nstates = el->fromstate; + if (el->tostate > nstates) + nstates = el->tostate; + } + nstates++; + + xmlp->elements = elements; + xmlp->nelements = nelements; + elementhelper = solv_calloc(nelements + nstates, sizeof(Id)); + for (i = nelements - 1; i >= 0; i--) + { + int fromstate = elements[i].fromstate; + elementhelper[i] = elementhelper[nelements + fromstate]; + elementhelper[nelements + fromstate] = i + 1; + } + xmlp->elementhelper = elementhelper; + queue_init(&xmlp->elementq); + xmlp->acontent = 256; + xmlp->content = solv_malloc(xmlp->acontent); + + xmlp->userdata = userdata; + xmlp->startelement = startelement; + xmlp->endelement = endelement; +} + +void +solv_xmlparser_free(struct solv_xmlparser *xmlp) +{ + xmlp->elementhelper = solv_free(xmlp->elementhelper); + queue_free(&xmlp->elementq); + xmlp->content = solv_free(xmlp->content); + xmlp->errstr = solv_free(xmlp->errstr); +} + +static void +set_error(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column) +{ + solv_free(xmlp->errstr); + xmlp->errstr = solv_strdup(errstr); + xmlp->line = line; + xmlp->column = column; +} + +#ifdef WITH_LIBXML2 + +static inline int +create_parser(struct solv_xmlparser *xmlp) +{ + /* delayed to parse_block so that we have the first bytes */ + return 1; +} + +static inline void +free_parser(struct solv_xmlparser *xmlp) +{ + if (xmlp->parser) + xmlFreeParserCtxt(xmlp->parser); + xmlp->parser = 0; +} + +static xmlParserCtxtPtr +create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l) +{ + xmlSAXHandler sax; + memset(&sax, 0, sizeof(sax)); + sax.startElement = start_element; + sax.endElement = end_element; + sax.characters = character_data; + return xmlCreatePushParserCtxt(&sax, xmlp, buf, l, NULL); +} + +static inline int +parse_block(struct solv_xmlparser *xmlp, char *buf, int l) +{ + if (!xmlp->parser) + { + int l2 = l > 4 ? 4 : 0; + xmlp->parser = create_parser_ctx(xmlp, buf, l2); + if (!xmlp->parser) + { + set_error(xmlp, "could not create parser", 0, 0); + return 0; + } + buf += l2; + l -= l2; + if (l2 && !l) + return 1; + } + if (xmlParseChunk(xmlp->parser, buf, l, l == 0 ? 1 : 0)) + { + xmlErrorPtr err = xmlCtxtGetLastError(xmlp->parser); + set_error(xmlp, err->message, err->line, err->int2); + return 0; + } + return 1; +} + +unsigned int +solv_xmlparser_lineno(struct solv_xmlparser *xmlp) +{ + return (unsigned int)xmlSAX2GetLineNumber(xmlp->parser); +} + +#else + +static inline int +create_parser(struct solv_xmlparser *xmlp) +{ + xmlp->parser = XML_ParserCreate(NULL); + if (!xmlp->parser) + return 0; + XML_SetUserData(xmlp->parser, xmlp); + XML_SetElementHandler(xmlp->parser, start_element, end_element); + XML_SetCharacterDataHandler(xmlp->parser, character_data); + return 1; +} + +static inline void +free_parser(struct solv_xmlparser *xmlp) +{ + XML_ParserFree(xmlp->parser); + xmlp->parser = 0; +} + +static inline int +parse_block(struct solv_xmlparser *xmlp, char *buf, int l) +{ + if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR) + { + set_error(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), XML_GetCurrentLineNumber(xmlp->parser), XML_GetCurrentColumnNumber(xmlp->parser)); + return 0; + } + return 1; +} + +unsigned int +solv_xmlparser_lineno(struct solv_xmlparser *xmlp) +{ + return (unsigned int)XML_GetCurrentLineNumber(xmlp->parser); +} + +#endif + +int +solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp) +{ + char buf[8192]; + int l, ret = SOLV_XMLPARSER_OK; + + xmlp->state = 0; + xmlp->unknowncnt = 0; + xmlp->docontent = 0; + xmlp->lcontent = 0; + queue_empty(&xmlp->elementq); + + if (!create_parser(xmlp)) + { + set_error(xmlp, "could not create parser", 0, 0); + return SOLV_XMLPARSER_ERROR; + } + for (;;) + { + l = fread(buf, 1, sizeof(buf), fp); + if (!parse_block(xmlp, buf, l)) + { + ret = SOLV_XMLPARSER_ERROR; + break; + } + if (!l) + break; + } + free_parser(xmlp); + return ret; +} + +char * +solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l) +{ + xmlp->lcontent = 0; + if (l > xmlp->acontent) + { + xmlp->acontent = l + 256; + xmlp->content = solv_realloc(xmlp->content, xmlp->acontent); + } + return xmlp->content; +} + diff --git a/libsolv-0.7.2/ext/solv_xmlparser.h b/libsolv-0.7.2/ext/solv_xmlparser.h new file mode 100644 index 0000000..ced0571 --- /dev/null +++ b/libsolv-0.7.2/ext/solv_xmlparser.h @@ -0,0 +1,56 @@ + +struct solv_xmlparser_element { + int fromstate; + char *element; + int tostate; + int docontent; +}; + +struct solv_xmlparser { + void *userdata; + char *errstr; + unsigned int line; + unsigned int column; + + int state; + int docontent; + + Queue elementq; + int unknowncnt; + + char *content; + int lcontent; /* current content length */ + int acontent; /* allocated content length */ + + struct solv_xmlparser_element *elements; + int nelements; + + void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts); + void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content); + + Id *elementhelper; + void *parser; +}; + +#define SOLV_XMLPARSER_OK 0 +#define SOLV_XMLPARSER_ERROR -1 + +static inline const char * +solv_xmlparser_find_attr(const char *txt, const char **atts) +{ + for (; *atts; atts += 2) + if (!strcmp(*atts, txt)) + return atts[1]; + return 0; +} + +extern void solv_xmlparser_init(struct solv_xmlparser *xmlp, struct solv_xmlparser_element *elements, void *userdata, + void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts), + void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content)); + +extern void solv_xmlparser_free(struct solv_xmlparser *xmlp); +extern int solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp); +unsigned int solv_xmlparser_lineno(struct solv_xmlparser *xmlp); +char *solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l); + + diff --git a/libsolv-0.7.2/ext/solv_zchunk.c b/libsolv-0.7.2/ext/solv_zchunk.c new file mode 100644 index 0000000..0833445 --- /dev/null +++ b/libsolv-0.7.2/ext/solv_zchunk.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2018, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include +#include + +#include "chksum.h" +#include "util.h" +#include "solv_zchunk.h" + +#define MAX_HDR_SIZE 0xffffff00 +#define MAX_CHUNK_CNT 0x0fffffff + +#undef VERIFY_DATA_CHKSUM + +struct solv_zchunk { + FILE *fp; + unsigned char *hdr; + unsigned char *hdr_end; + + unsigned int flags; /* header flags */ + unsigned int comp; /* compression type */ + + unsigned int hdr_chk_type; /* header + data checksum */ + unsigned int hdr_chk_len; + Id hdr_chk_id; + + unsigned int chunk_chk_type; /* chunk checksum */ + unsigned int chunk_chk_len; + Id chunk_chk_id; + + Chksum *data_chk; /* for data checksum verification */ + unsigned char *data_chk_ptr; + + unsigned int streamid; /* stream we are reading */ + unsigned int nchunks; /* chunks left */ + unsigned char *chunks; + + ZSTD_DCtx *dctx; + ZSTD_DDict *ddict; + + int eof; + unsigned char *buf; + unsigned int buf_used; + unsigned int buf_avail; +}; + +/* return 32bit compressed integer. returns NULL on overflow. */ +static unsigned char * +getuint(unsigned char *p, unsigned char *endp, unsigned int *dp) +{ + if (!p || p >= endp) + return 0; + if (p < endp && (*p & 0x80) != 0) + { + *dp = p[0] ^ 0x80; + return p + 1; + } + if (++p < endp && (*p & 0x80) != 0) + { + *dp = p[-1] ^ ((p[0] ^ 0x80) << 7); + return p + 1; + } + if (++p < endp && (*p & 0x80) != 0) + { + *dp = p[-2] ^ (p[-1] << 7) ^ ((p[0] ^ 0x80) << 14); + return p + 1; + } + if (++p < endp && (*p & 0x80) != 0) + { + *dp = p[-3] ^ (p[-2] << 7) ^ (p[1] << 14) ^ ((p[0] ^ 0x80) << 21); + return p + 1; + } + if (++p < endp && (*p & 0xf0) == 0x80) + { + *dp = p[-4] ^ (p[-3] << 7) ^ (p[2] << 14) ^ (p[1] << 21) ^ ((p[0] ^ 0x80) << 28); + return p + 1; + } + return 0; +} + +static unsigned char * +getchksum(unsigned char *p, unsigned char *endp, unsigned int *typep, unsigned int *lenp, Id *idp) +{ + if ((p = getuint(p, endp, typep)) == 0) + return 0; + switch (*typep) + { + case 0: + *lenp = 20; + *idp = REPOKEY_TYPE_SHA1; + return p; + case 1: + *lenp = 32; + *idp = REPOKEY_TYPE_SHA256; + return p; + case 2: + *lenp = 64; + *idp = REPOKEY_TYPE_SHA512; + return p; + case 3: + *lenp = 16; + *idp = REPOKEY_TYPE_SHA512; + return p; + default: + break; + } + return 0; +} + +static int +skip_bytes(FILE *fp, size_t skip, Chksum *chk) +{ + unsigned char buf[4096]; + while (skip) + { + size_t bite = skip > sizeof(buf) ? sizeof(buf) : skip; + if (fread(buf, bite, 1, fp) != 1) + return 0; + if (chk) + solv_chksum_add(chk, buf, bite); + skip -= bite; + } + return 1; +} + +static int +nextchunk(struct solv_zchunk *zck, unsigned int streamid) +{ + unsigned char *p = zck->chunks; + unsigned char *chunk_chk_ptr; + unsigned int sid, chunk_len, uncompressed_len; + unsigned char *cbuf; + + /* free old buffer */ + zck->buf = solv_free(zck->buf); + zck->buf_avail = 0; + zck->buf_used = 0; + + for (;;) + { + if (zck->nchunks == 0) + { + zck->chunks = p; + return 1; /* EOF reached */ + } + if (p >= zck->hdr_end) + return 0; + sid = streamid ? 1 : 0; + /* check if this is the correct stream */ + if ((zck->flags & 1) != 0 && (p = getuint(p, zck->hdr_end, &sid)) == 0) + return 0; + chunk_chk_ptr = p; /* remember for verification */ + p += zck->chunk_chk_len; + if (p >= zck->hdr_end) + return 0; + if ((p = getuint(p, zck->hdr_end, &chunk_len)) == 0) + return 0; + if ((p = getuint(p, zck->hdr_end, &uncompressed_len)) == 0) + return 0; + zck->nchunks--; + if (sid == streamid) + break; + /* skip the chunk, but the dict chunk must come first */ + if (streamid == 0 || skip_bytes(zck->fp, chunk_len, zck->data_chk) == 0) + return 0; + } + zck->chunks = p; + + /* ok, read the compressed chunk */ + if (!chunk_len) + return uncompressed_len ? 0 : 1; + cbuf = solv_malloc(chunk_len); + if (fread(cbuf, chunk_len, 1, zck->fp) != 1) + { + solv_free(cbuf); + return 0; + } + if (zck->data_chk) + solv_chksum_add(zck->data_chk, cbuf, chunk_len); + + /* verify the chunk checksum */ + if (zck->chunk_chk_id) + { + Chksum *chk = solv_chksum_create(zck->chunk_chk_id); + if (!chk) + { + solv_free(cbuf); + return 0; + } + solv_chksum_add(chk, cbuf, chunk_len); + if (memcmp(solv_chksum_get(chk, 0), chunk_chk_ptr, zck->chunk_chk_len) != 0) + { + solv_chksum_free(chk, 0); + solv_free(cbuf); + return 0; + } + solv_chksum_free(chk, 0); + } + + /* uncompress */ + if (zck->comp == 0) + { + /* not compressed */ + if (chunk_len != uncompressed_len) + { + solv_free(cbuf); + return 0; + } + zck->buf = cbuf; + zck->buf_avail = uncompressed_len; + return 1; + } + if (zck->comp == 2) + { + /* zstd compressed */ + size_t r; + zck->buf = solv_malloc(uncompressed_len + 1); /* +1 so we can detect too large frames */ + if (zck->ddict) + r = ZSTD_decompress_usingDDict(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len, zck->ddict); + else + r = ZSTD_decompressDCtx(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len); + solv_free(cbuf); + if (r != uncompressed_len) + return 0; + zck->buf_avail = uncompressed_len; + return 1; + } + solv_free(cbuf); + return 0; +} + +static inline struct solv_zchunk * +open_error(struct solv_zchunk *zck) +{ + solv_zchunk_close(zck); + return 0; +} + +struct solv_zchunk * +solv_zchunk_open(FILE *fp, unsigned int streamid) +{ + struct solv_zchunk *zck; + unsigned char *p; + unsigned int hdr_size; /* preface + index + signatures */ + unsigned int lead_size; + unsigned int preface_size; + unsigned int index_size; + + zck = solv_calloc(1, sizeof(*zck)); + + /* read and parse the lead, read the complete header */ + zck->hdr = solv_calloc(15, 1); + zck->hdr_end = zck->hdr + 15; + if (fread(zck->hdr, 15, 1, fp) != 1 || memcmp(zck->hdr, "\000ZCK1", 5) != 0) + return open_error(zck); + p = zck->hdr + 5; + if ((p = getchksum(p, zck->hdr_end, &zck->hdr_chk_type, &zck->hdr_chk_len, &zck->hdr_chk_id)) == 0) + return open_error(zck); + if ((p = getuint(p, zck->hdr_end, &hdr_size)) == 0 || hdr_size > MAX_HDR_SIZE) + return open_error(zck); + lead_size = p - zck->hdr + zck->hdr_chk_len; + zck->hdr = solv_realloc(zck->hdr, lead_size + hdr_size); + zck->hdr_end = zck->hdr + lead_size + hdr_size; + if (fread(zck->hdr + 15, lead_size + hdr_size - 15, 1, fp) != 1) + return open_error(zck); + + /* verify header checksum to guard against corrupt files */ + if (zck->hdr_chk_id) + { + Chksum *chk = solv_chksum_create(zck->hdr_chk_id); + if (!chk) + return open_error(zck); + solv_chksum_add(chk, zck->hdr, lead_size - zck->hdr_chk_len); + solv_chksum_add(chk, zck->hdr + lead_size, hdr_size); + if (memcmp(solv_chksum_get(chk, 0), zck->hdr + (lead_size - zck->hdr_chk_len), zck->hdr_chk_len) != 0) + { + solv_chksum_free(chk, 0); + return open_error(zck); + } + solv_chksum_free(chk, 0); + } + + /* parse preface: data chksum, flags, compression */ + p = zck->hdr + lead_size; + if (p + zck->hdr_chk_len > zck->hdr_end) + return open_error(zck); + zck->data_chk_ptr = p; + p += zck->hdr_chk_len; +#ifdef VERIFY_DATA_CHKSUM + if (zck->hdr_chk_id && (zck->data_chk = solv_chksum_create(zck->hdr_chk_id)) == 0) + return open_error(zck); +#endif + if ((p = getuint(p, zck->hdr_end, &zck->flags)) == 0) + return open_error(zck); + if ((zck->flags & ~(1)) != 0) + return open_error(zck); + if ((p = getuint(p, zck->hdr_end, &zck->comp)) == 0 || (zck->comp != 0 && zck->comp != 2)) + return open_error(zck); /* only uncompressed + zstd supported */ + preface_size = p - (zck->hdr + lead_size); + + /* parse index: index size, index chksum type, num chunks, chunk data */ + if ((p = getuint(p, zck->hdr_end, &index_size)) == 0) + return open_error(zck); + if (hdr_size < preface_size + index_size) + return open_error(zck); + if ((p = getchksum(p, zck->hdr_end, &zck->chunk_chk_type, &zck->chunk_chk_len, &zck->chunk_chk_id)) == 0) + return open_error(zck); + if ((p = getuint(p, zck->hdr_end, &zck->nchunks)) == 0 || zck->nchunks > MAX_CHUNK_CNT) + return open_error(zck); + + /* setup decompressor */ + if (zck->comp == 2) + { + if ((zck->dctx = ZSTD_createDCtx()) == 0) + return open_error(zck); + } + + zck->fp = fp; + zck->chunks = p; + zck->streamid = streamid; + if (streamid == 0) + { + zck->nchunks = zck->nchunks ? 1 : 0; /* limit to dict chunk */ + return zck; + } + + /* setup dictionary */ + if (!nextchunk(zck, 0)) + { + zck->fp = 0; + return open_error(zck); + } + if (zck->comp == 2 && zck->buf_avail) + { + if ((zck->ddict = ZSTD_createDDict(zck->buf, zck->buf_avail)) == 0) + { + zck->fp = 0; + return open_error(zck); + } + } + zck->buf = solv_free(zck->buf); + zck->buf_used = 0; + zck->buf_avail = 0; + + /* ready to read the rest of the chunks */ + return zck; +} + +ssize_t +solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len) +{ + size_t n = 0; + if (!zck || zck->eof == 2) + return -1; + while (n < len && !zck->eof) + { + unsigned int bite; + while (!zck->buf_avail) + { + if (!zck->nchunks) + { + /* verify data checksum if requested */ + if (zck->streamid != 0 && zck->data_chk && memcmp(solv_chksum_get(zck->data_chk, 0), zck->data_chk_ptr, zck->hdr_chk_len) != 0) { + zck->eof = 2; + return -1; + } + zck->eof = 1; + return n; + } + if (!nextchunk(zck, zck->streamid)) + { + zck->eof = 2; + return -1; + } + } + bite = len - n > zck->buf_avail ? zck->buf_avail : len - n; + memcpy(buf + n, zck->buf + zck->buf_used, bite); + n += bite; + zck->buf_used += bite; + zck->buf_avail -= bite; + } + return n; +} + +int +solv_zchunk_close(struct solv_zchunk *zck) +{ + if (zck->data_chk) + solv_chksum_free(zck->data_chk, 0); + if (zck->ddict) + ZSTD_freeDDict(zck->ddict); + if (zck->dctx) + ZSTD_freeDCtx(zck->dctx); + solv_free(zck->hdr); + solv_free(zck->buf); + if (zck->fp) + fclose(zck->fp); + solv_free(zck); + return 0; +} diff --git a/libsolv-0.7.2/ext/solv_zchunk.h b/libsolv-0.7.2/ext/solv_zchunk.h new file mode 100644 index 0000000..9d73486 --- /dev/null +++ b/libsolv-0.7.2/ext/solv_zchunk.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2018, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +struct solv_zchunk; + +extern struct solv_zchunk *solv_zchunk_open(FILE *fp, unsigned int streamid); +extern ssize_t solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len); +extern int solv_zchunk_close(struct solv_zchunk *zck); + diff --git a/libsolv-0.6.15/ext/testcase.c b/libsolv-0.7.2/ext/testcase.c similarity index 82% rename from libsolv-0.6.15/ext/testcase.c rename to libsolv-0.7.2/ext/testcase.c index b9fddef..b815c56 100644 --- a/libsolv-0.6.15/ext/testcase.c +++ b/libsolv-0.7.2/ext/testcase.c @@ -7,8 +7,6 @@ #include #include -#include -#include #include #include #include @@ -17,6 +15,7 @@ #include "pool.h" #include "poolarch.h" #include "poolvendor.h" +#include "evr.h" #include "repo.h" #include "repo_solv.h" #include "solver.h" @@ -25,6 +24,9 @@ #include "testcase.h" #include "selection.h" #include "solv_xfopen.h" +#if ENABLE_TESTCASE_HELIXREPO +#include "ext/repo_helix.h" +#endif #define DISABLE_JOIN2 #include "tools_util.h" @@ -46,6 +48,8 @@ static struct job2str { { SOLVER_DROP_ORPHANED, "droporphaned" }, { SOLVER_USERINSTALLED, "userinstalled" }, { SOLVER_ALLOWUNINSTALL, "allowuninstall" }, + { SOLVER_FAVOR, "favor" }, + { SOLVER_DISFAVOR, "disfavor" }, { 0, 0 } }; @@ -81,6 +85,9 @@ static struct resultflags2str { { TESTCASE_RESULT_ALTERNATIVES, "alternatives" }, { TESTCASE_RESULT_RULES, "rules" }, { TESTCASE_RESULT_GENID, "genid" }, + { TESTCASE_RESULT_REASON, "reason" }, + { TESTCASE_RESULT_CLEANDEPS, "cleandeps" }, + { TESTCASE_RESULT_JOBS, "jobs" }, { 0, 0 } }; @@ -111,6 +118,11 @@ static struct solverflags2str { { SOLVER_FLAG_FOCUS_INSTALLED, "focusinstalled", 0 }, { SOLVER_FLAG_YUM_OBSOLETES, "yumobsoletes", 0 }, { SOLVER_FLAG_NEED_UPDATEPROVIDE, "needupdateprovide", 0 }, + { SOLVER_FLAG_URPM_REORDER, "urpmreorder", 0 }, + { SOLVER_FLAG_FOCUS_BEST, "focusbest", 0 }, + { SOLVER_FLAG_STRONG_RECOMMENDS, "strongrecommends", 0 }, + { SOLVER_FLAG_INSTALL_ALSO_UPDATES, "installalsoupdates", 0 }, + { SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 }, { 0, 0, 0 } }; @@ -160,6 +172,13 @@ static struct selflags2str { { SELECTION_NOCASE, "nocase" }, { SELECTION_SOURCE_ONLY, "sourceonly" }, { SELECTION_WITH_SOURCE, "withsource" }, + { SELECTION_SKIP_KIND, "skipkind" }, + { SELECTION_MATCH_DEPSTR, "depstr" }, + { SELECTION_WITH_DISABLED, "withdisabled" }, + { SELECTION_WITH_BADARCH, "withbadarch" }, + { SELECTION_ADD, "add" }, + { SELECTION_SUBTRACT, "subtract" }, + { SELECTION_FILTER, "filter" }, { 0, 0 } }; @@ -170,6 +189,9 @@ static const char *features[] = { #ifdef ENABLE_COMPLEX_DEPS "complex_deps", #endif +#if ENABLE_TESTCASE_HELIXREPO + "testcase_helixrepo", +#endif 0 }; @@ -372,6 +394,7 @@ struct oplist { { REL_AND, "&" }, { REL_OR , "|" }, { REL_WITH , "+" }, + { REL_WITHOUT , "-" }, { REL_NAMESPACE , "" }, { REL_ARCH, "." }, { REL_MULTIARCH, "" }, @@ -380,41 +403,43 @@ struct oplist { { REL_COMPAT, "compat >=" }, { REL_KIND, "" }, { REL_ELSE, "" }, + { REL_ERROR, "" }, + { REL_UNLESS, "" }, { REL_LT, "<" }, { 0, 0 } }; -static const char * -testcase_dep2str_complex(Pool *pool, Id id, int addparens) +static char * +testcase_dep2str_complex(Pool *pool, char *s, Id id, int addparens) { Reldep *rd; - char *s; const char *s2; int needparens; struct oplist *op; if (!ISRELDEP(id)) - return testcase_id2str(pool, id, 1); + { + s2 = testcase_id2str(pool, id, 1); + s = pool_tmpappend(pool, s, s2, 0); + pool_freetmpspace(pool, s2); + return s; + } rd = GETRELDEP(pool, id); /* check for special shortcuts */ if (rd->flags == REL_NAMESPACE && !ISRELDEP(rd->name) && !strncmp(pool_id2str(pool, rd->name), "namespace:", 10)) { - const char *ns = pool_id2str(pool, rd->name); - int nslen = strlen(ns); - /* special namespace formatting */ - const char *evrs = testcase_dep2str_complex(pool, rd->evr, 0); - s = pool_tmpappend(pool, evrs, ns, "()"); - memmove(s + nslen + 1, s, strlen(s) - nslen - 2); - memcpy(s, ns, nslen); - s[nslen] = '('; - return s; + s = pool_tmpappend(pool, s, pool_id2str(pool, rd->name), "("); + s = testcase_dep2str_complex(pool, s, rd->evr, 0); + return pool_tmpappend(pool, s, ")", 0); } if (rd->flags == REL_MULTIARCH && !ISRELDEP(rd->name) && rd->evr == ARCH_ANY) { - /* special :any suffix */ - const char *ns = testcase_id2str(pool, rd->name, 1); - return pool_tmpappend(pool, ns, ":any", 0); + /* append special :any suffix */ + s2 = testcase_id2str(pool, rd->name, 1); + s = pool_tmpappend(pool, s, s2, ":any"); + pool_freetmpspace(pool, s2); + return s; } needparens = 0; @@ -425,14 +450,11 @@ testcase_dep2str_complex(Pool *pool, Id id, int addparens) if (rd->flags > 7 && rd->flags != REL_COMPAT && rd2->flags && rd2->flags <= 7) needparens = 0; } - s = (char *)testcase_dep2str_complex(pool, rd->name, needparens); if (addparens) - { - s = pool_tmpappend(pool, s, "(", 0); - memmove(s + 1, s, strlen(s + 1)); - s[0] = '('; - } + s = pool_tmpappend(pool, s, "(", 0); + s = testcase_dep2str_complex(pool, s, rd->name, needparens); + for (op = oplist; op->flags; op++) if (rd->flags == op->flags) break; @@ -463,21 +485,27 @@ testcase_dep2str_complex(Pool *pool, Id id, int addparens) needparens = 0; /* chain */ } if (!ISRELDEP(rd->evr)) - s2 = testcase_id2str(pool, rd->evr, 0); + { + s2 = testcase_id2str(pool, rd->evr, 0); + s = pool_tmpappend(pool, s, s2, 0); + pool_freetmpspace(pool, s2); + } else - s2 = testcase_dep2str_complex(pool, rd->evr, needparens); + s = (char *)testcase_dep2str_complex(pool, s, rd->evr, needparens); if (addparens) - s = pool_tmpappend(pool, s, s2, ")"); - else - s = pool_tmpappend(pool, s, s2, 0); - pool_freetmpspace(pool, s2); + s = pool_tmpappend(pool, s, ")", 0); return s; } const char * testcase_dep2str(Pool *pool, Id id) { - return testcase_dep2str_complex(pool, id, 0); + char *s; + if (!ISRELDEP(id)) + return testcase_id2str(pool, id, 1); + s = pool_alloctmpspace(pool, 1); + *s = 0; + return testcase_dep2str_complex(pool, s, id, 0); } @@ -763,6 +791,7 @@ testcase_str2solvid(Pool *pool, const char *str) evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0); if (!evrid) continue; + /* first check whatprovides */ FOR_PROVIDES(p, pp, nid) { Solvable *s = pool->solvables + p; @@ -774,6 +803,31 @@ testcase_str2solvid(Pool *pool, const char *str) continue; return p; } + /* maybe it's not installable and thus not in whatprovides. do a slow search */ + if (repo) + { + Solvable *s; + FOR_REPO_SOLVABLES(repo, p, s) + { + if (s->name != nid || s->evr != evrid) + continue; + if (arch && s->arch != arch) + continue; + return p; + } + } + else + { + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (s->name != nid || s->evr != evrid) + continue; + if (arch && s->arch != arch) + continue; + return p; + } + } } } return 0; @@ -882,7 +936,7 @@ str2selflags(Pool *pool, char *s) /* modifies the string! */ break; } if (!selflags2str[i].str) - pool_debug(pool, SOLV_ERROR, "str2job: unknown selection flag '%s'\n", s); + pool_error(pool, 0, "str2job: unknown selection flag '%s'", s); s = se; } return selflags; @@ -904,7 +958,7 @@ str2jobflags(Pool *pool, char *s) /* modifies the string */ break; } if (!jobflags2str[i].str) - pool_debug(pool, SOLV_ERROR, "str2job: unknown job flag '%s'\n", s); + pool_error(pool, 0, "str2job: unknown job flag '%s'", s); s = se; } return jobflags; @@ -939,7 +993,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) } if (npieces < 3) { - pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); + pool_error(pool, -1, "str2job: bad line '%s'", str); solv_free(pieces); return -1; } @@ -949,7 +1003,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) break; if (!job2str[i].str) { - pool_debug(pool, SOLV_ERROR, "str2job: unknown job '%s'\n", str); + pool_error(pool, -1, "str2job: unknown job '%s'", str); solv_free(pieces); return -1; } @@ -970,7 +1024,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) { if (npieces != 3) { - pool_debug(pool, SOLV_ERROR, "str2job: bad pkg selector in '%s'\n", str); + pool_error(pool, -1, "str2job: bad pkg selector in '%s'", str); solv_free(pieces); return -1; } @@ -978,7 +1032,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) what = testcase_str2solvid(pool, pieces[2]); if (!what) { - pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[2]); + pool_error(pool, -1, "str2job: unknown package '%s'", pieces[2]); solv_free(pieces); return -1; } @@ -1019,14 +1073,14 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) Queue q; job |= SOLVER_SOLVABLE_ONE_OF; queue_init(&q); - if (npieces > 3 && strcmp(pieces[2], "nothing") != 0) + if (npieces > 2 && strcmp(pieces[2], "nothing") != 0) { for (i = 2; i < npieces; i++) { Id p = testcase_str2solvid(pool, pieces[i]); if (!p) { - pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[i]); + pool_error(pool, -1, "str2job: unknown package '%s'", pieces[i]); queue_free(&q); solv_free(pieces); return -1; @@ -1042,14 +1096,14 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) Repo *repo; if (npieces != 3) { - pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); + pool_error(pool, -1, "str2job: bad line '%s'", str); solv_free(pieces); return -1; } repo = testcase_str2repo(pool, pieces[2]); if (!repo) { - pool_debug(pool, SOLV_ERROR, "str2job: unknown repo '%s'\n", pieces[2]); + pool_error(pool, -1, "str2job: unknown repo '%s'", pieces[2]); solv_free(pieces); return -1; } @@ -1060,7 +1114,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) { if (npieces != 3 && strcmp(pieces[2], "packages") != 0) { - pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str); + pool_error(pool, -1, "str2job: bad line '%s'", str); solv_free(pieces); return -1; } @@ -1069,7 +1123,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) } else { - pool_debug(pool, SOLV_ERROR, "str2job: unknown selection in '%s'\n", str); + pool_error(pool, -1, "str2job: unknown selection in '%s'", str); solv_free(pieces); return -1; } @@ -1078,22 +1132,24 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp) return job; } -int -addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue) +#define SELECTIONJOB_MATCHDEPS 1 +#define SELECTIONJOB_MATCHDEPID 2 +#define SELECTIONJOB_MATCHSOLVABLE 3 + +static int +addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int type, int keyname) { Id job; - int i, r; + int i, r = 0; int selflags; Queue sel; + char *sp; for (i = 0; job2str[i].str; i++) if (!strcmp(pieces[0], job2str[i].str)) break; if (!job2str[i].str) - { - pool_debug(pool, SOLV_ERROR, "selstr2job: unknown job '%s'\n", pieces[0]); - return -1; - } + return pool_error(pool, -1, "selstr2job: unknown job '%s'", pieces[0]); job = job2str[i].job; if (npieces > 3) { @@ -1107,13 +1163,27 @@ addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue) } } if (npieces < 4) - { - pool_debug(pool, SOLV_ERROR, "selstr2job: no selection flags\n"); - return -1; - } - selflags = str2selflags(pool, pieces[3]); + return pool_error(pool, -1, "selstr2job: no selection flags"); + selflags = str2selflags(pool, pieces[npieces - 1]); + /* re-join pieces */ + for (sp = pieces[2]; sp < pieces[npieces - 2]; sp++) + if (*sp == 0) + *sp = ' '; queue_init(&sel); - r = selection_make(pool, &sel, pieces[2], selflags); + if (selflags & (SELECTION_ADD | SELECTION_SUBTRACT | SELECTION_FILTER)) + { + for (i = 0; i < jobqueue->count; i += 2) + queue_push2(&sel, jobqueue->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK), jobqueue->elements[i + 1]); + queue_empty(jobqueue); + } + if (!type) + r = selection_make(pool, &sel, pieces[2], selflags); + else if (type == SELECTIONJOB_MATCHDEPS) + r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0); + else if (type == SELECTIONJOB_MATCHDEPID) + r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, keyname, 0); + else if (type == SELECTIONJOB_MATCHSOLVABLE) + r = selection_make_matchsolvable(pool, &sel, testcase_str2solvid(pool, pieces[2]), selflags, keyname, 0); for (i = 0; i < sel.count; i += 2) queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]); queue_free(&sel); @@ -1190,8 +1260,10 @@ testcase_write_testtags(Repo *repo, FILE *fp) const char *release; const char *tmp; unsigned int ti; + Queue q; fprintf(fp, "=Ver: 3.0\n"); + queue_init(&q); FOR_REPO_SOLVABLES(repo, p, s) { name = pool_id2str(pool, s->name); @@ -1212,6 +1284,14 @@ testcase_write_testtags(Repo *repo, FILE *fp) writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements); writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests); writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances); + if (solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &q)) + { + int i; + fprintf(fp, "+Ipr:\n"); + for (i = 0; i < q.count; i++) + fprintf(fp, "%s\n", testcase_dep2str(pool, q.elements[i])); + fprintf(fp, "-Ipr:\n"); + } if (s->vendor) fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor)); ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0); @@ -1219,6 +1299,7 @@ testcase_write_testtags(Repo *repo, FILE *fp) fprintf(fp, "=Tim: %u\n", ti); writefilelist(repo, fp, "Fls:", s); } + queue_free(&q); return 0; } @@ -1249,8 +1330,7 @@ finish_v2_solvable(Pool *pool, Repodata *data, Solvable *s, char *filelist, int repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p); } } - s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, 0); - s->conflicts = repo_fix_conflicts(s->repo, s->conflicts); + repo_rewrite_suse_deps(s, 0); } /* stripped down version of susetags parser used for testcases */ @@ -1318,12 +1398,13 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':') continue; tag = line[1] << 16 | line[2] << 8 | line[3]; + /* tags that do not need a solvable */ switch(tag) - { + { case 'V' << 16 | 'e' << 8 | 'r': tagsversion = atoi(line + 6); addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0; - break; + continue; case 'P' << 16 | 'k' << 8 | 'g': if (s) { @@ -1342,7 +1423,15 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) sp[2][-1] = '-'; s->evr = makeevr(pool, sp[1]); s->arch = pool_str2id(pool, sp[3], 1); + continue; + default: break; + } + if (!s) + continue; + /* tags that need a solvable */ + switch(tag) + { case 'S' << 16 | 'u' << 8 | 'm': repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6); break; @@ -1417,6 +1506,12 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags) case 'E' << 16 | 'n' << 8 | 'h': s->enhances = adddep(repo, s->enhances, line + 6, 0); break; + case 'I' << 16 | 'p' << 8 | 'r': + { + Id id = line[6] == '/' ? pool_str2id(pool, line + 6, 1) : testcase_str2dep(pool, line + 6); + repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id); + break; + } default: break; } @@ -1475,10 +1570,7 @@ testcase_setpoolflags(Pool *pool, const char *str) if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0) break; if (!poolflags2str[i].str) - { - pool_debug(pool, SOLV_ERROR, "setpoolflags: unknown flag '%.*s'\n", (int)(p - s), s); - return 0; - } + return pool_error(pool, 0, "setpoolflags: unknown flag '%.*s'", (int)(p - s), s); pool_set_flag(pool, poolflags2str[i].flag, v); } return 1; @@ -1532,11 +1624,9 @@ testcase_setsolverflags(Solver *solv, const char *str) if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0) break; if (!solverflags2str[i].str) - { - pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s); - return 0; - } - solver_set_flag(solv, solverflags2str[i].flag, v); + return pool_error(solv->pool, 0, "setsolverflags: unknown flag '%.*s'", (int)(p - s), s); + if (solver_set_flag(solv, solverflags2str[i].flag, v) == -1) + return pool_error(solv->pool, 0, "setsolverflags: unsupported flag '%s'", solverflags2str[i].str); } return 1; } @@ -1683,6 +1773,62 @@ static struct class2str { { 0, 0 } }; +static struct reason2str { + Id reason; + const char *str; +} reason2str[] = { + { SOLVER_REASON_UNRELATED, "unrelated" }, + { SOLVER_REASON_UNIT_RULE, "unit" }, + { SOLVER_REASON_KEEP_INSTALLED, "keep" }, + { SOLVER_REASON_RESOLVE_JOB, "job" }, + { SOLVER_REASON_UPDATE_INSTALLED, "update" }, + { SOLVER_REASON_CLEANDEPS_ERASE, "cleandeps" }, + { SOLVER_REASON_RESOLVE, "resolve" }, + { SOLVER_REASON_WEAKDEP, "weakdep" }, + { SOLVER_REASON_RESOLVE_ORPHAN, "orphan" }, + + { SOLVER_REASON_RECOMMENDED, "recommended" }, + { SOLVER_REASON_SUPPLEMENTED, "supplemented" }, + { 0, 0 } +}; + +static const char * +testcase_reason2str(Id reason) +{ + int i; + for (i = 0; reason2str[i].str; i++) + if (reason == reason2str[i].reason) + return reason2str[i].str; + return "?"; +} + +static struct rclass2str { + Id rclass; + const char *str; +} rclass2str[] = { + { SOLVER_RULE_PKG, "pkg" }, + { SOLVER_RULE_UPDATE, "update" }, + { SOLVER_RULE_FEATURE, "feature" }, + { SOLVER_RULE_JOB, "job" }, + { SOLVER_RULE_DISTUPGRADE, "distupgrade" }, + { SOLVER_RULE_INFARCH, "infarch" }, + { SOLVER_RULE_CHOICE, "choice" }, + { SOLVER_RULE_LEARNT, "learnt" }, + { SOLVER_RULE_BEST, "best" }, + { SOLVER_RULE_YUMOBS, "yumobs" }, + { 0, 0 } +}; + +static const char * +testcase_rclass2str(Id rclass) +{ + int i; + for (i = 0; rclass2str[i].str; i++) + if (rclass == rclass2str[i].rclass) + return rclass2str[i].str; + return "unknown"; +} + static int dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt) { @@ -1927,44 +2073,8 @@ testcase_solverresult(Solver *solv, int resultflags) queue_init(&q); for (rid = 1; (rclass = solver_ruleclass(solv, rid)) != SOLVER_RULE_UNKNOWN; rid++) { - char *prefix; - switch (rclass) - { - case SOLVER_RULE_PKG: - prefix = "pkg "; - break; - case SOLVER_RULE_UPDATE: - prefix = "update "; - break; - case SOLVER_RULE_FEATURE: - prefix = "feature "; - break; - case SOLVER_RULE_JOB: - prefix = "job "; - break; - case SOLVER_RULE_DISTUPGRADE: - prefix = "distupgrade "; - break; - case SOLVER_RULE_INFARCH: - prefix = "infarch "; - break; - case SOLVER_RULE_CHOICE: - prefix = "choice "; - break; - case SOLVER_RULE_LEARNT: - prefix = "learnt "; - break; - case SOLVER_RULE_BEST: - prefix = "best "; - break; - case SOLVER_RULE_YUMOBS: - prefix = "yumobs "; - break; - default: - prefix = "unknown "; - break; - } - prefix = solv_dupjoin("rule ", prefix, testcase_ruleid(solv, rid)); + char *prefix = solv_dupjoin("rule ", testcase_rclass2str(rclass), " "); + prefix = solv_dupappend(prefix, testcase_ruleid(solv, rid), 0); solver_ruleliterals(solv, rid, &q); if (rclass == SOLVER_RULE_FEATURE && q.count == 1 && q.elements[0] == -SYSTEMSOLVABLE) continue; @@ -2000,6 +2110,66 @@ testcase_solverresult(Solver *solv, int resultflags) dump_genid(pool, &sq, id, 1); } } + if ((resultflags & TESTCASE_RESULT_REASON) != 0) + { + Queue whyq; + queue_init(&whyq); + FOR_POOL_SOLVABLES(p) + { + Id info, p2, id; + int reason = solver_describe_decision(solv, p, &info); + if (reason == SOLVER_REASON_UNRELATED) + continue; + if (reason == SOLVER_REASON_WEAKDEP) + { + solver_describe_weakdep_decision(solv, p, &whyq); + if (whyq.count) + { + for (i = 0; i < whyq.count; i += 3) + { + reason = whyq.elements[i]; + p2 = whyq.elements[i + 1]; + id = whyq.elements[i + 2]; + s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0); + s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason)); + s = pool_tmpappend(pool, s, " ", testcase_dep2str(pool, id)); + if (p2) + s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, p2)); + strqueue_push(&sq, s); + } + continue; + } + } + s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0); + s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason)); + if (info) + s = pool_tmpappend(pool, s, " ", testcase_ruleid(solv, info)); + strqueue_push(&sq, s); + } + queue_free(&whyq); + } + if ((resultflags & TESTCASE_RESULT_CLEANDEPS) != 0) + { + Queue q; + + queue_init(&q); + solver_get_cleandeps(solv, &q); + for (i = 0; i < q.count; i++) + { + s = pool_tmpjoin(pool, "cleandeps ", testcase_solvid2str(pool, q.elements[i]), 0); + strqueue_push(&sq, s); + } + queue_free(&q); + } + if ((resultflags & TESTCASE_RESULT_JOBS) != 0) + { + for (i = 0; i < solv->job.count; i += 2) + { + s = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]); + s = pool_tmpjoin(pool, "job ", s, 0); + strqueue_push(&sq, s); + } + } strqueue_sort(&sq); result = strqueue_join(&sq); strqueue_free(&sq); @@ -2007,8 +2177,8 @@ testcase_solverresult(Solver *solv, int resultflags) } -int -testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname) +static int +testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname) { Pool *pool = solv->pool; Repo *repo; @@ -2026,10 +2196,7 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc resultname = "solver.result"; if (mkdir(dir, 0777) && errno != EEXIST) - { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not create directory '%s'\n", dir); - return 0; - } + return pool_error(solv->pool, 0, "testcase_write: could not create directory '%s'", dir); strqueue_init(&sq); FOR_REPOS(repoid, repo) { @@ -2040,6 +2207,9 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc else sprintf(priobuf, "%d", repo->priority); out = pool_tmpjoin(pool, name, ".repo", ".gz"); + for (i = 0; out[i]; i++) + if (out[i] == '/') + out[i] = '_'; cmd = pool_tmpjoin(pool, "repo ", name, " "); cmd = pool_tmpappend(pool, cmd, priobuf, " "); cmd = pool_tmpappend(pool, cmd, "testtags ", out); @@ -2047,14 +2217,14 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc out = pool_tmpjoin(pool, dir, "/", out); if (!(fp = solv_xfopen(out, "w"))) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); + pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out); strqueue_free(&sq); return 0; } testcase_write_testtags(repo, fp); if (fclose(fp)) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); + pool_error(solv->pool, 0, "testcase_write: write error"); strqueue_free(&sq); return 0; } @@ -2150,7 +2320,7 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc strqueue_push(&sq, cmd); } - if (resultflags) + if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) != 0) { char *result; cmd = 0; @@ -2179,14 +2349,14 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc out = pool_tmpjoin(pool, dir, "/", resultname); if (!(fp = fopen(out, "w"))) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); + pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out); solv_free(result); strqueue_free(&sq); return 0; } if (result && *result && fwrite(result, strlen(result), 1, fp) != 1) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); + pool_error(solv->pool, 0, "testcase_write: write error"); solv_free(result); strqueue_free(&sq); fclose(fp); @@ -2194,7 +2364,7 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc } if (fclose(fp)) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); + pool_error(solv->pool, 0, "testcase_write: write error"); strqueue_free(&sq); return 0; } @@ -2206,20 +2376,20 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc out = pool_tmpjoin(pool, dir, "/", testcasename); if (!(fp = fopen(out, "w"))) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out); + pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out); strqueue_free(&sq); return 0; } if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); + pool_error(solv->pool, 0, "testcase_write: write error"); strqueue_free(&sq); fclose(fp); return 0; } if (fclose(fp)) { - pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n"); + pool_error(solv->pool, 0, "testcase_write: write error"); strqueue_free(&sq); return 0; } @@ -2228,6 +2398,52 @@ testcase_write(Solver *solv, const char *dir, int resultflags, const char *testc return 1; } +int +testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname) +{ + Pool *pool = solv->pool; + int i, r, repoid; + int mangle = 1; + const char **orignames; + + /* mangle repo names so that there are no conflicts */ + orignames = solv_calloc(pool->nrepos, sizeof(char *)); + for (repoid = 1; repoid < pool->nrepos; repoid++) + { + Repo *repo = pool_id2repo(pool, repoid); + char *buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40); + char *mp; + orignames[repoid] = repo->name; + if (!repo->name || !repo->name[0]) + sprintf(buf, "#%d", repoid); + else + strcpy(buf, repo->name); + for (i = 0; buf[i]; i++) + if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '/') + buf[i] = '_'; + mp = buf + strlen(buf); + for (;;) + { + for (i = 1; i < repoid; i++) + if (!strcmp(buf, pool_id2repo(pool, i)->name)) + break; + if (i == repoid) + break; + sprintf(mp, "_%d", mangle++); + } + repo->name = buf; + } + r = testcase_write_mangled(solv, dir, resultflags, testcasename, resultname); + for (repoid = 1; repoid < pool->nrepos; repoid++) + { + Repo *repo = pool_id2repo(pool, repoid); + solv_free((void *)repo->name); + repo->name = orignames[repoid]; + } + solv_free(orignames); + return r; +} + static char * read_inline_file(FILE *fp, char **bufp, char **bufpp, int *buflp) { @@ -2327,7 +2543,7 @@ str2resultflags(Pool *pool, char *s) /* modifies the string! */ break; } if (!resultflags2str[i].str) - pool_debug(pool, SOLV_ERROR, "result: unknown flag '%s'\n", s); + pool_error(pool, 0, "result: unknown flag '%s'", s); s = se; } return resultflags; @@ -2349,10 +2565,15 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res int missing_features = 0; Id *genid = 0; int ngenid = 0; + Queue autoinstq; + if (resultp) + *resultp = 0; + if (resultflagsp) + *resultflagsp = 0; if (!fp && !(fp = fopen(testcase, "r"))) { - pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", testcase); + pool_error(pool, 0, "testcase_read: could not open '%s'", testcase); return 0; } testcasedir = solv_strdup(testcase); @@ -2364,6 +2585,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res buf = solv_malloc(bufl); bufp = buf; solv = 0; + queue_init(&autoinstq); for (;;) { if (bufp - buf + 16 > bufl) @@ -2441,7 +2663,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res } if (!rfp) { - pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata); + pool_error(pool, 0, "testcase_read: could not open '%s'", rdata); } else if (!strcmp(repotype, "testtags")) { @@ -2453,10 +2675,9 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res repo_add_solv(repo, rfp, 0); fclose(rfp); } -#if 0 +#if ENABLE_TESTCASE_HELIXREPO else if (!strcmp(repotype, "helix")) { - extern int repo_add_helix(Repo *repo, FILE *fp, int flags); repo_add_helix(repo, rfp, 0); fclose(rfp); } @@ -2464,7 +2685,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res else { fclose(rfp); - pool_debug(pool, SOLV_ERROR, "testcase_read: unknown repo type for repo '%s'\n", repo->name); + pool_error(pool, 0, "testcase_read: unknown repo type for repo '%s'", repo->name); } } } @@ -2500,7 +2721,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res } if (!(dp && *dp)) { - pool_debug(pool, SOLV_ERROR, "testcase_read: system: could not change disttype to '%s'\n", pieces[2]); + pool_error(pool, 0, "testcase_read: system: could not change disttype to '%s'", pieces[2]); missing_features = 1; } } @@ -2514,7 +2735,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res { Repo *repo = testcase_str2repo(pool, pieces[3]); if (!repo) - pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown repo '%s'\n", pieces[3]); + pool_error(pool, 0, "testcase_read: system: unknown repo '%s'", pieces[3]); else pool_set_installed(pool, repo); } @@ -2531,7 +2752,25 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res } if (npieces >= 3 && !strcmp(pieces[2], "selection")) { - addselectionjob(pool, pieces + 1, npieces - 1, job); + addselectionjob(pool, pieces + 1, npieces - 1, job, 0, 0); + continue; + } + if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdeps")) + { + pieces[2] = pieces[1]; + addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPS, pool_str2id(pool, pieces[3], 1)); + continue; + } + if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdepid")) + { + pieces[2] = pieces[1]; + addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPID, pool_str2id(pool, pieces[3], 1)); + continue; + } + if (npieces >= 4 && !strcmp(pieces[2], "selection_matchsolvable")) + { + pieces[2] = pieces[1]; + addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHSOLVABLE, pool_str2id(pool, pieces[3], 1)); continue; } /* rejoin */ @@ -2552,7 +2791,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res s = strchr(pieces[1], '('); if (!s && pieces[1][i - 1] != ')') { - pool_debug(pool, SOLV_ERROR, "testcase_read: bad namespace '%s'\n", pieces[1]); + pool_error(pool, 0, "testcase_read: bad namespace '%s'", pieces[1]); } else { @@ -2615,7 +2854,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res { FILE *rfp = fopen(rdata, "r"); if (!rfp) - pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata); + pool_error(pool, 0, "testcase_read: could not open '%s'", rdata); else { result = read_file(rfp); @@ -2630,8 +2869,10 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res if (resultflagsp) *resultflagsp = resultflags; } - else if (!strcmp(pieces[0], "nextjob") && npieces == 1) + else if (!strcmp(pieces[0], "nextjob")) { + if (npieces == 2 && resultflagsp && !strcmp(pieces[1], "reusesolver")) + *resultflagsp |= TESTCASE_RESULT_REUSE_SOLVER; break; } else if (!strcmp(pieces[0], "disable") && npieces == 3) @@ -2639,7 +2880,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res Id p; if (strcmp(pieces[1], "pkg")) { - pool_debug(pool, SOLV_ERROR, "testcase_read: bad disable type '%s'\n", pieces[1]); + pool_error(pool, 0, "testcase_read: bad disable type '%s'", pieces[1]); continue; } if (!prepared) @@ -2655,7 +2896,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res if (p) MAPCLR(pool->considered, p); else - pool_debug(pool, SOLV_ERROR, "disable: unknown package '%s'\n", pieces[2]); + pool_error(pool, 0, "disable: unknown package '%s'", pieces[2]); } else if (!strcmp(pieces[0], "feature")) { @@ -2667,7 +2908,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res break; if (!features[j]) { - pool_debug(pool, SOLV_ERROR, "testcase_read: missing feature '%s'\n", pieces[i]); + pool_error(pool, 0, "testcase_read: missing feature '%s'", pieces[i]); missing_features++; } } @@ -2694,12 +2935,12 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res break; if (!op->flags) { - pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown op '%s'\n", pieces[2]); + pool_error(pool, 0, "testcase_read: genid: unknown op '%s'", pieces[2]); break; } if (ngenid < 2) { - pool_debug(pool, SOLV_ERROR, "testcase_read: genid: out of stack\n"); + pool_error(pool, 0, "testcase_read: genid: out of stack"); break; } ngenid -= 2; @@ -2713,18 +2954,38 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res id = testcase_str2dep(pool, pieces[2]); else { - pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown command '%s'\n", pieces[1]); + pool_error(pool, 0, "testcase_read: genid: unknown command '%s'", pieces[1]); break; } genid[ngenid++] = id; } + else if (!strcmp(pieces[0], "autoinst") && npieces > 2) + { + if (strcmp(pieces[1], "name")) + { + pool_error(pool, 0, "testcase_read: autoinst: illegal mode"); + break; + } + queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1)); + } + else if (!strcmp(pieces[0], "evrcmp") && npieces == 3) + { + Id evr1 = pool_str2id(pool, pieces[1], 1); + Id evr2 = pool_str2id(pool, pieces[2], 1); + int r = pool_evrcmp(pool, evr1, evr2, EVRCMP_COMPARE); + r = r < 0 ? REL_LT : r > 0 ? REL_GT : REL_EQ; + queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, evr1, evr2, r, 1)); + } else { - pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]); + pool_error(pool, 0, "testcase_read: cannot parse command '%s'", pieces[0]); } } while (job && ngenid > 0) queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, genid[--ngenid]); + if (autoinstq.count) + pool_add_userinstalled_jobs(pool, &autoinstq, job, GET_USERINSTALLED_NAMES | GET_USERINSTALLED_INVERTED); + queue_free(&autoinstq); genid = solv_free(genid); buf = solv_free(buf); pieces = solv_free(pieces); diff --git a/libsolv-0.6.15/ext/testcase.h b/libsolv-0.7.2/ext/testcase.h similarity index 88% rename from libsolv-0.6.15/ext/testcase.h rename to libsolv-0.7.2/ext/testcase.h index 4903e6c..387a506 100644 --- a/libsolv-0.6.15/ext/testcase.h +++ b/libsolv-0.7.2/ext/testcase.h @@ -17,6 +17,12 @@ #define TESTCASE_RESULT_ALTERNATIVES (1 << 5) #define TESTCASE_RESULT_RULES (1 << 6) #define TESTCASE_RESULT_GENID (1 << 7) +#define TESTCASE_RESULT_REASON (1 << 8) +#define TESTCASE_RESULT_CLEANDEPS (1 << 9) +#define TESTCASE_RESULT_JOBS (1 << 10) + +/* reuse solver hack, testsolv use only */ +#define TESTCASE_RESULT_REUSE_SOLVER (1 << 31) extern Id testcase_str2dep(Pool *pool, const char *s); extern const char *testcase_dep2str(Pool *pool, Id id); diff --git a/libsolv-0.6.15/ext/tools_util.h b/libsolv-0.7.2/ext/tools_util.h similarity index 100% rename from libsolv-0.6.15/ext/tools_util.h rename to libsolv-0.7.2/ext/tools_util.h diff --git a/libsolv-0.6.15/libsolv.pc.in b/libsolv-0.7.2/libsolv.pc.in similarity index 53% rename from libsolv-0.6.15/libsolv.pc.in rename to libsolv-0.7.2/libsolv.pc.in index c82dfc4..40a8623 100644 --- a/libsolv-0.6.15/libsolv.pc.in +++ b/libsolv-0.7.2/libsolv.pc.in @@ -2,7 +2,7 @@ libdir=@LIB_INSTALL_DIR@ includedir=@INCLUDE_INSTALL_DIR@ Name: libsolv -Description: Library for solving packages and reading repositories +Description: Library for solving packages Version: @VERSION@ -Libs: -L${libdir} -lsolvext -lsolv +Libs: -L${libdir} -lsolv Cflags: -I${includedir} diff --git a/libsolv-0.7.2/libsolvext.pc.in b/libsolv-0.7.2/libsolvext.pc.in new file mode 100644 index 0000000..d48b6fa --- /dev/null +++ b/libsolv-0.7.2/libsolvext.pc.in @@ -0,0 +1,9 @@ +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@ + +Name: libsolvext +Description: Library for reading repositories +Version: @VERSION@ +Requires: libsolv +Libs: -L${libdir} -lsolvext +Cflags: -I${includedir} diff --git a/libsolv-0.6.15/package/libsolv.changes b/libsolv-0.7.2/package/libsolv.changes similarity index 82% rename from libsolv-0.6.15/package/libsolv.changes rename to libsolv-0.7.2/package/libsolv.changes index 8714d4a..53bfc30 100644 --- a/libsolv-0.6.15/package/libsolv.changes +++ b/libsolv-0.7.2/package/libsolv.changes @@ -1,4 +1,264 @@ ------------------------------------------------------------------- +Fri Dec 7 15:10:46 CET 2018 - mls@suse.de + +- do not autouninstall packages because of forcebest updates +- support rpm's new '^' version separator +- support set/get_considered_list in bindings +- new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag + [fate#325513] +- bump version to 0.7.2 + +------------------------------------------------------------------- +Wed Oct 31 13:50:22 CET 2018 - mls@suse.de + +- fix nasty off-by-one error in repo_write +- also copy pattern categories from the rpm that defines the + pattern [fate#323785] +- bump version to 0.7.1 + +------------------------------------------------------------------- +Wed Oct 24 10:48:56 CEST 2018 - mls@suse.de + +- new repowriter interface +- new selection_make_matchsolvable function +- dropped support of REPOKEY_TYPE_U32 +- bindings: Selection.flags is now an attribute +- bump version to 0.7.0 + +------------------------------------------------------------------- +Thu Aug 9 17:09:41 CEST 2018 - mls@suse.de + +- refactor arch handling +- add support for zstd and zchunk compression +- convert repo2solv.sh script into a binary tool +- bump version to 0.6.35 + +------------------------------------------------------------------ +Wed Jul 18 14:11:51 UTC 2018 - ngompa13@gmail.com + +- Fix compatibility with Mageia and RH/Fedora + +------------------------------------------------------------------ +Wed Jul 18 11:02:29 UTC 2018 - tchvatal@suse.com + +- Sort a bit with spec-cleaner +- Use python/ruby/etc condition names to match what other packages + do in order to make sure we are enabling/disabling stuff within + prjcfg +- Silence the source unpacking +- Make sure to execute tests + +------------------------------------------------------------------- +Fri Mar 23 12:02:08 CET 2018 - mls@suse.de + +- make sure product files come from /etc/products.d in fallback + search [bnc#1086602] +- bump version to 0.6.34 + +------------------------------------------------------------------- +Thu Mar 1 10:52:23 CET 2018 - mls@suse.de + +- also use suggests for ordering packages [bnc#1077635] + +------------------------------------------------------------------- +Wed Feb 28 16:29:55 CET 2018 - mls@suse.de + +- fix bad assignment in solution refinement that led + to a memory leak [bnc#1075978] +- use license tag instead of doc in the spec file [bnc#1082318] +- bump version to 0.6.33 + +------------------------------------------------------------------- +Tue Feb 13 11:51:11 CET 2018 - mls@suse.de + +- fixed bug that could make fileconflict detection very slow + in some cases [bnc#953130] +- bump version to 0.6.32 + +------------------------------------------------------------------- +Wed Jan 31 11:41:51 CET 2018 - mls@suse.de + +- new ENABLE_RPMDB_LIBRPM/ENABLE_RPMPKG_LIBRPM config options +- new pool_set_whatprovides function to change the whatprovides + data +- much improved selection code +- bump version to 0.6.31 + +------------------------------------------------------------------- +Tue Oct 24 12:09:32 UTC 2017 - jengelh@inai.de + +- Update package descriptions and groups. + Replace old $RPM_* variables by macros. + +------------------------------------------------------------------- +Mon Oct 23 11:40:22 CEST 2017 - mls@suse.de + +- many fixes and improvements for cleandeps +- support debian packages with xz compressed control.tar +- always create dup rules for "distupgrade" jobs +- use recommends also for ordering packages +- Fix splitprovides handling with addalreadyrecommended turned off + [bnc#1059065] +- bump version to 0.6.30 + +------------------------------------------------------------------- +Thu Sep 7 16:18:20 CEST 2017 - mls@suse.de + +- expose solver_get_recommendations in bindings +- fix bug in solver_prune_to_highest_prio_per_name resulting in + bad solver_get_recommendations output +- support 'without' and 'unless' dependencies +- fix yumobs rule generation bug +- Use same heuristic as upstream to determine src rpms +- bump version to 0.6.29 + +------------------------------------------------------------------- +Fri Jun 30 16:37:31 CEST 2017 - mls@suse.de + +- make peace with newer perl versions +- fix memory leak in bindings +- add pool_best_solvables() function +- fix 64bit integer parsing from RPM headers +- bump version to 0.6.28 + +------------------------------------------------------------------- +Sun May 28 13:32:15 UTC 2017 - ngompa13@gmail.com + +- Enable complex/rich dependencies for CentOS/RHEL 7, matching how + libsolv is configured there. + +------------------------------------------------------------------- +Thu May 11 12:41:07 UTC 2017 - ngompa13@gmail.com + +- Disable bzip2 and xz/lzma compression support for SLE <= 12 + +------------------------------------------------------------------- +Mon May 8 13:15:09 UTC 2017 - ngompa13@gmail.com + +- Enable bzip2 and xz/lzma compression support +- Enable complex/rich dependencies on distributions with RPM 4.13+ +- Simplified CentOS/RHEL conditionals +- Added Mageia conditionals +- Fixed a few spec portability issues + +------------------------------------------------------------------- +Tue Apr 25 14:11:05 CEST 2017 - mls@suse.de + +- change queue resize code to use adaptive chunk sizes +- fix potential segfault in testcase_depstr [bnc#1036002] +- fix performance issues with name = md5sum dependencies + [bnc#1035946] +- improve "forcebest with uninstall" handling +- make dirid handling more robust +- build with libxml2 instead of libexpat +- bump version to 0.6.27 + +------------------------------------------------------------------- +Wed Feb 15 11:34:59 CET 2017 - mls@suse.de + +- export solvable_matchesdep function, as we now use it in + the bindings [bnc#1025440] +- bump version to 0.6.26 + +------------------------------------------------------------------- +Tue Feb 7 13:13:01 CET 2017 - mls@suse.de + +- add SOLVABLE_NAME hack for pool_whatmatchesdep and + solvable_matchesdep +- add SOLVER_FLAG_STRONG_RECOMMENDS option +- add SOLVER_FLAG_INSTALL_ALSO_UPDATES option +- do not special case release-less provides in sort_by_common_dep +- solver_problemruleinfo2str: return reason why a package is not + installable +- guard against dirpool_add_dir being called with an illegal + component id +- reject solv files with bad directories +- bump version to 0.6.25 + +------------------------------------------------------------------- +Thu Nov 10 15:09:25 CET 2016 - mls@suse.de + +- make testcase_str2solvid work with ignored packages +- improve checks against corrupt rpm +- add SOLVER_FLAG_FOCUS_BEST solver flag +- rework susetags multi-line handling [bnc#1007273] +- build both for python2 and python3 +- bump version to 0.6.24 + +------------------------------------------------------------------- +Fri Jul 22 11:37:23 CEST 2016 - mls@suse.de + +- also scan /usr/share/metainfo for appdata files [bnc#989830] +- support tri-state product-endoflife [fate#320699] +- take lockstep into account when calculating unneeded packages +- ignore appplication extensions for now in appdata parser + [bnc#984332] +- add enabled features to solvversion.h +- take disfavors into account when auto-minimizing for recommended + packages +- change cleandeps code so that it keeps all providers +- make sure that all repos have different names in a testcase +- bump version to 0.6.23 + +------------------------------------------------------------------- +Tue Jun 7 11:24:47 CEST 2016 - mls@suse.de + +- fix bug in ignoreinst logic [bnc#983141] + +------------------------------------------------------------------- +Wed May 18 15:09:56 CEST 2016 - mls@suse.de + +- add pool->setdisttype to the bindings +- fix error in repo_deb that could lead to missing packages +- add reason testing to testcase code +- add pool_whatcontainsdep, selection_make_matchdepid, and + SELECTION_MATCH_DEPSTR +- add SOLVER_FAVOR and SOLVER_DISFAVOR job types +- allow unknown archs in pool_setarch +- add the SOLVER_FLAG_URPM_REORDER solver flag +- fix segfault in cshash dedup code [bnc#980901] +- fix supplements handling when implicitobsoleteusescolors is set +- bump version to 0.6.21 + +------------------------------------------------------------------- +Fri Apr 8 15:36:21 CEST 2016 - mls@suse.de + +- Better support of complex deps in pool_match_dep and + selection_make_matchdeps +- make SOLVER_REASON_CLEANDEPS_ERASE introspection reason work again +- make dep2str use rpm-like output if disttype is rpm +- implement filtering of Requires(pre,post) for installed packages +- simplify handling of pseudo package updates [bnc#967006] +- improve speed of rpmmd metadata parsing +- bump version to 0.6.20 + +------------------------------------------------------------------- +Mon Feb 15 16:46:31 CET 2016 - mls@suse.de + +- parse media number from baseurl +- support susedata..xml language files +- bump version to 0.6.19 + +------------------------------------------------------------------- +Fri Jan 29 14:17:26 CET 2016 - mls@suse.de + +- fix rule generation for linked packages [bnc#961738] +- add hash method in bindings for some classes +- bump version to 0.6.18 + +------------------------------------------------------------------- +Tue Dec 22 11:49:02 CET 2015 - mls@suse.de + +- fix update handling of multiversion packages [bnc#957606] +- bump version to 0.6.17 + +------------------------------------------------------------------- +Mon Dec 21 12:59:19 CET 2015 - mls@suse.de + +- fix orphan handling for dup with keeporphans set [bnc#957606] +- bump version to 0.6.16 + +------------------------------------------------------------------- Mon Dec 14 15:48:01 CET 2015 - mls@suse.de - change product links to also look at timestamps [bnc#956443] diff --git a/libsolv-0.7.2/package/libsolv.spec.in b/libsolv-0.7.2/package/libsolv.spec.in new file mode 100644 index 0000000..dd35ea9 --- /dev/null +++ b/libsolv-0.7.2/package/libsolv.spec.in @@ -0,0 +1,342 @@ +# +# spec file for package libsolv +# +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +%define libname libsolv@LIBSOLV_SOVERSION@ + +%if 0%{?sle_version} >= 120300 || 0%{?suse_version} >= 1330 || !0%{?suse_version} +%bcond_without bz2 +%bcond_without xz +%else +%bcond_with bz2 +%bcond_with xz +%endif +%if 0%{?is_opensuse} && (0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500) +%bcond_without zstd +%else +%bcond_with zstd +%endif +%if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?mageia} >= 6 || 0%{?suse_version} >= 1330 +%bcond_without richdeps +%else +%bcond_with richdeps +%endif +# we need at least swig 1.3.40 for the bindings ($typemap support) +%if 0%{?suse_version} != 1110 +%bcond_without python3 +%bcond_without python +%bcond_without ruby +%bcond_without perl +%else +%bcond_with python3 +%bcond_with python +%bcond_with ruby +%bcond_with perl +%endif +%bcond_without static +%bcond_with shared +%bcond_with zypp + +Name: libsolv +Version: @VERSION@ +Release: 0 +Summary: Package dependency solver using a satisfiability algorithm +License: BSD-3-Clause +Group: Development/Libraries/C and C++ +Url: https://github.com/openSUSE/libsolv +Source: libsolv-%{version}.tar.bz2 +BuildRequires: cmake +BuildRequires: gcc-c++ +BuildRequires: libxml2-devel +BuildRequires: rpm-devel +BuildRequires: zlib-devel +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia} +BuildRequires: db-devel +%endif + +%if %{with perl} +BuildRequires: perl +%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia} +BuildRequires: perl-devel +%endif +BuildRequires: swig +%endif + +%if %{with ruby} +%global ruby_vendorarch %(ruby -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']") +BuildRequires: ruby +BuildRequires: ruby-devel +BuildRequires: swig +%endif + +%if %{with python} +%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))") +BuildRequires: python-devel +BuildRequires: swig +%endif + +%if %{with python3} +%global python3_sitearch %(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))") +BuildRequires: python3-devel +BuildRequires: swig +%endif + +%if %{with bz2} +%if 0%{?suse_version} +BuildRequires: libbz2-devel +%else +BuildRequires: bzip2-devel +%endif +%endif + +%if %{with xz} +BuildRequires: xz-devel +%endif + +%if %{with zstd} +BuildRequires: libzstd-devel +%endif + + +%description +libsolv is a library for solving packages and reading repositories. +The solver uses a satisfiability algorithm. + +%if %{with shared} +%package -n %{libname} +Summary: Package dependency solver using a satisfiability algorithm +Group: System/Libraries + +%description -n %{libname} +libsolv is a library for solving packages and reading repositories. +It consists of two central blocks: Using a dictionary approach to +store and retrieve package and dependency information, and, using a +so-called satisfiability algorithm for resolving package +dependencies. + +%endif +%package devel +Summary: Development files for libsolv, a package solver +Group: Development/Libraries/C and C++ +%if %{with shared} +Requires: %{libname} = %version +%endif +Requires: rpm-devel +Conflicts: libsatsolver-devel + +%description devel +Development files for libsolv, a library for solving packages and +reading repositories. + +%package tools +Summary: Utilities to work with .solv files +Group: System/Management +Conflicts: satsolver-tools-obsolete +Obsoletes: satsolver-tools < 0.18 +Provides: satsolver-tools = 0.18 + +%description tools +libsolv is a library for solving packages and reading repositories. + +This subpackage contains utilities to create and work with the .solv +files used by libsolv. + +%package demo +Summary: Applications demoing the libsolv library +Group: System/Management +Requires: curl +Conflicts: libsatsolver-demo +%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia} +Requires: gnupg2 +%endif +%if 0%{?suse_version} +Requires: gpg2 +%endif + +%description demo +Applications demoing the libsolv library. + +%package -n ruby-solv +Summary: Ruby bindings for the libsolv library +Group: Development/Languages/Ruby + +%description -n ruby-solv +Ruby bindings for libsolv. + +%package -n python-solv +%if 0%{?py_requires:1} && %{with python} +%py_requires +%endif +Summary: Python bindings for the libsolv library +Group: Development/Languages/Python + +%description -n python-solv +Python bindings for libsolv. + +%package -n python3-solv +Summary: Python3 bindings for the libsolv library +Group: Development/Languages/Python + +%description -n python3-solv +Python3 bindings for libsolv. + +%package -n perl-solv +Summary: Perl bindings for the libsolv library +Group: Development/Languages/Perl +Requires: perl = %{perl_version} + +%description -n perl-solv +Perl bindings for libsolv. + +%prep +%setup -q + +%build +export CFLAGS="%{optflags}" +export CXXFLAGS="$CFLAGS" + +CMAKE_FLAGS= +%if 0%{?fedora} || 0%{?rhel} >= 6 +CMAKE_FLAGS="-DFEDORA=1" +%endif +%if 0%{?mageia} +CMAKE_FLAGS="-DMAGEIA=1" +%endif +%if 0%{?suse_version} +CMAKE_FLAGS="-DSUSE=1" +%endif + +cmake $CMAKE_FLAGS \ + -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DLIB=%{_lib} \ + -DCMAKE_VERBOSE_MAKEFILE=TRUE \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DWITH_LIBXML2=1 \ + -DENABLE_APPDATA=1 \ + -DENABLE_COMPS=1 \ + %{?with_static:-DENABLE_STATIC=1} \ + %{!?with_shared:-DDISABLE_SHARED=1} \ + %{?with_perl:-DENABLE_PERL=1} \ + %{?with_python:-DENABLE_PYTHON=1} \ + %{?with_python3:-DENABLE_PYTHON3=1} \ + %{?with_ruby:-DENABLE_RUBY=1} \ + %{?with_bz2:-DENABLE_BZIP2_COMPRESSION=1} \ + %{?with_xz:-DENABLE_LZMA_COMPRESSION=1} \ + %{?with_zstd:-DENABLE_ZSTD_COMPRESSION=1} \ + %{?with_zstd:-DENABLE_ZCHUNK_COMPRESSION=1} \ + %{?with_richdeps:-DENABLE_COMPLEX_DEPS=1} \ + %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \ + -DUSE_VENDORDIRS=1 \ + -DCMAKE_SKIP_RPATH=1 +make %{?_smp_mflags} + +%install +make DESTDIR=%{buildroot} install +ln -s repo2solv %{buildroot}/%{_bindir}/repo2solv.sh + +%if 0%{?suse_version} +%if %{with python} +%py_compile -O %{buildroot}/%{python_sitearch} +%endif +%if %{with python3} +%py3_compile %{buildroot}/%{python3_sitearch} +%endif +%endif +%if %{with static} +# we want to leave the .a file untouched +export NO_BRP_STRIP_DEBUG=true +%endif + +%check +make ARGS=--output-on-failure test + +%if %{with shared} +%post -n %{libname} -p /sbin/ldconfig + +%postun -n %{libname} -p /sbin/ldconfig + +%files -n %{libname} +%defattr(-,root,root) +%license LICENSE* +%{_libdir}/libsolv.so.* +%{_libdir}/libsolvext.so.* +%endif + +%files tools +%defattr(-,root,root) +%if 0%{?suse_version} +%exclude %{_bindir}/helix2solv +%exclude %{_mandir}/man1/helix2solv* +%endif +%exclude %{_mandir}/man1/solv.1* +%exclude %{_bindir}/solv +%{_bindir}/* +%{_mandir}/man1/* + +%files devel +%defattr(-,root,root) +%if %{with static} +%{_libdir}/libsolv.a +%{_libdir}/libsolvext.a +%endif +%if %{with shared} +%{_libdir}/libsolv.so +%{_libdir}/libsolvext.so +%endif +%{_includedir}/solv +%if 0%{?suse_version} +%{_bindir}/helix2solv +%{_mandir}/man1/helix2solv* +%endif +%{_datadir}/cmake/Modules/* +%{_libdir}/pkgconfig/libsolv*.pc +%{_mandir}/man3/* + +%files demo +%defattr(-,root,root) +%{_bindir}/solv +%{_mandir}/man1/solv.1* + +%if %{with perl} +%files -n perl-solv +%defattr(-,root,root) +%{perl_vendorarch}/* +%endif + +%if %{with ruby} +%files -n ruby-solv +%defattr(-,root,root) +%{ruby_vendorarch}/* +%endif + +%if %{with python} +%files -n python-solv +%defattr(-,root,root) +%{python_sitearch}/* +%endif + +%if %{with python3} +%files -n python3-solv +%defattr(-,root,root) +%{python3_sitearch}/*solv* +%if 0%{?suse_version} +%{python3_sitearch}/*/*solv* +%endif +%endif + +%changelog diff --git a/libsolv-0.6.15/src/CMakeLists.txt b/libsolv-0.7.2/src/CMakeLists.txt similarity index 90% rename from libsolv-0.6.15/src/CMakeLists.txt rename to libsolv-0.7.2/src/CMakeLists.txt index a2c0098..2e32968 100644 --- a/libsolv-0.6.15/src/CMakeLists.txt +++ b/libsolv-0.7.2/src/CMakeLists.txt @@ -18,7 +18,9 @@ SET (libsolv_SRCS solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c - chksum.c md5.c sha1.c sha2.c solvversion.c selection.c) + chksum.c md5.c sha1.c sha2.c solvversion.c selection.c + fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c + userinstalled.c filelistfilter.c) SET (libsolv_HEADERS bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h @@ -43,7 +45,7 @@ SET_TARGET_PROPERTIES(libsolv PROPERTIES SOVERSION ${LIBSOLV_SOVERSION}) SET_TARGET_PROPERTIES(libsolv PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR}) INSTALL (FILES ${libsolv_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv") -INSTALL (TARGETS libsolv LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) +INSTALL (TARGETS libsolv LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION bin) IF (ENABLE_STATIC AND NOT DISABLE_SHARED) ADD_LIBRARY (libsolv_static STATIC ${libsolv_SRCS}) diff --git a/libsolv-0.7.2/src/bitmap.c b/libsolv-0.7.2/src/bitmap.c new file mode 100644 index 0000000..4e8adbd --- /dev/null +++ b/libsolv-0.7.2/src/bitmap.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * bitmap.c + * + */ + +#include +#include + +#include "bitmap.h" +#include "util.h" + +/* constructor */ +void +map_init(Map *m, int n) +{ + m->size = (n + 7) >> 3; + m->map = m->size ? solv_calloc(m->size, 1) : 0; +} + +/* destructor */ +void +map_free(Map *m) +{ + m->map = solv_free(m->map); + m->size = 0; +} + +/* copy constructor target <- source */ +void +map_init_clone(Map *target, const Map *source) +{ + target->size = source->size; + if (source->size) + { + target->map = solv_malloc(source->size); + memcpy(target->map, source->map, source->size); + } + else + target->map = 0; +} + +/* grow a map */ +void +map_grow(Map *m, int n) +{ + n = (n + 7) >> 3; + if (m->size < n) + { + m->map = solv_realloc(m->map, n); + memset(m->map + m->size, 0, n - m->size); + m->size = n; + } +} + +/* bitwise-ands maps t and s, stores the result in t. */ +void +map_and(Map *t, const Map *s) +{ + unsigned char *ti, *si, *end; + ti = t->map; + si = s->map; + end = ti + (t->size < s->size ? t->size : s->size); + while (ti < end) + *ti++ &= *si++; +} + +/* bitwise-ors maps t and s, stores the result in t. */ +void +map_or(Map *t, const Map *s) +{ + unsigned char *ti, *si, *end; + if (t->size < s->size) + map_grow(t, s->size << 3); + ti = t->map; + si = s->map; + end = ti + (t->size < s->size ? t->size : s->size); + while (ti < end) + *ti++ |= *si++; +} + +/* remove all set bits in s from t. */ +void +map_subtract(Map *t, const Map *s) +{ + unsigned char *ti, *si, *end; + ti = t->map; + si = s->map; + end = ti + (t->size < s->size ? t->size : s->size); + while (ti < end) + *ti++ &= ~*si++; +} + +void +map_invertall(Map *m) +{ + unsigned char *ti, *end; + ti = m->map; + end = ti + m->size; + while (ti < end) + *ti++ ^= 0xff; +} + +/* EOF */ diff --git a/libsolv-0.6.15/src/bitmap.h b/libsolv-0.7.2/src/bitmap.h similarity index 74% rename from libsolv-0.6.15/src/bitmap.h rename to libsolv-0.7.2/src/bitmap.h index 5784e6c..6609678 100644 --- a/libsolv-0.6.15/src/bitmap.h +++ b/libsolv-0.7.2/src/bitmap.h @@ -19,7 +19,7 @@ extern "C" { #endif -typedef struct _Map { +typedef struct s_Map { unsigned char *map; int size; } Map; @@ -33,14 +33,17 @@ typedef struct _Map { #define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7))) /* test bit */ #define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7))) +/* clear some bits at a position */ +#define MAPCLR_AT(m, n) ((m)->map[(n) >> 3] = 0) extern void map_init(Map *m, int n); -extern void map_init_clone(Map *t, Map *s); +extern void map_init_clone(Map *target, const Map *source); extern void map_grow(Map *m, int n); extern void map_free(Map *m); -extern void map_and(Map *t, Map *s); -extern void map_or(Map *t, Map *s); -extern void map_subtract(Map *t, Map *s); +extern void map_and(Map *t, const Map *s); +extern void map_or(Map *t, const Map *s); +extern void map_subtract(Map *t, const Map *s); +extern void map_invertall(Map *m); static inline void map_empty(Map *m) { @@ -62,6 +65,10 @@ static inline int map_tst(Map *m, int n) { return MAPTST(m, n); } +static inline void map_clr_at(Map *m, int n) +{ + MAPCLR_AT(m, n); +} #ifdef __cplusplus } diff --git a/libsolv-0.6.15/src/chksum.c b/libsolv-0.7.2/src/chksum.c similarity index 99% rename from libsolv-0.6.15/src/chksum.c rename to libsolv-0.7.2/src/chksum.c index 935aea8..df46145 100644 --- a/libsolv-0.6.15/src/chksum.c +++ b/libsolv-0.7.2/src/chksum.c @@ -19,7 +19,7 @@ #include "sha1.h" #include "sha2.h" -struct _Chksum { +struct s_Chksum { Id type; int done; unsigned char result[64]; diff --git a/libsolv-0.6.15/src/chksum.h b/libsolv-0.7.2/src/chksum.h similarity index 95% rename from libsolv-0.6.15/src/chksum.h rename to libsolv-0.7.2/src/chksum.h index 479923a..65b775b 100644 --- a/libsolv-0.6.15/src/chksum.h +++ b/libsolv-0.7.2/src/chksum.h @@ -14,8 +14,8 @@ extern "C" { #endif -struct _Chksum; -typedef struct _Chksum Chksum; +struct s_Chksum; +typedef struct s_Chksum Chksum; Chksum *solv_chksum_create(Id type); Chksum *solv_chksum_create_clone(Chksum *chk); diff --git a/libsolv-0.7.2/src/cleandeps.c b/libsolv-0.7.2/src/cleandeps.c new file mode 100644 index 0000000..1da28f6 --- /dev/null +++ b/libsolv-0.7.2/src/cleandeps.c @@ -0,0 +1,1393 @@ +/* + * Copyright (c) 2017, SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * cleandeps.c + * + * code to find and erase unneeded packages + */ + +#include +#include +#include +#include + +#include "solver.h" +#include "solverdebug.h" +#include "solver_private.h" +#include "bitmap.h" +#include "pool.h" +#include "util.h" +#include "policy.h" +#include "cplxdeps.h" + +#undef CLEANDEPSDEBUG + +/* + * This functions collects all packages that are looked at + * when a dependency is checked. We need it to "pin" installed + * packages when removing a supplemented package in createcleandepsmap. + * Here's an not uncommon example: + * A contains "Supplements: packageand(B, C)" + * B contains "Requires: A" + * Now if we remove C, the supplements is no longer true, + * thus we also remove A. Without the dep_pkgcheck function, we + * would now also remove B, but this is wrong, as adding back + * C doesn't make the supplements true again. Thus we "pin" B + * when we remove A. + * There's probably a better way to do this, but I haven't come + * up with it yet ;) + */ +static void +dep_pkgcheck_slow(Solver *solv, Id dep, Map *m, Queue *q) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8) + { + if (rd->flags == REL_AND) + { + dep_pkgcheck_slow(solv, rd->name, m, q); + dep_pkgcheck_slow(solv, rd->evr, m, q); + return; + } + if (rd->flags == REL_COND || rd->flags == REL_UNLESS) + { + dep_pkgcheck_slow(solv, rd->name, m, q); + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + dep_pkgcheck_slow(solv, rd2->evr, m, q); + } + return; + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return; + } + } + FOR_PROVIDES(p, pp, dep) + if (!m || MAPTST(m, p)) + queue_push(q, p); +} + +static inline void +dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (!ISSIMPLEDEP(pool, dep)) + { + dep_pkgcheck_slow(solv, dep, m, q); + return; + } + FOR_PROVIDES(p, pp, dep) + if (!m || MAPTST(m, p)) + queue_push(q, p); +} + +static int +check_xsupp(Solver *solv, Queue *depq, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8) + { + if (rd->flags == REL_AND) + { + if (!check_xsupp(solv, depq, rd->name)) + return 0; + return check_xsupp(solv, depq, rd->evr); + } + if (rd->flags == REL_OR) + { + if (check_xsupp(solv, depq, rd->name)) + return 1; + return check_xsupp(solv, depq, rd->evr); + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return 0; + if (depq && rd->flags == REL_NAMESPACE) + { + int i; + for (i = 0; i < depq->count; i++) + if (depq->elements[i] == dep || depq->elements[i] == rd->name) + return 1; + } + } + } + FOR_PROVIDES(p, pp, dep) + if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed) + return 1; + return 0; +} + +struct trj_data { + Queue *edges; + Id *low; + Id idx; + Id nstack; + Id firstidx; +}; + +/* Tarjan's SCC algorithm, slightly modifed */ +static void +trj_visit(struct trj_data *trj, Id node) +{ + Id *low = trj->low; + Queue *edges = trj->edges; + Id nnode, myidx, stackstart; + int i; + + low[node] = myidx = trj->idx++; + low[(stackstart = trj->nstack++)] = node; + for (i = edges->elements[node]; (nnode = edges->elements[i]) != 0; i++) + { + Id l = low[nnode]; + if (!l) + { + if (!edges->elements[edges->elements[nnode]]) + { + trj->idx++; + low[nnode] = -1; + continue; + } + trj_visit(trj, nnode); + l = low[nnode]; + } + if (l < 0) + continue; + if (l < trj->firstidx) + { + int k; + for (k = l; low[low[k]] == l; k++) + low[low[k]] = -1; + } + else if (l < low[node]) + low[node] = l; + } + if (low[node] == myidx) + { + if (myidx != trj->firstidx) + myidx = -1; + for (i = stackstart; i < trj->nstack; i++) + low[low[i]] = myidx; + trj->nstack = stackstart; + } +} + +#ifdef ENABLE_COMPLEX_DEPS +static void +complex_filter_unneeded(Pool *pool, Id ip, Id req, Queue *edges, Map *cleandepsmap, Queue *unneededq) +{ + int i, j; + Queue dq; + Id p; + + queue_init(&dq); + i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); + if (i == 0 || i == 1) + { + queue_free(&dq); + return; + } + for (i = 0; i < dq.count; i++) + { + for (; (p = dq.elements[i]) != 0; i++) + { + if (p < 0) + { + if (pool->solvables[-p].repo != pool->installed) + break; + continue; + } + if (p == ip || pool->solvables[p].repo != pool->installed || !MAPTST(cleandepsmap, p - pool->installed->start)) + continue; + for (j = 0; j < unneededq->count; j++) + if (p == unneededq->elements[j]) + { + if (edges->elements[edges->count - 1] != j + 1) + queue_push(edges, j + 1); + break; + } + } + while (dq.elements[i]) + i++; + } + queue_free(&dq); +} +#endif + + +static void +filter_unneeded(Solver *solv, Queue *unneededq, Map *unneededmap, int justone) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Queue edges; + Id *nrequires; + Map m, installedm; + int i, j, pass, count = unneededq->count; + Id *low; + + if (unneededq->count < 2) + return; + map_init(&m, 0); + if (!unneededmap) + { + unneededmap = &m; + map_grow(unneededmap, installed->end - installed->start); + for (i = 0; i < count; i++) + MAPSET(unneededmap, unneededq->elements[i] - installed->start); + } + map_init(&installedm, pool->nsolvables); + for (i = installed->start; i < installed->end; i++) + if (pool->solvables[i].repo == installed) + MAPSET(&installedm, i); + + nrequires = solv_calloc(count, sizeof(Id)); + queue_init(&edges); + queue_prealloc(&edges, count * 4 + 10); /* pre-size */ + + /* + * Go through the solvables in the nodes queue and create edges for + * all requires/recommends/supplements between the nodes. + * The edges are stored in the edges queue, we add 1 to the node + * index so that nodes in the edges queue are != 0 and we can + * terminate the edge list with 0. + * Thus for node element 5, the edges are stored starting at + * edges.elements[6] and are 0-terminated. + */ + /* leave first element zero to make things easier */ + /* also add trailing zero */ + queue_insertn(&edges, 0, 1 + count + 1, 0); + + /* first requires and recommends */ + for (i = 0; i < count; i++) + { + Solvable *s = pool->solvables + unneededq->elements[i]; + int oldcount = edges.count; + edges.elements[i + 1] = oldcount; + for (pass = 0; pass < 2; pass++) + { + unsigned int off = pass == 0 ? s->requires : s->recommends; + Id p, pp, dep, *dp; + if (off) + for (dp = s->repo->idarraydata + off; (dep = *dp) != 0; dp++) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, dep)) + { + complex_filter_unneeded(pool, s - pool->solvables, dep, &edges, unneededmap, unneededq); + continue; + } +#endif + if (justone) + { + int count = 0; + FOR_PROVIDES(p, pp, dep) + { + Solvable *sp = pool->solvables + p; + if (s == sp || sp->repo != installed) + continue; + count++; + } + if (count != 1) + continue; + } + FOR_PROVIDES(p, pp, dep) + { + Solvable *sp = pool->solvables + p; + if (s == sp || sp->repo != installed || !MAPTST(unneededmap, p - installed->start)) + continue; + for (j = 0; j < count; j++) + if (p == unneededq->elements[j]) + { + if (edges.elements[edges.count - 1] != j + 1) + queue_push(&edges, j + 1); + } + } + } + if (pass == 0) + nrequires[i] = edges.count - oldcount; + } + queue_push(&edges, 0); + } +#if 0 + printf("requires + recommends\n"); + for (i = 0; i < count; i++) + { + int j; + printf(" %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]); + for (j = edges.elements[i + 1]; edges.elements[j]; j++) + printf(" - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1])); + } +#endif + + /* then add supplements */ + for (i = 0; i < count; i++) + { + Solvable *s = pool->solvables + unneededq->elements[i]; + if (s->supplements) + { + Id *dp; + int k; + for (dp = s->repo->idarraydata + s->supplements; *dp; dp++) + if (solver_dep_possible(solv, *dp, &installedm)) + { + Queue iq; + Id iqbuf[16]; + queue_init_buffer(&iq, iqbuf, sizeof(iqbuf)/sizeof(*iqbuf)); + dep_pkgcheck(solv, *dp, 0, &iq); + if (justone && iq.count != 1) + { + queue_free(&iq); + continue; + } + for (k = 0; k < iq.count; k++) + { + Id p = iq.elements[k]; + Solvable *sp = pool->solvables + p; + if (p == unneededq->elements[i] || sp->repo != installed || !MAPTST(unneededmap, p - installed->start)) + continue; + for (j = 0; j < count; j++) + if (p == unneededq->elements[j]) + break; + /* now add edge from j + 1 to i + 1 */ + queue_insert(&edges, edges.elements[j + 1] + nrequires[j], i + 1); + /* addapt following edge pointers */ + for (j = j + 2; j < count + 1; j++) + edges.elements[j]++; + } + queue_free(&iq); + } + } + } +#if 0 + /* print result */ + printf("+ supplements\n"); + for (i = 0; i < count; i++) + { + int j; + printf(" %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]); + for (j = edges.elements[i + 1]; edges.elements[j]; j++) + printf(" - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1])); + } +#endif + map_free(&installedm); + + /* now run SCC algo two times, first with requires+recommends+supplements, + * then again without the requires. We run it the second time to get rid + * of packages that got dragged in via recommends/supplements */ + /* + * low will contain the result of the SCC search. + * it must be of at least size 2 * (count + 1) and + * must be zero initialized. + * The layout is: + * 0 low low ... low stack stack ...stack 0 + * count count + */ + low = solv_calloc(count + 1, 2 * sizeof(Id)); + for (pass = 0; pass < 2; pass++) + { + struct trj_data trj; + if (pass) + { + memset(low, 0, (count + 1) * (2 * sizeof(Id))); + for (i = 0; i < count; i++) + { + edges.elements[i + 1] += nrequires[i]; + if (!unneededq->elements[i]) + low[i + 1] = -1; /* ignore this node */ + } + } + trj.edges = &edges; + trj.low = low; + trj.idx = count + 1; /* stack starts here */ + for (i = 1; i <= count; i++) + { + if (low[i]) + continue; + if (edges.elements[edges.elements[i]]) + { + trj.firstidx = trj.nstack = trj.idx; + trj_visit(&trj, i); + } + else + { + Id myidx = trj.idx++; + low[i] = myidx; + low[myidx] = i; + } + } + /* prune packages */ + for (i = 0; i < count; i++) + if (low[i + 1] <= 0) + unneededq->elements[i] = 0; + } + solv_free(low); + solv_free(nrequires); + queue_free(&edges); + + /* finally remove all pruned entries from unneededq */ + for (i = j = 0; i < count; i++) + if (unneededq->elements[i]) + unneededq->elements[j++] = unneededq->elements[i]; + queue_truncate(unneededq, j); + map_free(&m); +} + + +#ifdef ENABLE_COMPLEX_DEPS +static void +complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq) +{ + int i; + Queue dq; + Id p; + + queue_init(&dq); + i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); + if (i == 0 || i == 1) + { + queue_free(&dq); + return; + } + for (i = 0; i < dq.count; i++) + { + for (; (p = dq.elements[i]) != 0; i++) + { + if (p < 0) + { + if (!MAPTST(installedm, -p)) + break; + continue; + } + if (p != SYSTEMSOLVABLE && MAPTST(im, p)) + { +#ifdef CLEANDEPSDEBUG + printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + queue_push(iq, p); + } + } + while (dq.elements[i]) + i++; + } + queue_free(&dq); +} + +static void +complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled) +{ + int i, blk; + Queue dq; + Id p; + + queue_init(&dq); + i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); + if (i == 0 || i == 1) + { + queue_free(&dq); + return; + } + for (i = 0; i < dq.count; i++) + { + blk = i; + for (; (p = dq.elements[i]) != 0; i++) + { + if (p < 0) + { + if (!MAPTST(installedm, -p)) + break; + } + else if (p == ip) + break; + } + if (!p) + { + for (i = blk; (p = dq.elements[i]) != 0; i++) + { + if (p < 0) + continue; + if (MAPTST(im, p)) + continue; + if (!MAPTST(installedm, p)) + continue; + if (p == ip || MAPTST(userinstalled, p - pool->installed->start)) + continue; +#ifdef CLEANDEPSDEBUG + printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + MAPSET(im, p); + queue_push(iq, p); + } + } + while (dq.elements[i]) + i++; + } + queue_free(&dq); +} + +#endif + +static inline int +queue_contains(Queue *q, Id id) +{ + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == id) + return 1; + return 0; +} + +static void +find_update_seeds(Solver *solv, Queue *updatepkgs_filtered, Map *userinstalled) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Queue *cleandeps_updatepkgs = solv->cleandeps_updatepkgs; + int i, j; + Id p; + + queue_prealloc(updatepkgs_filtered, cleandeps_updatepkgs->count); + for (i = 0; i < cleandeps_updatepkgs->count; i++) + { + p = cleandeps_updatepkgs->elements[i]; + if (pool->solvables[p].repo == installed) + { +#ifdef ENABLE_LINKED_PKGS + const char *name = pool_id2str(pool, pool->solvables[p].name); + if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) + continue; +#endif + queue_push(updatepkgs_filtered, p); + } + } +#ifdef CLEANDEPSDEBUG + printf("SEEDS IN (%d)\n", updatepkgs_filtered->count); + for (i = 0; i < updatepkgs_filtered->count; i++) + printf(" - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i])); +#endif + filter_unneeded(solv, updatepkgs_filtered, 0, 1); +#ifdef CLEANDEPSDEBUG + printf("SEEDS OUT (%d)\n", updatepkgs_filtered->count); + for (i = 0; i < updatepkgs_filtered->count; i++) + printf(" - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i])); +#endif + /* make sure userinstalled packages are in the seeds */ + for (i = j = 0; i < updatepkgs_filtered->count; i++) + { + p = updatepkgs_filtered->elements[i]; + if (!MAPTST(userinstalled, p - installed->start)) + updatepkgs_filtered->elements[j++] = p; + } + queue_truncate(updatepkgs_filtered, j); + for (i = 0; i < cleandeps_updatepkgs->count; i++) + { + p = cleandeps_updatepkgs->elements[i]; + if (pool->solvables[p].repo == installed) + { +#ifdef ENABLE_LINKED_PKGS + const char *name = pool_id2str(pool, pool->solvables[p].name); + if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) + { + queue_push(updatepkgs_filtered, p); + continue; + } +#endif + if (MAPTST(userinstalled, p - installed->start)) + queue_push(updatepkgs_filtered, p); + } + } +#ifdef CLEANDEPSDEBUG + printf("SEEDS FINAL\n"); + for (i = 0; i < updatepkgs_filtered->count; i++) + printf(" - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i])); +#endif +} + +/* + * Find all installed packages that are no longer + * needed regarding the current solver job. + * + * The algorithm is: + * - remove pass: remove all packages that could have + * been dragged in by the obsoleted packages. + * i.e. if package A is obsolete and contains "Requires: B", + * also remove B, as installing A will have pulled in B. + * after this pass, we have a set of still installed packages + * with broken dependencies. + * - add back pass: + * now add back all packages that the still installed packages + * require. + * + * The cleandeps packages are the packages removed in the first + * pass and not added back in the second pass. + * + * If we search for unneeded packages (unneeded is true), we + * simply remove all packages except the userinstalled ones in + * the first pass. + */ +void +solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Queue *job = &solv->job; + Map userinstalled; + Map im; + Map installedm; + Rule *r; + Id rid, how, what, select; + Id p, pp, ip, jp; + Id req, *reqp, sup, *supp; + Solvable *s; + Queue iq, iqcopy, xsuppq; + Queue updatepkgs_filtered; + int i; + + map_empty(cleandepsmap); + if (!installed || installed->end == installed->start) + return; + map_init(&userinstalled, installed->end - installed->start); + map_init(&im, pool->nsolvables); + map_init(&installedm, pool->nsolvables); + queue_init(&iq); + queue_init(&xsuppq); + + for (i = 0; i < job->count; i += 2) + { + how = job->elements[i]; + if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) + { + what = job->elements[i + 1]; + select = how & SOLVER_SELECTMASK; + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + { + FOR_REPO_SOLVABLES(installed, p, s) + MAPSET(&userinstalled, p - installed->start); + } + FOR_JOB_SELECT(p, pp, select, what) + if (pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + } + if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES)) + { + what = job->elements[i + 1]; + if (ISRELDEP(what)) + { + Reldep *rd = GETRELDEP(pool, what); + if (rd->flags != REL_NAMESPACE) + continue; + if (rd->evr == 0) + { + queue_pushunique(&iq, rd->name); + continue; + } + FOR_PROVIDES(p, pp, what) + if (p) + break; + if (p) + continue; + queue_pushunique(&iq, what); + } + } + } + + /* have special namespace cleandeps erases */ + if (iq.count) + { + for (ip = installed->start; ip < installed->end; ip++) + { + s = pool->solvables + ip; + if (s->repo != installed) + continue; + if (!s->supplements) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup)) + { +#ifdef CLEANDEPSDEBUG + printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip)); +#endif + queue_pushunique(&xsuppq, sup); + } + } + queue_empty(&iq); + } + + /* also add visible patterns to userinstalled for openSUSE */ + if (1) + { + Dataiterator di; + dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0); + while (dataiterator_step(&di)) + { + Id *dp; + if (di.solvid <= 0) + continue; + s = pool->solvables + di.solvid; + if (!s->repo || !s->requires) + continue; + if (s->repo != installed && !pool_installable(pool, s)) + continue; + if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0) + continue; + dp = s->repo->idarraydata + s->requires; + for (dp = s->repo->idarraydata + s->requires; *dp; dp++) + FOR_PROVIDES(p, pp, *dp) + if (pool->solvables[p].repo == installed) + { + if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0) + continue; + MAPSET(&userinstalled, p - installed->start); + } + } + dataiterator_free(&di); + } + if (1) + { + /* all products and their buddies are userinstalled */ + for (p = installed->start; p < installed->end; p++) + { + Solvable *s = pool->solvables + p; + if (s->repo != installed) + continue; + if (!strncmp("product:", pool_id2str(pool, s->name), 8)) + { + MAPSET(&userinstalled, p - installed->start); +#ifdef ENABLE_LINKED_PKGS + if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1) + { + Id buddy = solv->instbuddy[p - installed->start]; + if (buddy >= installed->start && buddy < installed->end) + MAPSET(&userinstalled, buddy - installed->start); + } +#endif + } + } + } + + /* add all positive elements (e.g. locks) to "userinstalled" */ + for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) + { + r = solv->rules + rid; + if (r->d < 0) + continue; + i = solv->ruletojob.elements[rid - solv->jobrules]; + if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS) + continue; + FOR_RULELITERALS(p, jp, r) + if (p > 0 && pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + } + + /* add all cleandeps candidates to iq */ + for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) + { + r = solv->rules + rid; + if (r->d < 0) /* disabled? */ + continue; + if (r->d == 0 && r->p < 0 && r->w2 == 0) /* negative assertion (erase job)? */ + { + p = -r->p; + if (pool->solvables[p].repo != installed) + continue; + MAPCLR(&userinstalled, p - installed->start); + if (unneeded) + continue; + i = solv->ruletojob.elements[rid - solv->jobrules]; + how = job->elements[i]; + if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS)) + queue_push(&iq, p); + } + else if (r->p > 0) /* install job */ + { + if (unneeded) + continue; + i = solv->ruletojob.elements[rid - solv->jobrules]; + if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS) + { + /* check if the literals all obsolete some installed package */ + Map om; + int iqstart; + + /* just one installed literal */ + if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed) + continue; + /* multiversion is bad */ + if (solv->multiversion.size && !solv->keepexplicitobsoletes) + { + FOR_RULELITERALS(p, jp, r) + if (MAPTST(&solv->multiversion, p)) + break; + if (p) + continue; + } + + om.size = 0; + iqstart = iq.count; + FOR_RULELITERALS(p, jp, r) + { + if (p < 0) + { + queue_truncate(&iq, iqstart); /* abort */ + break; + } + if (pool->solvables[p].repo == installed) + { + if (iq.count == iqstart) + queue_push(&iq, p); + else + { + for (i = iqstart; i < iq.count; i++) + if (iq.elements[i] == p) + break; + queue_truncate(&iq, iqstart); + if (i < iq.count) + queue_push(&iq, p); + } + } + else + solver_intersect_obsoleted(solv, p, &iq, iqstart, &om); + if (iq.count == iqstart) + break; + } + if (om.size) + map_free(&om); + } + } + } + queue_init_clone(&iqcopy, &iq); + + if (!unneeded) + { + if (solv->cleandeps_updatepkgs) + for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) + queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]); + } + + if (unneeded) + queue_empty(&iq); /* just in case... */ + + /* clear userinstalled bit for the packages we really want to delete/update */ + for (i = 0; i < iq.count; i++) + { + p = iq.elements[i]; + if (pool->solvables[p].repo != installed) + continue; + MAPCLR(&userinstalled, p - installed->start); + } + + for (p = installed->start; p < installed->end; p++) + { + if (pool->solvables[p].repo != installed) + continue; + MAPSET(&installedm, p); + if (pool->considered && !MAPTST(pool->considered, p)) + MAPSET(&userinstalled, p - installed->start); /* we may not remove those */ + if (unneeded && !MAPTST(&userinstalled, p - installed->start)) + continue; + MAPSET(&im, p); + } + MAPSET(&installedm, SYSTEMSOLVABLE); + MAPSET(&im, SYSTEMSOLVABLE); + + if (!unneeded && solv->cleandeps_updatepkgs) + { + /* find update "seeds" */ + queue_init(&updatepkgs_filtered); + find_update_seeds(solv, &updatepkgs_filtered, &userinstalled); + } + +#ifdef CLEANDEPSDEBUG + printf("REMOVE PASS\n"); +#endif + + for (;;) + { + if (!iq.count) + { + if (unneeded) + break; + /* supplements pass */ + for (ip = installed->start; ip < installed->end; ip++) + { + if (!MAPTST(&installedm, ip)) + continue; + s = pool->solvables + ip; + if (!s->supplements) + continue; + if (!MAPTST(&im, ip)) + continue; + if (MAPTST(&userinstalled, ip - installed->start)) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_dep_possible(solv, sup, &im)) + break; + if (!sup) + { + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup))) + { + /* no longer supplemented, also erase */ + int iqcount = iq.count; + /* pin packages, see comment above dep_pkgcheck */ + dep_pkgcheck(solv, sup, &im, &iq); + for (i = iqcount; i < iq.count; i++) + { + Id pqp = iq.elements[i]; + if (pool->solvables[pqp].repo == installed) + MAPSET(&userinstalled, pqp - installed->start); + } + queue_truncate(&iq, iqcount); +#ifdef CLEANDEPSDEBUG + printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup)); +#endif + queue_push(&iq, ip); + } + } + } + if (!iq.count) + break; /* no supplementing package found, we're done */ + } + ip = queue_shift(&iq); + s = pool->solvables + ip; + if (!MAPTST(&im, ip)) + continue; + if (!MAPTST(&installedm, ip)) + continue; + if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start)) + continue; + MAPCLR(&im, ip); +#ifdef CLEANDEPSDEBUG + printf("removing %s\n", pool_solvable2str(pool, s)); +#endif + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + if (req == SOLVABLE_PREREQMARKER) + continue; +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, req)) + { + complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq); + continue; + } +#endif + FOR_PROVIDES(p, pp, req) + { + if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) + { +#ifdef CLEANDEPSDEBUG + printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + queue_push(&iq, p); + } + } + } + } + if (s->recommends) + { + reqp = s->repo->idarraydata + s->recommends; + while ((req = *reqp++) != 0) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, req)) + { + complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq); + continue; + } +#endif + FOR_PROVIDES(p, pp, req) + { + if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) + { +#ifdef CLEANDEPSDEBUG + printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + queue_push(&iq, p); + } + } + } + } + } + + /* turn userinstalled into remove set for pruning */ + map_empty(&userinstalled); + for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) + { + r = solv->rules + rid; + if (r->p >= 0 || r->d != 0 || r->w2 != 0) + continue; /* disabled or not erase */ + p = -r->p; + MAPCLR(&im, p); + if (pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + } + if (!unneeded && solv->cleandeps_updatepkgs) + { + for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) + { + p = solv->cleandeps_updatepkgs->elements[i]; + if (pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + } + } + MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */ + for (p = installed->start; p < installed->end; p++) + if (MAPTST(&im, p)) + queue_push(&iq, p); + for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) + { + r = solv->rules + rid; + if (r->d < 0) + continue; + FOR_RULELITERALS(p, jp, r) + if (p > 0) + queue_push(&iq, p); + } + /* also put directly addressed packages on the install queue + * so we can mark patterns as installed */ + for (i = 0; i < job->count; i += 2) + { + how = job->elements[i]; + if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) + { + what = job->elements[i + 1]; + select = how & SOLVER_SELECTMASK; + if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed) + queue_push(&iq, what); + } + } + +#ifdef CLEANDEPSDEBUG + printf("ADDBACK PASS\n"); +#endif + for (;;) + { + if (!iq.count) + { + /* supplements pass */ + for (ip = installed->start; ip < installed->end; ip++) + { + if (!MAPTST(&installedm, ip)) + continue; + if (MAPTST(&userinstalled, ip - installed->start)) + continue; + s = pool->solvables + ip; + if (!s->supplements) + continue; + if (MAPTST(&im, ip)) + continue; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_dep_possible(solv, sup, &im)) + break; + if (sup) + { +#ifdef CLEANDEPSDEBUG + printf("%s supplemented\n", pool_solvid2str(pool, ip)); +#endif + MAPSET(&im, ip); + queue_push(&iq, ip); + } + } + if (!iq.count) + break; + } + ip = queue_shift(&iq); + s = pool->solvables + ip; +#ifdef CLEANDEPSDEBUG + printf("adding back %s\n", pool_solvable2str(pool, s)); +#endif + if (s->repo == installed && pool->implicitobsoleteusescolors) + { + unsigned int a, bestscore = 0; + FOR_PROVIDES(p, pp, s->name) + { + Solvable *ps = pool->solvables + p; + if (ps->name != s->name || ps->repo == installed) + continue; + a = pool_arch2score(pool, ps->arch); + if (a && a != 1 && (!bestscore || a < bestscore)) + bestscore = a; + } + if (bestscore && pool_arch2score(pool, s->arch) != bestscore) + { + FOR_PROVIDES(p, pp, s->name) + { + Solvable *ps = pool->solvables + p; + if (ps->repo == installed && ps->name == s->name && ps->evr == s->evr && ps->arch != s->arch && pool_arch2score(pool, ps->arch) == bestscore) + if (!MAPTST(&im, p)) + { +#ifdef CLEANDEPSDEBUG + printf("%s lockstep %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + MAPSET(&im, p); + queue_push(&iq, p); + } + } + } + } + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, req)) + { + complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled); + continue; + } +#endif + FOR_PROVIDES(p, pp, req) + if (p == ip) + break; + if (p) + continue; + FOR_PROVIDES(p, pp, req) + { + if (MAPTST(&im, p)) + continue; + if (MAPTST(&installedm, p)) + { + if (p == ip) + continue; + if (MAPTST(&userinstalled, p - installed->start)) + continue; +#ifdef CLEANDEPSDEBUG + printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + MAPSET(&im, p); + queue_push(&iq, p); + } + } + } + } + if (s->recommends) + { + reqp = s->repo->idarraydata + s->recommends; + while ((req = *reqp++) != 0) + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, req)) + { + complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled); + continue; + } +#endif + FOR_PROVIDES(p, pp, req) + if (p == ip) + break; + if (p) + continue; + FOR_PROVIDES(p, pp, req) + { + if (MAPTST(&im, p)) + continue; + if (MAPTST(&installedm, p)) + { + if (p == ip) + continue; + if (MAPTST(&userinstalled, p - installed->start)) + continue; +#ifdef CLEANDEPSDEBUG + printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); +#endif + MAPSET(&im, p); + queue_push(&iq, p); + } + } + } + } + } + + queue_free(&iq); + /* make sure the updatepkgs and mistakes are not in the cleandeps map */ + if (!unneeded && solv->cleandeps_updatepkgs) + { + for (i = 0; i < updatepkgs_filtered.count; i++) + MAPSET(&im, updatepkgs_filtered.elements[i]); + queue_free(&updatepkgs_filtered); + } + if (solv->cleandeps_mistakes) + for (i = 0; i < solv->cleandeps_mistakes->count; i++) + MAPSET(&im, solv->cleandeps_mistakes->elements[i]); + /* also remove original iq packages */ + for (i = 0; i < iqcopy.count; i++) + MAPSET(&im, iqcopy.elements[i]); + queue_free(&iqcopy); + for (p = installed->start; p < installed->end; p++) + { + if (pool->solvables[p].repo != installed) + continue; + if (pool->considered && !MAPTST(pool->considered, p)) + continue; + if (!MAPTST(&im, p)) + MAPSET(cleandepsmap, p - installed->start); + } + map_free(&im); + map_free(&installedm); + map_free(&userinstalled); + queue_free(&xsuppq); +#ifdef CLEANDEPSDEBUG + printf("=== final cleandeps map:\n"); + for (p = installed->start; p < installed->end; p++) + if (MAPTST(cleandepsmap, p - installed->start)) + printf(" - %s\n", pool_solvid2str(pool, p)); +#endif +} + +void +solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered) +{ + Repo *installed = solv->installed; + int i; + Map cleandepsmap; + + queue_empty(unneededq); + if (!installed || installed->end == installed->start) + return; + + map_init(&cleandepsmap, installed->end - installed->start); + solver_createcleandepsmap(solv, &cleandepsmap, 1); + for (i = installed->start; i < installed->end; i++) + if (MAPTST(&cleandepsmap, i - installed->start)) + queue_push(unneededq, i); + + if (filtered) + filter_unneeded(solv, unneededq, &cleandepsmap, 0); + map_free(&cleandepsmap); +} + +static void +add_cleandeps_mistake(Solver *solv, Id p) +{ + if (!solv->cleandeps_mistakes) + { + solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue)); + queue_init(solv->cleandeps_mistakes); + } + queue_push(solv->cleandeps_mistakes, p); + MAPCLR(&solv->cleandepsmap, p - solv->installed->start); + solver_reenablepolicyrules_cleandeps(solv, p); +} + +static inline int +cleandeps_rule_is_true(Solver *solv, Rule *r) +{ + Pool *pool = solv->pool; + Id p, pp; + FOR_RULELITERALS(p, pp, r) + if (p > 0 && solv->decisionmap[p] > 0) + return 1; + return 0; +} + +int +solver_check_cleandeps_mistakes(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Rule *fr; + int i, j, nj; + int mademistake = 0; + + if (!solv->cleandepsmap.size || !installed) + return 0; + /* check for mistakes */ + policy_update_recommendsmap(solv); + for (i = installed->start; i < installed->end; i++) + { + if (pool->solvables[i].repo != installed) + continue; + if (solv->decisionmap[i] > 0) + { + Id req, *reqp; + Solvable *s = pool->solvables + i; + /* kept package, check requires. we need to do this for things like requires(pre) */ + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + Id p2, pp2; + FOR_PROVIDES(p2, pp2, req) + { + if (pool->solvables[p2].repo != installed) + continue; + if (p2 == i || solv->decisionmap[p2] > 0) + continue; + if (!MAPTST(&solv->cleandepsmap, p2 - installed->start)) + continue; + POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps requires mistake: %s %s %s\n", pool_solvid2str(pool, i), pool_dep2str(pool, req), pool_solvid2str(pool, p2)); + add_cleandeps_mistake(solv, p2); + mademistake = 1; + } + } + } + if (!MAPTST(&solv->cleandepsmap, i - installed->start)) + continue; + /* a mistake is when the featurerule is true but the updaterule is false */ + fr = solv->rules + solv->featurerules + (i - installed->start); + if (!fr->p) + fr = solv->rules + solv->updaterules + (i - installed->start); + if (!fr->p) + continue; + if (!cleandeps_rule_is_true(solv, fr)) + { + /* feature rule is not true, thus we cleandeps erased the package */ + /* check if the package is recommended/supplemented. if yes, we made a mistake. */ + if (!MAPTST(&solv->recommendsmap, i) && !solver_is_supplementing(solv, pool->solvables + i)) + continue; /* feature rule is not true */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps recommends mistake: "); + solver_printruleclass(solv, SOLV_DEBUG_SOLVER, fr); + } + else + { + Rule *r = solv->rules + solv->updaterules + (i - installed->start); + if (!r->p || r == fr || cleandeps_rule_is_true(solv, r)) + { + /* update rule is true, check best rules */ + if (!solv->bestrules_pkg) + continue; + nj = solv->bestrules_end - solv->bestrules; + for (j = 0; j < nj; j++) + if (solv->bestrules_pkg[j] == i) + { + r = solv->rules + solv->bestrules + j; + if (!cleandeps_rule_is_true(solv, r)) + break; + } + if (j == nj) + continue; + } + POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: "); + solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r); + POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: "); + solver_printruleclass(solv, SOLV_DEBUG_SOLVER, fr); + } + add_cleandeps_mistake(solv, i); + mademistake = 1; + } + return mademistake; +} diff --git a/libsolv-0.7.2/src/cplxdeps.c b/libsolv-0.7.2/src/cplxdeps.c new file mode 100644 index 0000000..6c40752 --- /dev/null +++ b/libsolv-0.7.2/src/cplxdeps.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2014, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * cplxdeps.c + * + * normalize complex dependencies into CNF/DNF form + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "cplxdeps.h" + +#ifdef ENABLE_COMPLEX_DEPS + +#undef CPLXDEBUG + +int +pool_is_complex_dep_rd(Pool *pool, Reldep *rd) +{ + for (;;) + { + if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS) /* those two are the complex ones */ + return 1; + if (rd->flags != REL_OR) + return 0; + if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name))) + return 1; + if (!ISRELDEP(rd->evr)) + return 0; + rd = GETRELDEP(pool, rd->evr); + } +} + +/* expand simple dependencies into package lists */ +static int +expand_simpledeps(Pool *pool, Queue *bq, int start, int split) +{ + int end = bq->count; + int i, x; + int newsplit = 0; + for (i = start; i < end; i++) + { + if (i == split) + newsplit = bq->count - (end - start); + x = bq->elements[i]; + if (x == pool->nsolvables) + { + Id *dp = pool->whatprovidesdata + bq->elements[++i]; + for (; *dp; dp++) + queue_push(bq, *dp); + } + else + queue_push(bq, x); + } + if (i == split) + newsplit = bq->count - (end - start); + queue_deleten(bq, start, end - start); + return newsplit; +} + +#ifdef CPLXDEBUG +static void +print_depblocks(Pool *pool, Queue *bq, int start) +{ + int i; + + for (i = start; i < bq->count; i++) + { + if (bq->elements[i] == pool->nsolvables) + { + Id *dp = pool->whatprovidesdata + bq->elements[++i]; + printf(" ("); + while (*dp) + printf(" %s", pool_solvid2str(pool, *dp++)); + printf(" )"); + } + else if (bq->elements[i] > 0) + printf(" %s", pool_solvid2str(pool, bq->elements[i])); + else if (bq->elements[i] < 0) + printf(" -%s", pool_solvid2str(pool, -bq->elements[i])); + else + printf(" ||"); + } + printf("\n"); +} +#endif + +/* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */ +static int +invert_depblocks(Pool *pool, Queue *bq, int start, int r) +{ + int i, j, end; + if (r == 0 || r == 1) + return r ? 0 : 1; + expand_simpledeps(pool, bq, start, 0); + end = bq->count; + for (i = j = start; i < end; i++) + { + if (bq->elements[i]) + { + bq->elements[i] = -bq->elements[i]; + continue; + } + /* end of block reached, reverse */ + if (i - 1 > j) + { + int k; + for (k = i - 1; j < k; j++, k--) + { + Id t = bq->elements[j]; + bq->elements[j] = bq->elements[k]; + bq->elements[k] = t; + } + } + j = i + 1; + } + return -1; +} + +/* distributive property: (a1*a2 + b1*b2) * (c1*c2 + d1*d2) = + a1*a2*c1*c2 + a1*a2*d1*d2 + b1*b2*c1*c2 + b1*b2*d1*d2 */ +static int +distribute_depblocks(Pool *pool, Queue *bq, int bqcnt, int bqcnt2, int flags) +{ + int i, j, bqcnt3; +#ifdef CPLXDEBUG + printf("COMPLEX DISTRIBUTE %d %d %d\n", bqcnt, bqcnt2, bq->count); +#endif + bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2); + bqcnt3 = bq->count; + for (i = bqcnt; i < bqcnt2; i++) + { + for (j = bqcnt2; j < bqcnt3; j++) + { + int a, b; + int bqcnt4 = bq->count; + int k = i; + + /* mix i block with j block, both blocks are sorted */ + while (bq->elements[k] && bq->elements[j]) + { + if (bq->elements[k] < bq->elements[j]) + queue_push(bq, bq->elements[k++]); + else + { + if (bq->elements[k] == bq->elements[j]) + k++; + queue_push(bq, bq->elements[j++]); + } + } + while (bq->elements[j]) + queue_push(bq, bq->elements[j++]); + while (bq->elements[k]) + queue_push(bq, bq->elements[k++]); + + /* block is finished, check for A + -A */ + for (a = bqcnt4, b = bq->count - 1; a < b; ) + { + if (-bq->elements[a] == bq->elements[b]) + break; + if (-bq->elements[a] > bq->elements[b]) + a++; + else + b--; + } + if (a < b) + queue_truncate(bq, bqcnt4); /* ignore this block */ + else + queue_push(bq, 0); /* finish block */ + } + /* advance to next block */ + while (bq->elements[i]) + i++; + } + queue_deleten(bq, bqcnt, bqcnt3 - bqcnt); + if (bqcnt == bq->count) + return flags & CPLXDEPS_TODNF ? 0 : 1; + return -1; +} + +static int normalize_dep(Pool *pool, Id dep, Queue *bq, int flags); + +static int +normalize_dep_or(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags) +{ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep(pool, dep1, bq, flags); + if (r1 == 1) + return 1; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep(pool, dep2, bq, flags ^ invflags); + if (invflags) + r2 = invert_depblocks(pool, bq, bqcnt2, r2); + if (r1 == 1 || r2 == 1) + { + queue_truncate(bq, bqcnt); + return 1; + } + if (r1 == 0) + return r2; + if (r2 == 0) + return r1; + if ((flags & CPLXDEPS_TODNF) == 0) + return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_and(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags) +{ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep(pool, dep1, bq, flags); + if (r1 == 0) + return 0; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep(pool, dep2, bq, flags ^ invflags); + if (invflags) + r2 = invert_depblocks(pool, bq, bqcnt2, r2); + if (r1 == 0 || r2 == 0) + { + queue_truncate(bq, bqcnt); + return 0; + } + if (r1 == 1) + return r2; + if (r2 == 1) + return r1; + if ((flags & CPLXDEPS_TODNF) != 0) + return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_if_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags) +{ + /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep_or(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF); + if (r1 == 0) + return 0; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep_or(pool, dep2, dep3, bq, flags, 0); + if (r1 == 0 || r2 == 0) + { + queue_truncate(bq, bqcnt); + return 0; + } + if (r1 == 1) + return r2; + if (r2 == 1) + return r1; + if ((flags & CPLXDEPS_TODNF) != 0) + return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags); + return -1; +} + +static int +normalize_dep_unless_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags) +{ + /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */ + int r1, r2, bqcnt2, bqcnt = bq->count; + r1 = normalize_dep_and(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF); + if (r1 == 1) + return 1; /* early exit */ + bqcnt2 = bq->count; + r2 = normalize_dep_and(pool, dep2, dep3, bq, flags, 0); + if (r1 == 1 || r2 == 1) + { + queue_truncate(bq, bqcnt); + return 1; + } + if (r1 == 0) + return r2; + if (r2 == 0) + return r1; + if ((flags & CPLXDEPS_TODNF) == 0) + return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags); + return -1; +} + +/* + * returns: + * 0: no blocks + * 1: matches all + * -1: at least one block + */ +static int +normalize_dep(Pool *pool, Id dep, Queue *bq, int flags) +{ + Id p, dp; + int bqcnt; + + if (pool_is_complex_dep(pool, dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND) + { + Id evr = rd->evr; + if (ISRELDEP(evr)) + { + Reldep *rd2 = GETRELDEP(pool, evr); + if (rd2->flags == REL_ELSE) + return normalize_dep_if_else(pool, rd->name, rd2->name, rd2->evr, bq, flags); + } + return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF); + } + if (rd->flags == REL_UNLESS) + { + Id evr = rd->evr; + if (ISRELDEP(evr)) + { + Reldep *rd2 = GETRELDEP(pool, evr); + if (rd2->flags == REL_ELSE) + return normalize_dep_unless_else(pool, rd->name, rd2->name, rd2->evr, bq, flags); + } + return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF); + } + if (rd->flags == REL_OR) + return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, 0); + if (rd->flags == REL_AND) + return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, 0); + } + + /* fallback case: just use package list */ + dp = pool_whatprovides(pool, dep); + if (dp <= 2 || !pool->whatprovidesdata[dp]) + return dp == 2 ? 1 : 0; + if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE) + return 1; + bqcnt = bq->count; + if ((flags & CPLXDEPS_NAME) != 0) + { + while ((p = pool->whatprovidesdata[dp++]) != 0) + { + if (!pool_match_nevr(pool, pool->solvables + p, dep)) + continue; + queue_push(bq, p); + if ((flags & CPLXDEPS_TODNF) != 0) + queue_push(bq, 0); + } + } + else if ((flags & CPLXDEPS_TODNF) != 0) + { + while ((p = pool->whatprovidesdata[dp++]) != 0) + queue_push2(bq, p, 0); + } + else + queue_push2(bq, pool->nsolvables, dp); /* not yet expanded marker + offset */ + if (bq->count == bqcnt) + return 0; /* no provider */ + if (!(flags & CPLXDEPS_TODNF)) + queue_push(bq, 0); /* finish block */ + return -1; +} + +int +pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags) +{ + int i, bqcnt = bq->count; + + i = normalize_dep(pool, dep, bq, flags); + if ((flags & CPLXDEPS_EXPAND) != 0) + { + if (i != 0 && i != 1) + expand_simpledeps(pool, bq, bqcnt, 0); + } + if ((flags & CPLXDEPS_INVERT) != 0) + i = invert_depblocks(pool, bq, bqcnt, i); +#ifdef CPLXDEBUG + if (i == 0) + printf("NONE\n"); + else if (i == 1) + printf("ALL\n"); + else + print_depblocks(pool, bq, bqcnt); +#endif + return i; +} + +void +pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg) +{ + while (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND && rd->flags != REL_UNLESS) + break; + pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg); + dep = rd->evr; + if (rd->flags == REL_COND || rd->flags == REL_UNLESS) + { + neg = !neg; + if (ISRELDEP(dep)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg); + dep = rd2->name; + } + } + } + } + if (!neg) + { + Id p, pp; + FOR_PROVIDES(p, pp, dep) + if (!MAPTST(m, p)) + queue_push(q, p); + } +} + +#endif /* ENABLE_COMPLEX_DEPS */ + diff --git a/libsolv-0.6.15/src/cplxdeps.h b/libsolv-0.7.2/src/cplxdeps.h similarity index 79% rename from libsolv-0.6.15/src/cplxdeps.h rename to libsolv-0.7.2/src/cplxdeps.h index 798b485..7c5946a 100644 --- a/libsolv-0.6.15/src/cplxdeps.h +++ b/libsolv-0.7.2/src/cplxdeps.h @@ -35,12 +35,5 @@ extern void pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map #define CPLXDEPS_NAME (1 << 3) #define CPLXDEPS_DONTFIX (1 << 4) -#define CPLXDEPS_ELSE_AND_1 (1 << 8) -#define CPLXDEPS_ELSE_AND_2 (1 << 9) -#define CPLXDEPS_ELSE_OR_1 (1 << 10) -#define CPLXDEPS_ELSE_OR_2 (1 << 11) -#define CPLXDEPS_ELSE_OR_3 (1 << 12) -#define CPLXDEPS_ELSE_MASK (0x1f00) - #endif diff --git a/libsolv-0.6.15/src/dataiterator.h b/libsolv-0.7.2/src/dataiterator.h similarity index 85% rename from libsolv-0.6.15/src/dataiterator.h rename to libsolv-0.7.2/src/dataiterator.h index 3133686..0649258 100644 --- a/libsolv-0.6.15/src/dataiterator.h +++ b/libsolv-0.7.2/src/dataiterator.h @@ -20,9 +20,9 @@ extern "C" { #endif -struct _Repo; +struct s_Repo; -typedef struct _KeyValue { +typedef struct s_KeyValue { Id id; const char *str; unsigned int num; @@ -31,7 +31,7 @@ typedef struct _KeyValue { int entry; /* array entry, starts with 0 */ int eof; /* last entry reached */ - struct _KeyValue *parent; + struct s_KeyValue *parent; } KeyValue; #define SOLV_KV_NUM64(kv) (((unsigned long long)((kv)->num2)) << 32 | (kv)->num) @@ -52,7 +52,7 @@ typedef struct _KeyValue { #define SEARCH_SUB (1<<9) #define SEARCH_ARRAYSENTINEL (1<<10) #define SEARCH_DISABLED_REPOS (1<<11) -#define SEARCH_COMPLETE_FILELIST (1<<12) +#define SEARCH_KEEP_TYPE_DELETED (1<<12) /* only has effect if no keyname is given */ /* stringification flags */ #define SEARCH_SKIP_KIND (1<<16) @@ -62,13 +62,17 @@ typedef struct _KeyValue { #define SEARCH_FILES (1<<17) #define SEARCH_CHECKSUMS (1<<18) -/* dataiterator internal */ +/* internal */ +#define SEARCH_SUBSCHEMA (1<<30) #define SEARCH_THISSOLVID (1<<31) +/* obsolete */ +#define SEARCH_COMPLETE_FILELIST 0 /* ignored, this is the default */ + /* * Datamatcher: match a string against a query */ -typedef struct _Datamatcher { +typedef struct s_Datamatcher { int flags; /* see matcher flags above */ const char *match; /* the query string */ void *matchdata; /* e.g. compiled regexp */ @@ -96,14 +100,14 @@ int datamatcher_checkbasename(Datamatcher *ma, const char *str); * dosomething(di.solvid, di.key, di.kv); * dataiterator_free(&di); */ -typedef struct _Dataiterator +typedef struct s_Dataiterator { int state; int flags; Pool *pool; - struct _Repo *repo; - struct _Repodata *data; + struct s_Repo *repo; + struct s_Repodata *data; /* data pointers */ unsigned char *dp; @@ -112,7 +116,7 @@ typedef struct _Dataiterator Id *keyp; /* the result */ - struct _Repokey *key; + struct s_Repokey *key; KeyValue kv; /* our matcher */ @@ -146,6 +150,8 @@ typedef struct _Dataiterator char *dupstr; int dupstrn; + Id *keyskip; + Id *oldkeyskip; } Dataiterator; @@ -159,9 +165,9 @@ typedef struct _Dataiterator * keyname: if non-null, limit search to this keyname * match: if non-null, limit search to this match */ -int dataiterator_init(Dataiterator *di, Pool *pool, struct _Repo *repo, Id p, Id keyname, const char *match, int flags); +int dataiterator_init(Dataiterator *di, Pool *pool, struct s_Repo *repo, Id p, Id keyname, const char *match, int flags); void dataiterator_init_clone(Dataiterator *di, Dataiterator *from); -void dataiterator_set_search(Dataiterator *di, struct _Repo *repo, Id p); +void dataiterator_set_search(Dataiterator *di, struct s_Repo *repo, Id p); void dataiterator_set_keyname(Dataiterator *di, Id keyname); int dataiterator_set_match(Dataiterator *di, const char *match, int flags); @@ -175,7 +181,7 @@ void dataiterator_skip_attribute(Dataiterator *di); void dataiterator_skip_solvable(Dataiterator *di); void dataiterator_skip_repo(Dataiterator *di); void dataiterator_jump_to_solvid(Dataiterator *di, Id solvid); -void dataiterator_jump_to_repo(Dataiterator *di, struct _Repo *repo); +void dataiterator_jump_to_repo(Dataiterator *di, struct s_Repo *repo); void dataiterator_entersub(Dataiterator *di); void dataiterator_clonepos(Dataiterator *di, Dataiterator *from); void dataiterator_seek(Dataiterator *di, int whence); diff --git a/libsolv-0.6.15/src/dirpool.c b/libsolv-0.7.2/src/dirpool.c similarity index 97% rename from libsolv-0.6.15/src/dirpool.c rename to libsolv-0.7.2/src/dirpool.c index 5f08361..afb26ea 100644 --- a/libsolv-0.6.15/src/dirpool.c +++ b/libsolv-0.7.2/src/dirpool.c @@ -99,7 +99,7 @@ dirpool_make_dirtraverse(Dirpool *dp) Id dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create) { - Id did, d, ds, *dirtraverse; + Id did, d, ds; if (!dp->ndirs) { @@ -110,14 +110,15 @@ dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create) dp->dirs[0] = 0; dp->dirs[1] = 1; /* "" */ } + if (comp <= 0) + return 0; if (parent == 0 && comp == 1) return 1; if (!dp->dirtraverse) dirpool_make_dirtraverse(dp); /* check all entries with this parent if we * already have this component */ - dirtraverse = dp->dirtraverse; - ds = dirtraverse[parent]; + ds = dp->dirtraverse[parent]; while (ds) { /* ds: first component in this block diff --git a/libsolv-0.6.15/src/dirpool.h b/libsolv-0.7.2/src/dirpool.h similarity index 98% rename from libsolv-0.6.15/src/dirpool.h rename to libsolv-0.7.2/src/dirpool.h index fe05cc6..ca92954 100644 --- a/libsolv-0.6.15/src/dirpool.h +++ b/libsolv-0.7.2/src/dirpool.h @@ -15,7 +15,7 @@ extern "C" { #endif -typedef struct _Dirpool { +typedef struct s_Dirpool { Id *dirs; int ndirs; Id *dirtraverse; diff --git a/libsolv-0.7.2/src/diskusage.c b/libsolv-0.7.2/src/diskusage.c new file mode 100644 index 0000000..63c43bf --- /dev/null +++ b/libsolv-0.7.2/src/diskusage.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2007-2016, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * diskusage.c + * + * calculate needed space on partitions + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "poolarch.h" +#include "repo.h" +#include "util.h" +#include "bitmap.h" + + +struct mptree { + Id sibling; + Id child; + const char *comp; + int compl; + Id mountpoint; +}; + +struct ducbdata { + DUChanges *mps; + struct mptree *mptree; + int addsub; + int hasdu; + + Id *dirmap; + int nmap; + Repodata *olddata; +}; + + +static int +solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +{ + struct ducbdata *cbd = cbdata; + Id mp; + + if (data != cbd->olddata) + { + Id dn, mp, comp, *dirmap, *dirs; + int i, compl; + const char *compstr; + struct mptree *mptree; + + /* create map from dir to mptree */ + cbd->dirmap = solv_free(cbd->dirmap); + cbd->nmap = 0; + dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); + mptree = cbd->mptree; + mp = 0; + for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) + { + comp = *dirs++; + if (comp <= 0) + { + mp = dirmap[-comp]; + continue; + } + if (mp < 0) + { + /* unconnected */ + dirmap[dn] = mp; + continue; + } + if (!mptree[mp].child) + { + dirmap[dn] = -mp; + continue; + } + if (data->localpool) + compstr = stringpool_id2str(&data->spool, comp); + else + compstr = pool_id2str(data->repo->pool, comp); + compl = strlen(compstr); + for (i = mptree[mp].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + dirmap[dn] = i ? i : -mp; + } + /* change dirmap to point to mountpoint instead of mptree */ + for (dn = 0; dn < data->dirpool.ndirs; dn++) + { + mp = dirmap[dn]; + dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; + } + cbd->dirmap = dirmap; + cbd->nmap = data->dirpool.ndirs; + cbd->olddata = data; + } + cbd->hasdu = 1; + if (value->id < 0 || value->id >= cbd->nmap) + return 0; + mp = cbd->dirmap[value->id]; + if (mp < 0) + return 0; + if (cbd->addsub > 0) + { + cbd->mps[mp].kbytes += value->num; + cbd->mps[mp].files += value->num2; + } + else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) + { + cbd->mps[mp].kbytes -= value->num; + cbd->mps[mp].files -= value->num2; + } + return 0; +} + +static void +propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) +{ + int i; + if (mptree[pos].mountpoint == -1) + mptree[pos].mountpoint = mountpoint; + else + mountpoint = mptree[pos].mountpoint; + for (i = mptree[pos].child; i; i = mptree[i].sibling) + propagate_mountpoints(mptree, i, mountpoint); +} + +#define MPTREE_BLOCK 15 + +static struct mptree * +create_mptree(DUChanges *mps, int nmps) +{ + int i, nmptree; + struct mptree *mptree; + int pos, compl; + int mp; + const char *p, *path, *compstr; + + mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); + + /* our root node */ + mptree[0].sibling = 0; + mptree[0].child = 0; + mptree[0].comp = 0; + mptree[0].compl = 0; + mptree[0].mountpoint = -1; + nmptree = 1; + + /* create component tree */ + for (mp = 0; mp < nmps; mp++) + { + mps[mp].kbytes = 0; + mps[mp].files = 0; + pos = 0; + path = mps[mp].path; + while(*path == '/') + path++; + while (*path) + { + if ((p = strchr(path, '/')) == 0) + { + compstr = path; + compl = strlen(compstr); + path += compl; + } + else + { + compstr = path; + compl = p - path; + path = p + 1; + while(*path == '/') + path++; + } + for (i = mptree[pos].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + if (!i) + { + /* create new node */ + mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); + i = nmptree++; + mptree[i].sibling = mptree[pos].child; + mptree[i].child = 0; + mptree[i].comp = compstr; + mptree[i].compl = compl; + mptree[i].mountpoint = -1; + mptree[pos].child = i; + } + pos = i; + } + mptree[pos].mountpoint = mp; + } + + propagate_mountpoints(mptree, 0, mptree[0].mountpoint); + +#if 0 + for (i = 0; i < nmptree; i++) + { + printf("#%d sibling: %d\n", i, mptree[i].sibling); + printf("#%d child: %d\n", i, mptree[i].child); + printf("#%d comp: %s\n", i, mptree[i].comp); + printf("#%d compl: %d\n", i, mptree[i].compl); + printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); + } +#endif + + return mptree; +} + +void +pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) +{ + struct mptree *mptree; + struct ducbdata cbd; + Solvable *s; + int i, sp; + Map ignoredu; + Repo *oldinstalled = pool->installed; + int haveonlyadd = 0; + + map_init(&ignoredu, 0); + mptree = create_mptree(mps, nmps); + + for (i = 0; i < nmps; i++) + if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) + haveonlyadd = 1; + cbd.mps = mps; + cbd.dirmap = 0; + cbd.nmap = 0; + cbd.olddata = 0; + cbd.mptree = mptree; + cbd.addsub = 1; + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + cbd.hasdu = 0; + repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + if (!cbd.hasdu && oldinstalled) + { + Id op, opp; + int didonlyadd = 0; + /* no du data available, ignore data of all installed solvables we obsolete */ + if (!ignoredu.size) + map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); + FOR_PROVIDES(op, opp, s->name) + { + Solvable *s2 = pool->solvables + op; + if (!pool->implicitobsoleteusesprovides && s->name != s2->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + if (op >= oldinstalled->start && op < oldinstalled->end) + { + MAPSET(&ignoredu, op - oldinstalled->start); + if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) + { + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = -1; + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = 1; + didonlyadd = 1; + } + } + } + if (s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + FOR_PROVIDES(op, opp, obs) + { + Solvable *s2 = pool->solvables + op; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + continue; + if (op >= oldinstalled->start && op < oldinstalled->end) + { + MAPSET(&ignoredu, op - oldinstalled->start); + if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) + { + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = -1; + repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + cbd.addsub = 1; + didonlyadd = 1; + } + } + } + } + } + } + cbd.addsub = -1; + if (oldinstalled) + { + /* assumes we allways have du data for installed solvables */ + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + if (ignoredu.size && MAPTST(&ignoredu, sp - oldinstalled->start)) + continue; + repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + } + } + map_free(&ignoredu); + solv_free(cbd.dirmap); + solv_free(mptree); +} + +long long +pool_calc_installsizechange(Pool *pool, Map *installedmap) +{ + Id sp; + Solvable *s; + long long change = 0; + Repo *oldinstalled = pool->installed; + + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); + } + if (oldinstalled) + { + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); + } + } + return change; +} + diff --git a/libsolv-0.6.15/src/evr.c b/libsolv-0.7.2/src/evr.c similarity index 97% rename from libsolv-0.6.15/src/evr.c rename to libsolv-0.7.2/src/evr.c index a7d4311..c63878e 100644 --- a/libsolv-0.6.15/src/evr.c +++ b/libsolv-0.7.2/src/evr.c @@ -77,10 +77,10 @@ solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2) for (;;) { while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') && - !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~') + !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~' && *s1 != '^') s1++; while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') && - !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~') + !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~' && *s2 != '^') s2++; if (s1 < q1 && *s1 == '~') { @@ -94,6 +94,18 @@ solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2) } if (s2 < q2 && *s2 == '~') return 1; + if (s1 < q1 && *s1 == '^') + { + if (s2 < q2 && *s2 == '^') + { + s1++; + s2++; + continue; + } + return s2 < q2 ? -1 : 1; + } + if (s2 < q2 && *s2 == '^') + return s1 < q1 ? 1 : -1; if (s1 >= q1 || s2 >= q2) break; if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9')) diff --git a/libsolv-0.6.15/src/evr.h b/libsolv-0.7.2/src/evr.h similarity index 100% rename from libsolv-0.6.15/src/evr.h rename to libsolv-0.7.2/src/evr.h diff --git a/libsolv-0.7.2/src/filelistfilter.c b/libsolv-0.7.2/src/filelistfilter.c new file mode 100644 index 0000000..e698d6f --- /dev/null +++ b/libsolv-0.7.2/src/filelistfilter.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2018, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * filelistfilter.c + * + * Support repodata with a filelist filtered by a custom filter + */ + +#define _GNU_SOURCE +#include +#include + +#include +#include +#include +#include + +#include "repo.h" +#include "pool.h" +#include "util.h" + +static Id default_filelist_filter; + +#define FF_EXACT 0 +#define FF_END 1 +#define FF_START 2 +#define FF_SUB 3 /* FF_END | FF_START */ +#define FF_GLOB 4 +#define FF_START5 5 + +void +repodata_free_filelistfilter(Repodata *data) +{ + if (data->filelistfilter) + { + if (data->filelistfilter != &default_filelist_filter) + solv_free(data->filelistfilter); + data->filelistfilter = 0; + } + data->filelistfilterdata = solv_free(data->filelistfilterdata); +} + +static void +repodata_set_filelistfilter(Repodata *data) +{ + Id type; + Queue q; + int i, j; + char *filterdata; + int nfilterdata; + + if (data->filelistfilter && data->filelistfilter != &default_filelist_filter) + data->filelistfilter = solv_free(data->filelistfilter); + data->filelistfilterdata = solv_free(data->filelistfilterdata); + type = repodata_lookup_type(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST); + if (type != REPOKEY_TYPE_IDARRAY) + { + data->filelistfilter = &default_filelist_filter; + return; + } + queue_init(&q); + repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST, &q); + if (q.count == 3) + { + /* check if this is the default filter */ + int t = 0; + for (i = 0; i < 3; i++) + { + Id id = q.elements[i]; + const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); + if (!strcmp(g, "*bin/*")) + t |= 1; + else if (!strcmp(g, "/etc/*")) + t |= 2; + else if (!strcmp(g, "/usr/lib/sendmail")) + t |= 4; + } + if (t == 7) + { + queue_free(&q); + data->filelistfilter = &default_filelist_filter; + return; + } + } + data->filelistfilter = solv_calloc(q.count * 2 + 1, sizeof(Id)); + filterdata = solv_calloc_block(1, 1, 255); + nfilterdata = 1; + + for (i = j = 0; i < q.count; i++) + { + Id id = q.elements[i]; + const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); + const char *p; + int t = FF_EXACT; + int gl; + if (!id || !g || !*g) + continue; + for (p = g; *p && t != FF_GLOB; p++) + { + if (*p == '*') + { + if (p == g) + t |= FF_END; + else if (!p[1]) + t |= FF_START; + else + t = FF_GLOB; + } + else if (*p == '[' || *p == '?') + t = FF_GLOB; + } + gl = strlen(g); + if (t == FF_END) /* not supported */ + t = FF_GLOB; + if (t == FF_START && gl == 5) + t = FF_START5; + filterdata = solv_extend(filterdata, nfilterdata, gl + 1, 1, 255); + data->filelistfilter[j++] = nfilterdata; + data->filelistfilter[j++] = t; + switch (t) + { + case FF_START: + case FF_START5: + strcpy(filterdata + nfilterdata, g); + filterdata[nfilterdata + gl - 1] = 0; + nfilterdata += gl; + break; + case FF_SUB: + strcpy(filterdata + nfilterdata, g + 1); + filterdata[nfilterdata + gl - 2] = 0; + nfilterdata += gl - 1; + break; + default: + strcpy(filterdata + nfilterdata, g); + nfilterdata += gl + 1; + break; + } + } + filterdata = solv_realloc(filterdata, nfilterdata); + data->filelistfilter[j++] = 0; + data->filelistfilterdata = filterdata; + queue_free(&q); +} + +int +repodata_filelistfilter_matches(Repodata *data, const char *str) +{ + Id *ff; + if (data && !data->filelistfilter) + repodata_set_filelistfilter(data); + if (!data || data->filelistfilter == &default_filelist_filter) + { + /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */ + if (strstr(str, "bin/")) + return 1; + if (!strncmp(str, "/etc/", 5)) + return 1; + if (!strcmp(str, "/usr/lib/sendmail")) + return 1; + return 0; + } + for (ff = data->filelistfilter; *ff; ff += 2) + { + const char *g = data->filelistfilterdata + *ff; + switch (ff[1]) + { + case FF_EXACT: + if (!strcmp(str, g)) + return 1; + break; + case FF_START: + if (!strncmp(str, g, strlen(g))) + return 1; + break; + case FF_SUB: + if (!strstr(str, g)) + return 1; + break; + case FF_START5: + if (!strncmp(str, g, 5)) + return 1; + break; + default: + if (!fnmatch(g, str, 0)) + return 1; + break; + } + } + return 0; +} + diff --git a/libsolv-0.7.2/src/fileprovides.c b/libsolv-0.7.2/src/fileprovides.c new file mode 100644 index 0000000..ec80831 --- /dev/null +++ b/libsolv-0.7.2/src/fileprovides.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2007-2016, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * fileprovides.c + * + * Add missing file dependencies to the package provides + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "bitmap.h" + + +struct searchfiles { + Id *ids; + int nfiles; + Map seen; +}; + +#define SEARCHFILES_BLOCK 127 + +static void +pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) +{ + Id dep, sid; + const char *s; + struct searchfiles *csf; + + while ((dep = *ida++) != 0) + { + csf = sf; + while (ISRELDEP(dep)) + { + Reldep *rd; + sid = pool->ss.nstrings + GETRELID(dep); + if (MAPTST(&csf->seen, sid)) + { + dep = 0; + break; + } + MAPSET(&csf->seen, sid); + rd = GETRELDEP(pool, dep); + if (rd->flags < 8) + dep = rd->name; + else if (rd->flags == REL_NAMESPACE) + { + if (rd->name == NAMESPACE_SPLITPROVIDES) + { + csf = isf; + if (!csf || MAPTST(&csf->seen, sid)) + { + dep = 0; + break; + } + MAPSET(&csf->seen, sid); + } + dep = rd->evr; + } + else if (rd->flags == REL_FILECONFLICT) + { + dep = 0; + break; + } + else + { + Id ids[2]; + ids[0] = rd->name; + ids[1] = 0; + pool_addfileprovides_dep(pool, ids, csf, isf); + dep = rd->evr; + } + } + if (!dep) + continue; + if (MAPTST(&csf->seen, dep)) + continue; + MAPSET(&csf->seen, dep); + s = pool_id2str(pool, dep); + if (*s != '/') + continue; + if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) + continue; /* skip non-standard locations csf == isf: installed case */ + csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); + csf->ids[csf->nfiles++] = dep; + } +} + +struct addfileprovides_cbdata { + int nfiles; + Id *ids; + char **dirs; + char **names; + Id *dids; + + Map *providedids; + int provstart; + int provend; + + Map *todo; + int todo_start; + int todo_end; +}; + +/* split filelist dep into basename and dirname */ +static void +create_dirs_names_array(struct addfileprovides_cbdata *cbd, Pool *pool) +{ + int i; + cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); + cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); + for (i = 0; i < cbd->nfiles; i++) + { + char *s = solv_strdup(pool_id2str(pool, cbd->ids[i])); + cbd->dirs[i] = s; + s = strrchr(s, '/'); + *s = 0; + cbd->names[i] = s + 1; + } +} + +static void +free_dirs_names_array(struct addfileprovides_cbdata *cbd) +{ + int i; + if (cbd->dirs) + { + for (i = 0; i < cbd->nfiles; i++) + solv_free(cbd->dirs[i]); + cbd->dirs = solv_free(cbd->dirs); + cbd->names = solv_free(cbd->names); + } +} + +static void +prune_todo_range(Repo *repo, struct addfileprovides_cbdata *cbd) +{ + int start = cbd->todo_start, end = cbd->todo_end; + while (start < end && !MAPTST(cbd->todo, start - repo->start)) + start++; + while (end > start && !MAPTST(cbd->todo, end - 1 - repo->start)) + end--; + cbd->todo_start = start; + cbd->todo_end = end; +} + +static int +repodata_intersects_todo(Repodata *data, struct addfileprovides_cbdata *cbd) +{ + Repo *repo; + int p, start = data->start, end = data->end; + if (start >= cbd->todo_end || end <= cbd->todo_start) + return 0; + repo = data->repo; + if (start < cbd->todo_start) + start = cbd->todo_start; + if (end > cbd->todo_end) + end = cbd->todo_end; + for (p = start; p < end; p++) + if (MAPTST(cbd->todo, p - repo->start)) + return 1; + return 0; +} + +/* forward declaration */ +static void repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd); + +/* search a subset of the todo range */ +static void +repodata_addfileprovides_search_limited(Repodata *data, struct addfileprovides_cbdata *cbd, int start, int end) +{ + + int old_todo_start = cbd->todo_start; + int old_todo_end = cbd->todo_end; + if (start < cbd->todo_start) + start = cbd->todo_start; + if (end > cbd->todo_end) + end = cbd->todo_end; + if (start >= end) + return; + cbd->todo_start = start; + cbd->todo_end = end; + repodata_addfileprovides_search(data, cbd); + cbd->todo_start = old_todo_start; + cbd->todo_end = old_todo_end; + prune_todo_range(data->repo, cbd); +} + +static void +repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd) +{ + Repo *repo = data->repo; + int i, p, start, end; + Map useddirs; + Map *providedids = 0; + + /* make it available */ + if (data->state == REPODATA_STUB) + repodata_load(data); + if (data->state != REPODATA_AVAILABLE) + return; + if (!data->incoredata || !data->dirpool.ndirs) + return; + + start = cbd->todo_start > data->start ? cbd->todo_start : data->start; + end = cbd->todo_end > data->end ? data->end : cbd->todo_end; + + if (start >= end) + return; + + /* deal with provideids overlap */ + if (cbd->providedids) + { + if (start >= cbd->provstart && end <= cbd->provend) + providedids = cbd->providedids; /* complete overlap */ + else if (start < cbd->provend && end > cbd->provstart) + { + /* partial overlap, need to split search */ + if (start < cbd->provstart) + { + repodata_addfileprovides_search_limited(data, cbd, start, cbd->provstart); + start = cbd->provstart; + } + if (end > cbd->provend) + { + repodata_addfileprovides_search_limited(data, cbd, cbd->provend, end); + end = cbd->provend; + } + if (start < end) + repodata_addfileprovides_search_limited(data, cbd, start, end); + return; + } + } + + /* set up dirs and names array if not already done */ + if (!cbd->dirs) + create_dirs_names_array(cbd, repo->pool); + + /* set up useddirs map and the cbd->dids array */ + map_init(&useddirs, data->dirpool.ndirs); + for (i = 0; i < cbd->nfiles; i++) + { + Id did; + if (providedids && MAPTST(providedids, cbd->ids[i])) + { + cbd->dids[i] = 0; /* already included, do not add again */ + continue; + } + cbd->dids[i] = did = repodata_str2dir(data, cbd->dirs[i], 0); + if (did) + MAPSET(&useddirs, did); + } + repodata_free_dircache(data); /* repodata_str2dir created it */ + + for (p = start; p < end; p++) + { + const unsigned char *dp; + Solvable *s; + if (!MAPTST(cbd->todo, p - repo->start)) + continue; + dp = repodata_lookup_packed_dirstrarray(data, p, SOLVABLE_FILELIST); + if (!dp) + continue; + /* now iterate through the packed array */ + s = repo->pool->solvables + p; + MAPCLR(cbd->todo, p - repo->start); /* this entry is done */ + for (;;) + { + Id did = 0; + int c; + while ((c = *dp++) & 0x80) + did = (did << 7) ^ c ^ 0x80; + did = (did << 6) | (c & 0x3f); + if ((unsigned int)did < (unsigned int)data->dirpool.ndirs && MAPTST(&useddirs, did)) + { + /* there is at least one entry with that did */ + for (i = 0; i < cbd->nfiles; i++) + if (cbd->dids[i] == did && !strcmp(cbd->names[i], (const char *)dp)) + s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); + } + if (!(c & 0x40)) + break; + dp += strlen((const char *)dp) + 1; + } + } + map_free(&useddirs); + prune_todo_range(repo, cbd); +} + +static void +repo_addfileprovides_search_filtered(Repo *repo, struct addfileprovides_cbdata *cbd, int filteredid, Map *postpone) +{ + Repodata *data = repo->repodata + filteredid; + Map *providedids = cbd->providedids; + int rdid; + int start, end, p, i; + Map old_todo; + int old_todo_start, old_todo_end; + + start = cbd->todo_start > data->start ? cbd->todo_start : data->start; + end = cbd->todo_end > data->end ? data->end : cbd->todo_end; + + if (providedids) + { + /* check if all solvables are in the provide range */ + if (start < cbd->provstart || end > cbd->provend) + { + /* unclear, check each solvable */ + for (p = start; p < end; p++) + { + if (p >= cbd->provstart && p < cbd->provend) + continue; + if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start)) + { + providedids = 0; /* nope, cannot prune with providedids */ + break; + } + } + } + } + + /* check if the filtered files are enough */ + for (i = 0; i < cbd->nfiles; i++) + { + if (providedids && MAPTST(providedids, cbd->ids[i])) /* this one is already provided */ + continue; + if (!repodata_filelistfilter_matches(data, pool_id2str(repo->pool, cbd->ids[i]))) + break; + } + if (i < cbd->nfiles) + { + /* nope, need to search the extensions as well. postpone. */ + for (p = start; p < end; p++) + { + if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start)) + { + if (!postpone->size) + map_grow(postpone, repo->nsolvables); + MAPSET(postpone, p - repo->start); + MAPCLR(cbd->todo, p - repo->start); + } + } + prune_todo_range(repo, cbd); + return; + } + + /* now check if there is no data marked withour EXTENSION */ + /* limit todo to the solvables in this repodata */ + old_todo_start = cbd->todo_start; + old_todo_end = cbd->todo_end; + old_todo = *cbd->todo; + map_init(cbd->todo, repo->nsolvables); + for (p = start; p < end; p++) + if (data->incoreoffset[p - data->start] && MAPTST(&old_todo, p - repo->start)) + { + MAPCLR(&old_todo, p - repo->start); + MAPSET(cbd->todo, p - repo->start); + } + prune_todo_range(repo, cbd); + + /* do the check */ + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > filteredid ; rdid--, data--) + { + if (data->filelisttype == REPODATA_FILELIST_EXTENSION) + continue; + if (data->start >= cbd->todo_end || data->end <= cbd->todo_start) + continue; + if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) + continue; + if (!repodata_intersects_todo(data, cbd)) + continue; + /* oh no, this filelist data is not tagged with REPODATA_FILELIST_EXTENSION! */ + /* postpone entries that have filelist data */ + start = cbd->todo_start > data->start ? cbd->todo_start : data->start; + end = cbd->todo_end > data->end ? data->end : cbd->todo_end; + for (p = start; p < end; p++) + if (MAPTST(cbd->todo, p - repo->start)) + if (repodata_lookup_type(data, p, SOLVABLE_FILELIST)) + { + if (!postpone->size) + map_grow(postpone, repo->nsolvables); + MAPSET(postpone, p - repo->start); + MAPCLR(cbd->todo, p - repo->start); + } + prune_todo_range(repo, cbd); + if (cbd->todo_start >= cbd->todo_end) + break; + } + + /* do the search over the filtered file list with the remaining entries*/ + if (cbd->todo_start < cbd->todo_end) + repodata_addfileprovides_search(repo->repodata + filteredid, cbd); + + /* restore todo map */ + map_free(cbd->todo); + *cbd->todo = old_todo; + cbd->todo_start = old_todo_start; + cbd->todo_end = old_todo_end; + prune_todo_range(repo, cbd); +} + +static void +repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf) +{ + Repodata *data; + int rdid, p, i; + int provstart, provend; + Map todo; + Map providedids; + + if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles) + return; + + /* update search data if changed */ + if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids) + { + free_dirs_names_array(cbd); + cbd->nfiles = sf->nfiles; + cbd->ids = sf->ids; + cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); + } + + /* create todo map and range */ + map_init(&todo, repo->end - repo->start); + for (p = repo->start; p < repo->end; p++) + if (repo->pool->solvables[p].repo == repo) + MAPSET(&todo, p - repo->start); + cbd->todo = &todo; + cbd->todo_start = repo->start; + cbd->todo_end = repo->end; + prune_todo_range(repo, cbd); + + provstart = provend = 0; + map_init(&providedids, 0); + data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES); + if (data) + { + Queue fileprovidesq; + queue_init(&fileprovidesq); + if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) + { + map_grow(&providedids, repo->pool->ss.nstrings); + cbd->providedids = &providedids; + provstart = data->start; + provend = data->end; + for (i = 0; i < fileprovidesq.count; i++) + MAPSET(&providedids, fileprovidesq.elements[i]); + for (i = 0; i < cbd->nfiles; i++) + if (!MAPTST(&providedids, cbd->ids[i])) + break; + if (i == cbd->nfiles) + { + /* all included, clear entries from todo list */ + if (provstart <= cbd->todo_start && provend >= cbd->todo_end) + cbd->todo_end = cbd->todo_start; /* clear complete range */ + else + { + for (p = provstart; p < provend; p++) + MAPCLR(&todo, p - repo->start); + prune_todo_range(repo, cbd); + } + } + } + queue_free(&fileprovidesq); + } + + if (cbd->todo_start >= cbd->todo_end) + { + map_free(&todo); + cbd->todo = 0; + map_free(&providedids); + cbd->providedids = 0; + return; + } + + /* this is similar to repo_lookup_filelist_repodata in repo.c */ + + for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++) + if (data->filelisttype == REPODATA_FILELIST_FILTERED) + break; + for (; rdid < repo->nrepodata; rdid++, data++) + if (data->filelisttype == REPODATA_FILELIST_EXTENSION) + break; + + if (rdid < repo->nrepodata) + { + /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */ + Map postpone; + map_init(&postpone, 0); + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) + { + if (data->filelisttype != REPODATA_FILELIST_FILTERED) + continue; + if (!repodata_intersects_todo(data, cbd)) + continue; + if (data->state != REPODATA_AVAILABLE) + { + if (data->state != REPODATA_STUB) + continue; + repodata_load(data); + if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED) + continue; + } + repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone); + } + if (postpone.size) + { + /* add postponed entries back to todo */ + map_or(&todo, &postpone); + cbd->todo_start = repo->start; + cbd->todo_end = repo->end; + prune_todo_range(repo, cbd); + } + map_free(&postpone); + } + + /* search remaining entries in the standard way */ + if (cbd->todo_start < cbd->todo_end) + { + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) + { + if (data->start >= cbd->todo_end || data->end <= cbd->todo_start) + continue; + if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) + continue; + if (!repodata_intersects_todo(data, cbd)) + continue; + repodata_addfileprovides_search(data, cbd); + if (cbd->todo_start >= cbd->todo_end) + break; + } + } + + map_free(&todo); + cbd->todo = 0; + map_free(&providedids); + cbd->providedids = 0; +} + +void +pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) +{ + Solvable *s; + Repo *installed, *repo; + struct searchfiles sf, isf, *isfp; + struct addfileprovides_cbdata cbd; + int i; + unsigned int now; + + installed = pool->installed; + now = solv_timems(0); + memset(&cbd, 0, sizeof(cbd)); + memset(&sf, 0, sizeof(sf)); + map_init(&sf.seen, pool->ss.nstrings + pool->nrels); + memset(&isf, 0, sizeof(isf)); + map_init(&isf.seen, pool->ss.nstrings + pool->nrels); + pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; + + if (idq) + queue_empty(idq); + if (idqinst) + queue_empty(idqinst); + isfp = installed ? &isf : 0; + for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) + { + repo = s->repo; + if (!repo) + continue; + if (s->obsoletes) + pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); + if (s->conflicts) + pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); + if (s->requires) + pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); + if (s->recommends) + pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); + if (s->suggests) + pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); + if (s->supplements) + pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); + if (s->enhances) + pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); + } + + map_free(&sf.seen); + map_free(&isf.seen); + POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); + if (sf.nfiles) + { +#if 0 + for (i = 0; i < sf.nfiles; i++) + POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); +#endif + FOR_REPOS(i, repo) + repo_addfileprovides_search(repo, &cbd, &sf); + if (idq) + queue_insertn(idq, idq->count, sf.nfiles, sf.ids); + if (idqinst) + queue_insertn(idqinst, idqinst->count, sf.nfiles, sf.ids); + solv_free(sf.ids); + } + if (isf.nfiles) + { +#if 0 + for (i = 0; i < isf.nfiles; i++) + POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); +#endif + if (installed) + repo_addfileprovides_search(installed, &cbd, &isf); + if (installed && idqinst) + for (i = 0; i < isf.nfiles; i++) + queue_pushunique(idqinst, isf.ids[i]); + solv_free(isf.ids); + } + free_dirs_names_array(&cbd); + solv_free(cbd.dids); + pool_freewhatprovides(pool); /* as we have added provides */ + POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); +} + +void +pool_addfileprovides(Pool *pool) +{ + pool_addfileprovides_queue(pool, 0, 0); +} + diff --git a/libsolv-0.6.15/src/hash.h b/libsolv-0.7.2/src/hash.h similarity index 100% rename from libsolv-0.6.15/src/hash.h rename to libsolv-0.7.2/src/hash.h diff --git a/libsolv-0.6.15/src/knownid.h b/libsolv-0.7.2/src/knownid.h similarity index 91% rename from libsolv-0.6.15/src/knownid.h rename to libsolv-0.7.2/src/knownid.h index c094bf5..8e53183 100644 --- a/libsolv-0.6.15/src/knownid.h +++ b/libsolv-0.7.2/src/knownid.h @@ -76,18 +76,12 @@ KNOWNID(REPOSITORY_EXTERNAL, "repository:external"), KNOWNID(REPOSITORY_KEYS, "repository:keys"), KNOWNID(REPOSITORY_LOCATION, "repository:location"), -/* file provides already added to our solvables */ -KNOWNID(REPOSITORY_ADDEDFILEPROVIDES, "repository:addedfileprovides"), -/* inode of the rpm database for rpm --rebuilddb detection */ -KNOWNID(REPOSITORY_RPMDBCOOKIE, "repository:rpmdbcookie"), - /* the known data types */ KNOWNID(REPOKEY_TYPE_VOID, "repokey:type:void"), KNOWNID(REPOKEY_TYPE_CONSTANT, "repokey:type:constant"), KNOWNID(REPOKEY_TYPE_CONSTANTID, "repokey:type:constantid"), KNOWNID(REPOKEY_TYPE_ID, "repokey:type:id"), KNOWNID(REPOKEY_TYPE_NUM, "repokey:type:num"), -KNOWNID(REPOKEY_TYPE_U32, "repokey:type:num32"), KNOWNID(REPOKEY_TYPE_DIR, "repokey:type:dir"), KNOWNID(REPOKEY_TYPE_STR, "repokey:type:str"), KNOWNID(REPOKEY_TYPE_BINARY, "repokey:type:binary"), @@ -145,6 +139,8 @@ KNOWNID(SOLVABLE_CHANGELOG, "solvable:changelog"), KNOWNID(SOLVABLE_CHANGELOG_AUTHOR, "solvable:changelog:author"), KNOWNID(SOLVABLE_CHANGELOG_TIME, "solvable:changelog:time"), KNOWNID(SOLVABLE_CHANGELOG_TEXT, "solvable:changelog:text"), +KNOWNID(SOLVABLE_INSTALLSTATUS, "solvable:installstatus"), /* debian install status */ +KNOWNID(SOLVABLE_PREREQ_IGNOREINST, "solvable:prereq_ignoreinst"), /* ignore these pre-requires for installed packages */ /* stuff for solvables of type pattern */ KNOWNID(SOLVABLE_CATEGORY, "solvable:category"), @@ -187,6 +183,7 @@ KNOWNID(PRODUCT_URL_TYPE, "product:url:type"), KNOWNID(PRODUCT_FLAGS, "product:flags"), /* e.g. 'update', 'no_you' */ KNOWNID(PRODUCT_PRODUCTLINE, "product:productline"), /* installed product only */ KNOWNID(PRODUCT_REGISTER_TARGET, "product:regtarget"), /* installed and available product */ +KNOWNID(PRODUCT_REGISTER_FLAVOR, "product:regflavor"), /* installed and available product */ KNOWNID(PRODUCT_REGISTER_RELEASE, "product:regrelease"), /* installed product only */ KNOWNID(PRODUCT_UPDATES_REPOID, "product:updates:repoid"), KNOWNID(PRODUCT_UPDATES, "product:updates"), @@ -204,21 +201,18 @@ KNOWNID(SUSETAGS_SHARE_NAME, "susetags:share:name"), KNOWNID(SUSETAGS_SHARE_EVR, "susetags:share:evr"), KNOWNID(SUSETAGS_SHARE_ARCH, "susetags:share:arch"), -/* timestamp then the repository was generated */ -KNOWNID(REPOSITORY_TIMESTAMP, "repository:timestamp"), -/* hint when the metadata could be outdated w/respect to generated timestamp */ -KNOWNID(REPOSITORY_EXPIRE, "repository:expire"), -/* which things does this repo provides updates for, if it does (array) */ -KNOWNID(REPOSITORY_UPDATES, "repository:updates"), /* obsolete? */ -/* which products this repository is supposed to be for (array) */ -KNOWNID(REPOSITORY_DISTROS, "repository:distros"), +KNOWNID(REPOSITORY_ADDEDFILEPROVIDES, "repository:addedfileprovides"), /* file provides already added to our solvables */ +KNOWNID(REPOSITORY_RPMDBCOOKIE, "repository:rpmdbcookie"), /* inode of the rpm database for rpm --rebuilddb detection */ +KNOWNID(REPOSITORY_FILTEREDFILELIST, "repository:filteredfilelist"), /* filelist in repository is filtered */ +KNOWNID(REPOSITORY_TIMESTAMP, "repository:timestamp"), /* timestamp then the repository was generated */ +KNOWNID(REPOSITORY_EXPIRE, "repository:expire"), /* hint when the metadata could be outdated w/respect to generated timestamp */ +KNOWNID(REPOSITORY_UPDATES, "repository:updates"), /* which things does this repo provides updates for, if it does (array) (obsolete?) */ +KNOWNID(REPOSITORY_DISTROS, "repository:distros"), /* which products this repository is supposed to be for (array) */ KNOWNID(REPOSITORY_PRODUCT_LABEL, "repository:product:label"), KNOWNID(REPOSITORY_PRODUCT_CPEID, "repository:product:cpeid"), KNOWNID(REPOSITORY_REPOID, "repository:repoid"), /* obsolete? */ -/* keyword (tags) for this repository */ -KNOWNID(REPOSITORY_KEYWORDS, "repository:keywords"), -/* revision of the repository. arbitrary string */ -KNOWNID(REPOSITORY_REVISION, "repository:revision"), +KNOWNID(REPOSITORY_KEYWORDS, "repository:keywords"), /* keyword (tags) for this repository */ +KNOWNID(REPOSITORY_REVISION, "repository:revision"), /* revision of the repository. arbitrary string */ KNOWNID(REPOSITORY_TOOLVERSION, "repository:toolversion"), KNOWNID(DELTA_PACKAGE_NAME, "delta:pkgname"), @@ -256,10 +250,6 @@ KNOWNID(SIGNATURE_TIME, "signature:time"), KNOWNID(SIGNATURE_EXPIRES, "signature:expires"), KNOWNID(SIGNATURE_DATA, "signature:data"), -KNOWNID(PRODUCT_REGISTER_FLAVOR, "product:regflavor"), /* installed and available product */ - -KNOWNID(SOLVABLE_INSTALLSTATUS, "solvable:installstatus"), /* debian install status */ - KNOWNID(ID_NUM_INTERNAL, 0) #ifdef KNOWNID_INITIALIZE diff --git a/libsolv-0.6.15/src/libsolv.ver b/libsolv-0.7.2/src/libsolv.ver similarity index 92% rename from libsolv-0.6.15/src/libsolv.ver rename to libsolv-0.7.2/src/libsolv.ver index 6508288..f0e86ff 100644 --- a/libsolv-0.6.15/src/libsolv.ver +++ b/libsolv-0.7.2/src/libsolv.ver @@ -120,6 +120,8 @@ SOLV_1.0 { pool_trivial_installable_multiversionmap; pool_vendor2mask; pool_whatmatchesdep; + pool_whatmatchessolvable; + pool_whatcontainsdep; queue_alloc_one; queue_alloc_one_head; queue_delete; @@ -144,6 +146,7 @@ SOLV_1.0 { repo_addid; repo_addid_dep; repo_create; + repo_create_keyskip; repo_disable_paging; repo_empty; repo_fix_conflicts; @@ -164,8 +167,8 @@ SOLV_1.0 { repo_lookup_str; repo_lookup_type; repo_lookup_void; - repo_matchvalue; repo_reserve_ids; + repo_rewrite_suse_deps; repo_search; repo_set_deparray; repo_set_id; @@ -202,10 +205,9 @@ SOLV_1.0 { repodata_localize_id; repodata_lookup_bin_checksum; repodata_lookup_binary; - repodata_lookup_dirstrarray_uninternalized; repodata_lookup_id; - repodata_lookup_id_uninternalized; repodata_lookup_idarray; + repodata_lookup_kv_uninternalized; repodata_lookup_num; repodata_lookup_str; repodata_lookup_type; @@ -216,12 +218,16 @@ SOLV_1.0 { repodata_new_handle; repodata_schema2id; repodata_search; + repodata_search_arrayelement; + repodata_search_keyskip; + repodata_search_uninternalized; repodata_set_binary; repodata_set_bin_checksum; repodata_set_checksum; repodata_set_constant; repodata_set_constantid; repodata_set_deltalocation; + repodata_set_filelisttype; repodata_set_id; repodata_set_idarray; repodata_set_location; @@ -235,16 +241,28 @@ SOLV_1.0 { repodata_str2dir; repodata_stringify; repodata_swap_attrs; + repodata_translate_dir_slow; repodata_translate_id; repodata_unset; repodata_unset_uninternalized; repodata_write; repodata_write_filtered; repopagestore_compress_page; + repowriter_create; + repowriter_free; + repowriter_set_flags; + repowriter_set_keyfilter; + repowriter_set_keyqueue; + repowriter_set_repodatarange; + repowriter_set_solvablerange; + repowriter_write; selection_add; selection_filter; selection_make; + selection_make_matchdepid; selection_make_matchdeps; + selection_make_matchsolvable; + selection_make_matchsolvablelist; selection_solvables; solv_bin2hex; solv_calloc; @@ -306,6 +324,7 @@ SOLV_1.0 { solvable_lookup_str_poollang; solvable_lookup_type; solvable_lookup_void; + solvable_matchesdep; solvable_selfprovidedep; solvable_set_deparray; solvable_set_id; @@ -329,8 +348,6 @@ SOLV_1.0 { solver_create_transaction; solver_describe_decision; solver_describe_weakdep_decision; - solver_disableproblem; - solver_enableproblem; solver_findallproblemrules; solver_findproblemrule; solver_free; @@ -417,3 +434,18 @@ SOLV_1.0 { local: *; }; + +SOLV_1.1 { + pool_best_solvables; + solver_get_cleandeps; +} SOLV_1.0; + +SOLV_1.2 { + map_invertall; + pool_set_whatprovides; + selection_subtract; +} SOLV_1.1; + +SOLV_1.3 { + repodata_set_kv; +} SOLV_1.2; diff --git a/libsolv-0.6.15/src/linkedpkg.c b/libsolv-0.7.2/src/linkedpkg.c similarity index 88% rename from libsolv-0.6.15/src/linkedpkg.c rename to libsolv-0.7.2/src/linkedpkg.c index 6387373..5912f98 100644 --- a/libsolv-0.6.15/src/linkedpkg.c +++ b/libsolv-0.7.2/src/linkedpkg.c @@ -37,7 +37,9 @@ #include "pool.h" #include "repo.h" +#include "solver.h" #include "evr.h" +#include "bitmap.h" #include "linkedpkg.h" #ifdef ENABLE_LINKED_PKGS @@ -190,16 +192,25 @@ find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Qu /* oh no! Look up reference file */ Dataiterator di; const char *refbasename = solvable_lookup_str(s, PRODUCT_REFERENCEFILE); - dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING); - while (dataiterator_step(&di)) - queue_push(qr, di.solvid); - dataiterator_free(&di); - if (qp) + if (refbasename) { - dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING); + dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING); while (dataiterator_step(&di)) - queue_push(qp, di.solvid); + { + if (di.key->type != REPOKEY_TYPE_DIRSTRARRAY) + continue; + if (strcmp(repodata_dir2str(di.data, di.kv.id, 0), "/etc/products.d") != 0) + continue; + queue_push(qr, di.solvid); + } dataiterator_free(&di); + if (qp) + { + dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING); + while (dataiterator_step(&di)) + queue_push(qp, di.solvid); + dataiterator_free(&di); + } } } else if (qp) @@ -377,5 +388,30 @@ pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2) return 0; } +void +extend_updatemap_to_buddies(Solver *solv) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Solvable *s; + int p, ip; + + if (!installed) + return; + if (!solv->updatemap.size || !solv->instbuddy) + return; + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!MAPTST(&solv->updatemap, p - installed->start)) + continue; + if ((ip = solv->instbuddy[p - installed->start]) <= 1) + continue; + if (!has_package_link(pool, s)) /* only look at pseudo -> real relations */ + continue; + if (ip < installed->start || ip >= installed->end || pool->solvables[ip].repo != installed) + continue; /* just in case... */ + MAPSET(&solv->updatemap, ip - installed->start); + } +} #endif diff --git a/libsolv-0.6.15/src/linkedpkg.h b/libsolv-0.7.2/src/linkedpkg.h similarity index 91% rename from libsolv-0.6.15/src/linkedpkg.h rename to libsolv-0.7.2/src/linkedpkg.h index 4463280..51b82a5 100644 --- a/libsolv-0.6.15/src/linkedpkg.h +++ b/libsolv-0.7.2/src/linkedpkg.h @@ -18,7 +18,7 @@ has_package_link(Pool *pool, Solvable *s) const char *name = pool_id2str(pool, s->name); if (name[0] == 'a' && !strncmp("application:", name, 12)) return 1; - if (name[0] == 'p' && !strncmp("pattern:", name, 7)) + if (name[0] == 'p' && !strncmp("pattern:", name, 8)) return 1; if (name[0] == 'p' && !strncmp("product:", name, 8)) return 1; @@ -35,5 +35,6 @@ extern Id find_autoproduct_name(Pool *pool, Solvable *s); /* generic */ extern void find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp); extern int pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2); +extern void extend_updatemap_to_buddies(Solver *solv); #endif diff --git a/libsolv-0.6.15/src/md5.c b/libsolv-0.7.2/src/md5.c similarity index 100% rename from libsolv-0.6.15/src/md5.c rename to libsolv-0.7.2/src/md5.c diff --git a/libsolv-0.6.15/src/md5.h b/libsolv-0.7.2/src/md5.h similarity index 100% rename from libsolv-0.6.15/src/md5.h rename to libsolv-0.7.2/src/md5.h diff --git a/libsolv-0.6.15/src/order.c b/libsolv-0.7.2/src/order.c similarity index 88% rename from libsolv-0.6.15/src/order.c rename to libsolv-0.7.2/src/order.c index d560865..c0cc07f 100644 --- a/libsolv-0.6.15/src/order.c +++ b/libsolv-0.7.2/src/order.c @@ -23,14 +23,14 @@ #include "repo.h" #include "util.h" -struct _TransactionElement { +struct s_TransactionElement { Id p; /* solvable id */ Id edges; /* pointer into edges data */ Id mark; }; -struct _TransactionOrderdata { - struct _TransactionElement *tes; +struct s_TransactionOrderdata { + struct s_TransactionElement *tes; int ntes; Id *invedgedata; int ninvedgedata; @@ -43,8 +43,11 @@ struct _TransactionOrderdata { #define TYPE_REQ_P (1<<2) #define TYPE_PREREQ_P (1<<3) -#define TYPE_REQ (1<<4) -#define TYPE_PREREQ (1<<5) +#define TYPE_SUG (1<<4) +#define TYPE_REC (1<<5) + +#define TYPE_REQ (1<<6) +#define TYPE_PREREQ (1<<7) #define TYPE_CYCLETAIL (1<<16) #define TYPE_CYCLEHEAD (1<<17) @@ -54,7 +57,7 @@ struct _TransactionOrderdata { void transaction_clone_orderdata(Transaction *trans, Transaction *srctrans) { - struct _TransactionOrderdata *od = srctrans->orderdata; + struct s_TransactionOrderdata *od = srctrans->orderdata; if (!od) return; trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata)); @@ -74,7 +77,7 @@ transaction_free_orderdata(Transaction *trans) { if (trans->orderdata) { - struct _TransactionOrderdata *od = trans->orderdata; + struct s_TransactionOrderdata *od = trans->orderdata; od->tes = solv_free(od->tes); od->invedgedata = solv_free(od->invedgedata); if (od->cycles) @@ -88,7 +91,7 @@ transaction_free_orderdata(Transaction *trans) struct orderdata { Transaction *trans; - struct _TransactionElement *tes; + struct s_TransactionElement *tes; int ntes; Id *edgedata; int nedgedata; @@ -103,7 +106,7 @@ static int addteedge(struct orderdata *od, int from, int to, int type) { int i; - struct _TransactionElement *te; + struct s_TransactionElement *te; if (from == to) return 0; @@ -151,7 +154,7 @@ addedge(struct orderdata *od, Id from, Id to, int type) Transaction *trans = od->trans; Pool *pool = trans->pool; Solvable *s; - struct _TransactionElement *te; + struct s_TransactionElement *te; int i; /* printf("addedge %d %d type %d\n", from, to, type); */ @@ -245,21 +248,21 @@ addsolvableedges(struct orderdata *od, Solvable *s) { Transaction *trans = od->trans; Pool *pool = trans->pool; - Id req, *reqp, con, *conp; Id p, p2, pp2; int i, j, pre, numins; Repo *installed = pool->installed; Solvable *s2; - Queue reqq; + Queue depq; int provbyinst; #if 0 printf("addsolvableedges %s\n", pool_solvable2str(pool, s)); #endif p = s - pool->solvables; - queue_init(&reqq); + queue_init(&depq); if (s->requires) { + Id req, *reqp; reqp = s->repo->idarraydata + s->requires; pre = TYPE_REQ; while ((req = *reqp++) != 0) @@ -269,15 +272,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) pre = TYPE_PREREQ; continue; } -#if 0 - if (pre != TYPE_PREREQ && installed && s->repo == installed) - { - /* ignore normal requires if we're getting obsoleted */ - if (trans->transaction_installed[p - pool->installed->start]) - continue; - } -#endif - queue_empty(&reqq); + queue_empty(&depq); numins = 0; /* number of packages to be installed providing it */ provbyinst = 0; /* provided by kept package */ FOR_PROVIDES(p2, pp2, req) @@ -285,19 +280,13 @@ addsolvableedges(struct orderdata *od, Solvable *s) s2 = pool->solvables + p2; if (p2 == p) { - reqq.count = 0; /* self provides */ + depq.count = 0; /* self provides */ break; } if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2)) { provbyinst = 1; -#if 0 - printf("IGNORE inst provides %s by %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s2)); - reqq.count = 0; /* provided by package that stays installed */ - break; -#else continue; -#endif } if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2)) continue; /* package stays uninstalled */ @@ -305,7 +294,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) if (s->repo == installed) { /* s gets uninstalled */ - queue_pushunique(&reqq, p2); + queue_pushunique(&depq, p2); if (s2->repo != installed) numins++; } @@ -313,55 +302,53 @@ addsolvableedges(struct orderdata *od, Solvable *s) { if (s2->repo == installed) continue; /* s2 gets uninstalled */ - queue_pushunique(&reqq, p2); + queue_pushunique(&depq, p2); } } if (provbyinst) { /* prune to harmless ->inst edges */ - for (i = j = 0; i < reqq.count; i++) - if (pool->solvables[reqq.elements[i]].repo != installed) - reqq.elements[j++] = reqq.elements[i]; - reqq.count = j; + for (i = j = 0; i < depq.count; i++) + if (pool->solvables[depq.elements[i]].repo != installed) + depq.elements[j++] = depq.elements[i]; + depq.count = j; } - if (numins && reqq.count) + if (numins && depq.count) { if (s->repo == installed) { - for (i = 0; i < reqq.count; i++) + for (i = 0; i < depq.count; i++) { - if (pool->solvables[reqq.elements[i]].repo == installed) + if (pool->solvables[depq.elements[i]].repo == installed) { - for (j = 0; j < reqq.count; j++) + for (j = 0; j < depq.count; j++) { - if (pool->solvables[reqq.elements[j]].repo != installed) + if (pool->solvables[depq.elements[j]].repo != installed) { - if (trans->transaction_installed[reqq.elements[i] - pool->installed->start] == reqq.elements[j]) + if (trans->transaction_installed[depq.elements[i] - pool->installed->start] == depq.elements[j]) continue; /* no self edge */ #if 0 - printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, reqq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, reqq.elements[j])); + printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, depq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, depq.elements[j])); #endif - addedge(od, reqq.elements[i], reqq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P); + addedge(od, depq.elements[i], depq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P); } } } } } /* no mixed types, remove all deps on uninstalls */ - for (i = j = 0; i < reqq.count; i++) - if (pool->solvables[reqq.elements[i]].repo != installed) - reqq.elements[j++] = reqq.elements[i]; - reqq.count = j; + for (i = j = 0; i < depq.count; i++) + if (pool->solvables[depq.elements[i]].repo != installed) + depq.elements[j++] = depq.elements[i]; + depq.count = j; } - if (!reqq.count) - continue; - for (i = 0; i < reqq.count; i++) + for (i = 0; i < depq.count; i++) { - p2 = reqq.elements[i]; + p2 = depq.elements[i]; if (pool->solvables[p2].repo != installed) { - /* all elements of reqq are installs, thus have different TEs */ + /* all elements of depq are installs, thus have different TEs */ if (pool->solvables[p].repo != installed) { #if 0 @@ -399,6 +386,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) } if (s->conflicts) { + Id con, *conp; conp = s->repo->idarraydata + s->conflicts; while ((con = *conp++) != 0) { @@ -435,13 +423,83 @@ addsolvableedges(struct orderdata *od, Solvable *s) } } } - if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &reqq) && reqq.count) + if (s->recommends && s->repo != installed) + { + Id rec, *recp; + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + queue_empty(&depq); + FOR_PROVIDES(p2, pp2, rec) + { + s2 = pool->solvables + p2; + if (p2 == p) + { + depq.count = 0; /* self provides */ + break; + } + if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2)) + continue; + if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2)) + continue; /* package stays uninstalled */ + if (s2->repo != installed) + queue_pushunique(&depq, p2); + } + for (i = 0; i < depq.count; i++) + { + p2 = depq.elements[i]; + if (pool->solvables[p2].repo != installed) + { +#if 0 + printf("add recommends inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, rec), pool_solvid2str(pool, p2)); +#endif + addedge(od, p, p2, TYPE_REC); + } + } + } + } + if (s->suggests && s->repo != installed) + { + Id sug, *sugp; + sugp = s->repo->idarraydata + s->suggests; + while ((sug = *sugp++) != 0) + { + queue_empty(&depq); + FOR_PROVIDES(p2, pp2, sug) + { + s2 = pool->solvables + p2; + if (p2 == p) + { + depq.count = 0; /* self provides */ + break; + } + if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2)) + continue; + if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2)) + continue; /* package stays uninstalled */ + if (s2->repo != installed) + queue_pushunique(&depq, p2); + } + for (i = 0; i < depq.count; i++) + { + p2 = depq.elements[i]; + if (pool->solvables[p2].repo != installed) + { +#if 0 + printf("add suggests inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, sug), pool_solvid2str(pool, p2)); +#endif + addedge(od, p, p2, TYPE_SUG); + } + } + } + } + if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &depq) && depq.count) { /* we're getting deinstalled/updated. Try to do this before our * triggers are hit */ - for (i = 0; i < reqq.count; i++) + for (i = 0; i < depq.count; i++) { - Id tri = reqq.elements[i]; + Id tri = depq.elements[i]; FOR_PROVIDES(p2, pp2, tri) { if (p2 == p) @@ -462,7 +520,7 @@ addsolvableedges(struct orderdata *od, Solvable *s) } } } - queue_free(&reqq); + queue_free(&depq); } @@ -473,7 +531,7 @@ breakcycle(struct orderdata *od, Id *cycle) Pool *pool = od->trans->pool; Id ddegmin, ddegmax, ddeg; int k, l; - struct _TransactionElement *te; + struct s_TransactionElement *te; l = 0; ddegmin = ddegmax = 0; @@ -546,7 +604,7 @@ dump_tes(struct orderdata *od) Pool *pool = od->trans->pool; int i, j; Queue obsq; - struct _TransactionElement *te, *te2; + struct s_TransactionElement *te, *te2; queue_init(&obsq); for (i = 1, te = od->tes + i; i < od->ntes; i++, te++) @@ -574,7 +632,7 @@ dump_tes(struct orderdata *od) static void reachable(struct orderdata *od, Id i) { - struct _TransactionElement *te = od->tes + i; + struct s_TransactionElement *te = od->tes + i; int j, k; if (te->mark != 0) @@ -602,7 +660,7 @@ addcycleedges(struct orderdata *od, Id *cycle, Queue *todo) Transaction *trans = od->trans; Pool *pool = trans->pool; #endif - struct _TransactionElement *te; + struct s_TransactionElement *te; int i, j, k, tail; int head; @@ -722,7 +780,7 @@ transaction_order(Transaction *trans, int flags) Solvable *s; int i, j, k, numte, numedge; struct orderdata od; - struct _TransactionElement *te; + struct s_TransactionElement *te; Queue todo, obsq, samerepoq, uninstq; int cycstart, cycel; Id *cycle; @@ -737,7 +795,7 @@ transaction_order(Transaction *trans, int flags) /* free old data if present */ if (trans->orderdata) { - struct _TransactionOrderdata *od = trans->orderdata; + struct s_TransactionOrderdata *od = trans->orderdata; od->tes = solv_free(od->tes); od->invedgedata = solv_free(od->invedgedata); trans->orderdata = solv_free(trans->orderdata); @@ -1011,7 +1069,7 @@ printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]); s = pool->solvables + te->p; for (j = te->edges; od.invedgedata[j]; j++) { - struct _TransactionElement *te2 = od.tes + od.invedgedata[j]; + struct s_TransactionElement *te2 = od.tes + od.invedgedata[j]; assert(te2->mark > 0); if (--te2->mark == 0) { @@ -1045,7 +1103,7 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES)) != 0) { - struct _TransactionOrderdata *tod; + struct s_TransactionOrderdata *tod; trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata)); if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES) != 0) { @@ -1079,8 +1137,8 @@ int transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices) { int i, j; - struct _TransactionOrderdata *od = trans->orderdata; - struct _TransactionElement *te; + struct s_TransactionOrderdata *od = trans->orderdata; + struct s_TransactionElement *te; if (!od) return choices->count; @@ -1262,8 +1320,10 @@ transaction_check_order(Transaction *trans) map_init(&ins, pool->nsolvables); map_init(&seen, pool->nsolvables); if (pool->installed) - FOR_REPO_SOLVABLES(pool->installed, p, s) - MAPSET(&ins, p); + { + FOR_REPO_SOLVABLES(pool->installed, p, s) + MAPSET(&ins, p); + } lastins = 0; for (i = 0; i < trans->steps.count; i++) { @@ -1289,7 +1349,7 @@ transaction_check_order(Transaction *trans) void transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity) { - struct _TransactionOrderdata *od = trans->orderdata; + struct s_TransactionOrderdata *od = trans->orderdata; Queue *cq; int i, cid, ncycles; @@ -1317,7 +1377,7 @@ transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity) int transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q) { - struct _TransactionOrderdata *od = trans->orderdata; + struct s_TransactionOrderdata *od = trans->orderdata; Queue *cq; int cmin, cmax, severity; int ncycles; diff --git a/libsolv-0.6.15/src/policy.c b/libsolv-0.7.2/src/policy.c similarity index 84% rename from libsolv-0.6.15/src/policy.c rename to libsolv-0.7.2/src/policy.c index 12ad771..191327a 100644 --- a/libsolv-0.6.15/src/policy.c +++ b/libsolv-0.7.2/src/policy.c @@ -56,11 +56,11 @@ prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp) } if (sa->arch != sb->arch) { - int aa, ab; - aa = (sa->arch <= pool->lastarch) ? pool->id2arch[sa->arch] : 0; - ab = (sb->arch <= pool->lastarch) ? pool->id2arch[sb->arch] : 0; + unsigned int aa, ab; + aa = pool_arch2score(pool, sa->arch); + ab = pool_arch2score(pool, sb->arch); if (aa != ab && aa > 1 && ab > 1) - return aa - ab; /* lowest score first */ + return aa < ab ? -1 : 1; /* lowest score first */ } /* the same name, bring installed solvables to the front */ @@ -145,7 +145,7 @@ solver_prune_installed_dup_packages(Solver *solv, Queue *plist) Solvable *s = pool->solvables + p; if (s->repo != pool->installed && s->repo->priority < bestprio) continue; - if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))) + if (s->repo == pool->installed && (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))) { Id p2, pp2; int keepit = 0; @@ -181,7 +181,7 @@ static inline void solver_prune_to_highest_prio(Solver *solv, Queue *plist) { prune_to_highest_prio(solv->pool, plist); - if (plist->count > 1 && solv->pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size)) + if (plist->count > 1 && solv->pool->installed && (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size)) solver_prune_installed_dup_packages(solv, plist); } @@ -202,14 +202,14 @@ solver_prune_to_highest_prio_per_name(Solver *solv, Queue *plist) { if (pool->solvables[plist->elements[i]].name != name) { + name = pool->solvables[plist->elements[i]].name; if (pq.count > 2) solver_prune_to_highest_prio(solv, &pq); for (k = 0; k < pq.count; k++) plist->elements[j++] = pq.elements[k]; queue_empty(&pq); - queue_push(&pq, plist->elements[i]); - name = pool->solvables[pq.elements[0]].name; } + queue_push(&pq, plist->elements[i]); } if (pq.count > 2) solver_prune_to_highest_prio(solv, &pq); @@ -453,6 +453,89 @@ prefer_suggested(Solver *solv, Queue *plist) } } +static int +sort_by_favorq_cmp(const void *ap, const void *bp, void *dp) +{ + const Id *a = ap, *b = bp, *d = dp; + return d[b[0]] - d[a[0]]; +} + +static void +sort_by_favorq(Queue *favorq, Id *el, int cnt) +{ + int i; + /* map to offsets into favorq */ + for (i = 0; i < cnt; i++) + { + Id p = el[i]; + /* lookup p in sorted favorq */ + int med = 0, low = 0; + int high = favorq->count / 2; + while (low != high) + { + med = (low + high) / 2; + Id pp = favorq->elements[2 * med]; + if (pp < p) + low = med; + else if (pp > p) + high = med; + else + break; + } + while(med && favorq->elements[2 * med - 2] == p) + med--; + if (favorq->elements[2 * med] == p) + el[i] = 2 * med + 1; + else + el[i] = 0; /* hmm */ + } + /* sort by position */ + solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements); + /* map back */ + for (i = 0; i < cnt; i++) + if (el[i]) + el[i] = favorq->elements[el[i] - 1]; +} + +/* bring favored packages to front and disfavored packages to back */ +void +policy_prefer_favored(Solver *solv, Queue *plist) +{ + int i, fav, disfav, count; + if (!solv->favormap.size) + return; + for (i = fav = disfav = 0, count = plist->count; i < count; i++) + { + Id p = plist->elements[i]; + if (!MAPTST(&solv->favormap, p)) + continue; + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)) + { + /* disfavored package. bring to back */ + if (i < plist->count - 1) + { + memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id)); + plist->elements[plist->count - 1] = p; + } + i--; + count--; + disfav++; + } + else + { + /* favored package. bring to front */ + if (i > fav) + memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id)); + plist->elements[fav++] = p; + } + } + /* if we have multiple favored/disfavored packages, sort by favorq index */ + if (fav > 1) + sort_by_favorq(solv->favorq, plist->elements, fav); + if (disfav > 1) + sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav); +} + /* * prune to recommended/suggested packages. * does not prune installed packages (they are also somewhat recommended). @@ -563,8 +646,7 @@ prune_to_best_arch(const Pool *pool, Queue *plist) for (i = 0; i < plist->count; i++) { s = pool->solvables + plist->elements[i]; - a = s->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + a = pool_arch2score(pool, s->arch); if (a && a != 1 && (!bestscore || a < bestscore)) bestscore = a; } @@ -573,10 +655,9 @@ prune_to_best_arch(const Pool *pool, Queue *plist) for (i = j = 0; i < plist->count; i++) { s = pool->solvables + plist->elements[i]; - a = s->arch; - if (a > pool->lastarch) + a = pool_arch2score(pool, s->arch); + if (!a) continue; - a = pool->id2arch[a]; /* a == 1 -> noarch */ if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0) continue; @@ -898,23 +979,7 @@ sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp) return 0; a = aa[2] < 0 ? -aa[2] : aa[2]; b = bb[2] < 0 ? -bb[2] : bb[2]; - if (pool->disttype != DISTTYPE_DEB && a != b) - { - /* treat release-less versions different */ - const char *as = pool_id2str(pool, a); - const char *bs = pool_id2str(pool, b); - if (strchr(as, '-')) - { - if (!strchr(bs, '-')) - return -2; - } - else - { - if (strchr(bs, '-')) - return 2; - } - } - r = pool_evrcmp(pool, b, a, EVRCMP_COMPARE); + r = pool_evrcmp(pool, b, a, pool->disttype != DISTTYPE_DEB ? EVRCMP_MATCH_RELEASE : EVRCMP_COMPARE); if (!r && (aa[2] < 0 || bb[2] < 0)) { if (bb[2] >= 0) @@ -922,9 +987,7 @@ sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp) if (aa[2] >= 0) return -1; } - if (r) - return r < 0 ? -1 : 1; - return 0; + return r; } /* common end of sort_by_srcversion and sort_by_common_dep */ @@ -1112,6 +1175,132 @@ dislike_old_versions(Pool *pool, Queue *plist) } } + +/* special lang package handling for urpm */ +/* see https://bugs.mageia.org/show_bug.cgi?id=18315 */ + +static int +urpm_reorder_cmp(const void *ap, const void *bp, void *dp) +{ + return ((Id *)bp)[1] - ((Id *)ap)[1]; +} + +static void +urpm_reorder(Solver *solv, Queue *plist) +{ + Pool *pool = solv->pool; + int i, count = plist->count; + /* add locale score to packages */ + queue_insertn(plist, count, count, 0); + for (i = count - 1; i >= 0; i--) + { + Solvable *s = pool->solvables + plist->elements[i]; + int score = 1; + const char *sn = pool_id2str(pool, s->name); + + if (!strncmp(sn, "kernel-", 7)) + { + const char *devel = strstr(sn, "-devel-"); + if (devel && strlen(sn) < 256) + { + char kn[256]; + Id p, pp, knid; + memcpy(kn, sn, devel - sn); + strcpy(kn + (devel - sn), devel + 6); + knid = pool_str2id(pool, kn, 0); + if (knid) + { + FOR_PROVIDES(p, pp, knid) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + else if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + } + } + } + else if ((sn = strstr(sn, "-kernel-")) != 0) + { + sn += 8; + if (strlen(sn) < 256 - 8 && *sn >= '0' && *sn <= '9' && sn[1] == '.') + { + const char *flavor = strchr(sn, '-'); + if (flavor) + { + const char *release = strchr(flavor + 1, '-'); + if (release) + { + char kn[256]; + Id p, pp, knid; + memcpy(kn, "kernel", 7); + memcpy(kn + 6, flavor, release - flavor + 1); + memcpy(kn + 6 + (release - flavor) + 1, sn, flavor - sn); + strcpy(kn + 6 + (release + 1 - sn), release); + knid = pool_str2id(pool, kn, 0); + if (knid) + { + FOR_PROVIDES(p, pp, knid) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + } + } + } + } + } + if (score == 1 && s->requires) + { + Id id, *idp, p, pp; + const char *deps; + for (idp = s->repo->idarraydata + s->requires; (id = *idp) != 0; idp++) + { + while (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + id = rd->name; + } + deps = strstr(pool_id2str(pool, id), "locales-"); + if (!deps) + continue; + if (!strncmp(deps + 8, "en", 2)) + score = 2; + else + { + score = 0; + FOR_PROVIDES(p, pp, id) + { + if (solv->decisionmap[p] > 0) + { + score = 4; + break; + } + if (pool->installed && pool->solvables[p].repo == pool->installed) + score = 3; + } + break; + } + } + } + plist->elements[i * 2] = plist->elements[i]; + plist->elements[i * 2 + 1] = score; + } + solv_sort(plist->elements, count, sizeof(Id) * 2, urpm_reorder_cmp, pool); + for (i = 0; i < count; i++) + plist->elements[i] = plist->elements[2 * i]; + queue_truncate(plist, count); +} + + /* * POLICY_MODE_CHOOSE: default, do all pruning steps * POLICY_MODE_RECOMMEND: leave out prune_to_recommended @@ -1121,6 +1310,17 @@ void policy_filter_unwanted(Solver *solv, Queue *plist, int mode) { Pool *pool = solv->pool; + if (mode == POLICY_MODE_SUPPLEMENT) + { + /* reorder only */ + dislike_old_versions(pool, plist); + sort_by_common_dep(pool, plist); + if (solv->urpmreorder) + urpm_reorder(solv, plist); + prefer_suggested(solv, plist); + policy_prefer_favored(solv, plist); + return; + } if (plist->count > 1) { if (mode != POLICY_MODE_SUGGEST) @@ -1143,11 +1343,30 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode) #endif dislike_old_versions(pool, plist); sort_by_common_dep(pool, plist); + if (solv->urpmreorder) + urpm_reorder(solv, plist); prefer_suggested(solv, plist); + policy_prefer_favored(solv, plist); } } } +void +pool_best_solvables(Pool *pool, Queue *plist, int flags) +{ + if (plist->count > 1) + prune_to_highest_prio(pool, plist); + if (plist->count > 1) + prune_to_best_arch(pool, plist); + if (plist->count > 1) + prune_to_best_version(pool, plist); + if (plist->count > 1) + { + dislike_old_versions(pool, plist); + sort_by_common_dep(pool, plist); + } +} + /* check if there is an illegal architecture change if * installed solvable s1 is replaced by s2 */ @@ -1162,8 +1381,8 @@ policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2) return 0; if (!pool->id2arch) return 0; - a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0; - a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0; + a1 = pool_arch2score(pool, a1); + a2 = pool_arch2score(pool, a2); if (((a1 ^ a2) & 0xffff0000) != 0) return 1; return 0; @@ -1203,7 +1422,7 @@ policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore) { Pool *pool = solv->pool; int ret = 0; - int duppkg = solv->dupmap_all ? 1 : 0; + int duppkg = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, is - pool->solvables)); if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !(duppkg ? solv->dup_allowdowngrade : solv->allowdowngrade)) { if (is->name == s->name && pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0) diff --git a/libsolv-0.6.15/src/policy.h b/libsolv-0.7.2/src/policy.h similarity index 87% rename from libsolv-0.6.15/src/policy.h rename to libsolv-0.7.2/src/policy.h index 73410ee..68f4db9 100644 --- a/libsolv-0.6.15/src/policy.h +++ b/libsolv-0.7.2/src/policy.h @@ -20,6 +20,7 @@ extern "C" { #define POLICY_MODE_RECOMMEND 1 #define POLICY_MODE_SUGGEST 2 #define POLICY_MODE_CHOOSE_NOREORDER 3 /* internal, do not use */ +#define POLICY_MODE_SUPPLEMENT 4 /* internal, do not use */ #define POLICY_ILLEGAL_DOWNGRADE 1 @@ -37,8 +38,11 @@ extern void policy_update_recommendsmap(Solver *solv); extern void policy_create_obsolete_index(Solver *solv); +extern void pool_best_solvables(Pool *pool, Queue *plist, int flags); + /* internal, do not use */ extern void prune_to_best_version(Pool *pool, Queue *plist); +extern void policy_prefer_favored(Solver *solv, Queue *plist); #ifdef __cplusplus diff --git a/libsolv-0.6.15/src/pool.c b/libsolv-0.7.2/src/pool.c similarity index 66% rename from libsolv-0.6.15/src/pool.c rename to libsolv-0.7.2/src/pool.c index 85932bf..383edb2 100644 --- a/libsolv-0.6.15/src/pool.c +++ b/libsolv-0.7.2/src/pool.c @@ -44,7 +44,7 @@ pool_create(void) pool = (Pool *)solv_calloc(1, sizeof(*pool)); - stringpool_init (&pool->ss, initpool_data); + stringpool_init(&pool->ss, initpool_data); /* alloc space for RelDep 0 */ pool->rels = solv_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK); @@ -705,6 +705,10 @@ pool_match_nevr_rel(Pool *pool, Solvable *s, Id d) if (!pool_match_nevr(pool, s, name)) return 0; return pool_match_nevr(pool, s, evr); + case REL_WITHOUT: + if (!pool_match_nevr(pool, s, name)) + return 0; + return !pool_match_nevr(pool, s, evr); case REL_MULTIARCH: if (evr != ARCH_ANY) return 0; @@ -799,7 +803,7 @@ pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr) /* public (i.e. not inlined) version of pool_match_flags_evr */ int -pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr) +pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, Id evr) { return pool_match_flags_evr(pool, pflags, pevr, flags, evr); } @@ -813,10 +817,49 @@ pool_match_dep(Pool *pool, Id d1, Id d2) if (d1 == d2) return 1; + + if (ISRELDEP(d1)) + { + /* we use potentially matches for complex deps */ + rd1 = GETRELDEP(pool, d1); + if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS) + { + if (pool_match_dep(pool, rd1->name, d2)) + return 1; + if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr)) + { + rd1 = GETRELDEP(pool, rd1->evr); + if (rd1->flags != REL_ELSE) + return 0; + } + if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2)) + return 1; + return 0; + } + } + if (ISRELDEP(d2)) + { + /* we use potentially matches for complex deps */ + rd2 = GETRELDEP(pool, d2); + if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS) + { + if (pool_match_dep(pool, d1, rd2->name)) + return 1; + if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr)) + { + rd2 = GETRELDEP(pool, rd2->evr); + if (rd2->flags != REL_ELSE) + return 0; + } + if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr)) + return 1; + return 0; + } + } if (!ISRELDEP(d1)) { if (!ISRELDEP(d2)) - return 0; + return 0; /* cannot match as d1 != d2 */ rd2 = GETRELDEP(pool, d2); return pool_match_dep(pool, d1, rd2->name); } @@ -884,7 +927,7 @@ pool_addstdproviders(Pool *pool, Id d) return 1; } queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf)); - dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST); + dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES); for (; dataiterator_step(&di); dataiterator_skip_solvable(&di)) { Solvable *s = pool->solvables + di.solvid; @@ -959,6 +1002,64 @@ pool_is_kind(Pool *pool, Id name, Id kind) } /* + * rpm eq magic: + * + * some dependencies are of the from "foo = md5sum", like the + * buildid provides. There's not much we can do to speed up + * getting the providers, because rpm's complex evr comparison + * rules get in the way. But we can use the first character(s) + * of the md5sum to do a simple pre-check. + */ +static inline int +rpmeqmagic(Pool *pool, Id evr) +{ + const char *s = pool_id2str(pool, evr); + if (*s == '0') + { + while (*s == '0' && s[1] >= '0' && s[1] <= '9') + s++; + /* ignore epoch 0 */ + if (*s == '0' && s[1] == ':') + { + s += 2; + while (*s == '0' && s[1] >= '0' && s[1] <= '9') + s++; + } + } + if (*s >= '0' && *s <= '9') + { + if (s[1] >= '0' && s[1] <= '9') + return *s + (s[1] << 8); + return *s; + } + if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')) + { + if ((s[1] >= 'a' && s[1] <= 'z') || (s[1] >= 'A' && s[1] <= 'Z')) + return *s + (s[1] << 8); + return *s; + } + return -1; +} + +static inline int +rpmeqmagic_init(Pool *pool, int flags, Id evr) +{ + if (flags != REL_EQ || pool->disttype != DISTTYPE_RPM || pool->promoteepoch || ISRELDEP(evr)) + return -1; + else + return rpmeqmagic(pool, evr); +} + +static inline int +rpmeqmagic_cantmatch(Pool *pool, int flags, Id evr, int eqmagic) +{ + int peqmagic = rpmeqmagic(pool, evr); + if (peqmagic > 0 && peqmagic != eqmagic) + return 1; + return 0; +} + +/* * addrelproviders * * add packages fulfilling the relation to whatprovides array @@ -1011,11 +1112,26 @@ pool_addrelproviders(Pool *pool, Id d) wp = 0; } break; - + case REL_WITHOUT: + wp = pool_whatprovides(pool, name); + pp2 = pool_whatprovides_ptr(pool, evr); + pp = pool->whatprovidesdata + wp; + while ((p = *pp++) != 0) + { + for (pp3 = pp2; *pp3; pp3++) + if (*pp3 == p) + break; + if (!*pp3) + queue_push(&plist, p); /* use it */ + else + wp = 0; + } + break; case REL_AND: case REL_OR: case REL_COND: - if (flags == REL_COND) + case REL_UNLESS: + if (flags == REL_COND || flags == REL_UNLESS) { if (ISRELDEP(evr)) { @@ -1179,6 +1295,7 @@ pool_addrelproviders(Pool *pool, Id d) else if (flags) { Id *ppaux = 0; + int eqmagic = 0; /* simple version comparison relation */ #if 0 POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name)); @@ -1214,6 +1331,11 @@ pool_addrelproviders(Pool *pool, Id d) prd = GETRELDEP(pool, pid); if (prd->name != name) continue; /* wrong provides name */ + if (!eqmagic) + eqmagic = rpmeqmagic_init(pool, flags, evr); + if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) && + rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic)) + continue; /* right package, both deps are rels. check flags/evr */ if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr)) continue; @@ -1230,6 +1352,8 @@ pool_addrelproviders(Pool *pool, Id d) continue; } /* solvable p provides name in some rels */ + if (!eqmagic) + eqmagic = rpmeqmagic_init(pool, flags, evr); pidp = s->repo->idarraydata + s->provides; while ((pid = *pidp++) != 0) { @@ -1245,6 +1369,9 @@ pool_addrelproviders(Pool *pool, Id d) if (prd->name != name) continue; /* wrong provides name */ /* right package, both deps are rels. check flags/evr */ + if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) && + rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic)) + continue; if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr)) break; /* matches */ } @@ -1283,7 +1410,8 @@ pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr) continue; if (evr && rd->evr != evr) continue; - pool->whatprovides_rel[d] = 0; + if (pool->whatprovides_rel[d]) + pool_set_whatprovides(pool, MAKERELDEP(d), 0); } } @@ -1292,8 +1420,19 @@ void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) { Id p; + Queue qq; + int i; queue_empty(q); + if (keyname == SOLVABLE_NAME) + { + Id pp; + FOR_PROVIDES(p, pp, dep) + if (pool_match_dep(pool, p, dep)) + queue_push(q, p); + return; + } + queue_init(&qq); FOR_POOL_SOLVABLES(p) { Solvable *s = pool->solvables + p; @@ -1301,9 +1440,80 @@ pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) continue; if (s->repo != pool->installed && !pool_installable(pool, s)) continue; - if (solvable_matchesdep(s, keyname, dep, marker)) - queue_push(q, p); + if (qq.count) + queue_empty(&qq); + solvable_lookup_deparray(s, keyname, &qq, marker); + for (i = 0; i < qq.count; i++) + if (pool_match_dep(pool, qq.elements[i], dep)) + { + queue_push(q, p); + break; + } } + queue_free(&qq); +} + +/* check if keyname contains dep, return list of matching packages */ +void +pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) +{ + Id p; + Queue qq; + int i; + + queue_empty(q); + if (!dep) + return; + queue_init(&qq); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (qq.count) + queue_empty(&qq); + solvable_lookup_deparray(s, keyname, &qq, marker); + for (i = 0; i < qq.count; i++) + if (qq.elements[i] == dep) + { + queue_push(q, p); + break; + } + } + queue_free(&qq); +} + +/* intersect dependencies in keyname with all provides of solvable solvid, + * return list of matching packages */ +/* this currently only works for installable packages */ +void +pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker) +{ + Id p; + Queue qq; + Map missc; /* cache for misses */ + int reloff; + + queue_empty(q); + queue_init(&qq); + reloff = pool->ss.nstrings; + map_init(&missc, reloff + pool->nrels); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (p == solvid) + continue; /* filter out self-matches */ + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff)) + queue_push(q, p); + } + map_free(&missc); + queue_free(&qq); } /*************************************************************************/ @@ -1338,6 +1548,9 @@ pool_error(Pool *pool, int ret, const char *format, ...) { va_list args; int l; + + if (!pool) + return ret; va_start(args, format); if (!pool->errstr) { @@ -1389,7 +1602,7 @@ pool_setdebuglevel(Pool *pool, int level) pool->debugmask = mask; } -void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata) +void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata) { pool->debugcallback = debugcallback; pool->debugcallbackdata = debugcallbackdata; @@ -1400,371 +1613,20 @@ void pool_setdebugmask(Pool *pool, int mask) pool->debugmask = mask; } -void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata) +void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata) { pool->loadcallback = cb; pool->loadcallbackdata = loadcbdata; } -void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata) +void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata) { pool->nscallback = cb; pool->nscallbackdata = nscbdata; } -/*************************************************************************/ - -struct searchfiles { - Id *ids; - int nfiles; - Map seen; -}; - -#define SEARCHFILES_BLOCK 127 - -static void -pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) -{ - Id dep, sid; - const char *s; - struct searchfiles *csf; - - while ((dep = *ida++) != 0) - { - csf = sf; - while (ISRELDEP(dep)) - { - Reldep *rd; - sid = pool->ss.nstrings + GETRELID(dep); - if (MAPTST(&csf->seen, sid)) - { - dep = 0; - break; - } - MAPSET(&csf->seen, sid); - rd = GETRELDEP(pool, dep); - if (rd->flags < 8) - dep = rd->name; - else if (rd->flags == REL_NAMESPACE) - { - if (rd->name == NAMESPACE_SPLITPROVIDES) - { - csf = isf; - if (!csf || MAPTST(&csf->seen, sid)) - { - dep = 0; - break; - } - MAPSET(&csf->seen, sid); - } - dep = rd->evr; - } - else if (rd->flags == REL_FILECONFLICT) - { - dep = 0; - break; - } - else - { - Id ids[2]; - ids[0] = rd->name; - ids[1] = 0; - pool_addfileprovides_dep(pool, ids, csf, isf); - dep = rd->evr; - } - } - if (!dep) - continue; - if (MAPTST(&csf->seen, dep)) - continue; - MAPSET(&csf->seen, dep); - s = pool_id2str(pool, dep); - if (*s != '/') - continue; - if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s)) - continue; /* skip non-standard locations csf == isf: installed case */ - csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); - csf->ids[csf->nfiles++] = dep; - } -} - -struct addfileprovides_cbdata { - int nfiles; - Id *ids; - char **dirs; - char **names; - - Id *dids; - - Map providedids; - - Map useddirs; -}; - -static int -addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) -{ - struct addfileprovides_cbdata *cbd = cbdata; - int i; - - if (!cbd->useddirs.size) - { - map_init(&cbd->useddirs, data->dirpool.ndirs + 1); - if (!cbd->dirs) - { - cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *)); - cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *)); - for (i = 0; i < cbd->nfiles; i++) - { - char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i])); - cbd->dirs[i] = s; - s = strrchr(s, '/'); - *s = 0; - cbd->names[i] = s + 1; - } - } - for (i = 0; i < cbd->nfiles; i++) - { - Id did; - if (MAPTST(&cbd->providedids, cbd->ids[i])) - { - cbd->dids[i] = 0; - continue; - } - did = repodata_str2dir(data, cbd->dirs[i], 0); - cbd->dids[i] = did; - if (did) - MAPSET(&cbd->useddirs, did); - } - repodata_free_dircache(data); - } - if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) - return 0; - for (i = 0; i < cbd->nfiles; i++) - if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str)) - s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); - return 0; -} - -static void -pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) -{ - Id p; - Repodata *data; - Repo *repo; - Queue fileprovidesq; - int i, j, repoid, repodataid; - int provstart, provend; - Map donemap; - int ndone, incomplete; - - if (!pool->urepos) - return; - - cbd->nfiles = sf->nfiles; - cbd->ids = sf->ids; - cbd->dirs = 0; - cbd->names = 0; - cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); - map_init(&cbd->providedids, pool->ss.nstrings); - - repoid = 1; - repo = repoonly ? repoonly : pool->repos[repoid]; - map_init(&donemap, pool->nsolvables); - queue_init(&fileprovidesq); - provstart = provend = 0; - for (;;) - { - if (!repo || repo->disabled) - { - if (repoonly || ++repoid == pool->nrepos) - break; - repo = pool->repos[repoid]; - continue; - } - ndone = 0; - FOR_REPODATAS(repo, repodataid, data) - { - if (ndone >= repo->nsolvables) - break; - - if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) - { - map_empty(&cbd->providedids); - for (i = 0; i < fileprovidesq.count; i++) - MAPSET(&cbd->providedids, fileprovidesq.elements[i]); - provstart = data->start; - provend = data->end; - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i])) - break; - if (i == cbd->nfiles) - { - /* great! no need to search files */ - for (p = data->start; p < data->end; p++) - if (pool->solvables[p].repo == repo) - { - if (MAPTST(&donemap, p)) - continue; - MAPSET(&donemap, p); - ndone++; - } - continue; - } - } - - if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) - continue; - - if (data->start < provstart || data->end > provend) - { - map_empty(&cbd->providedids); - provstart = provend = 0; - } - - /* check if the data is incomplete */ - incomplete = 0; - if (data->state == REPODATA_AVAILABLE) - { - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - break; - if (j < data->nkeys) - { -#if 0 - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) - printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i])); -#endif - for (i = 0; i < cbd->nfiles; i++) - if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i]))) - break; - if (i < cbd->nfiles) - incomplete = 1; - } - } - - /* do the search */ - map_init(&cbd->useddirs, 0); - for (p = data->start; p < data->end; p++) - if (pool->solvables[p].repo == repo) - { - if (MAPTST(&donemap, p)) - continue; - repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); - if (!incomplete) - { - MAPSET(&donemap, p); - ndone++; - } - } - map_free(&cbd->useddirs); - } - - if (repoonly || ++repoid == pool->nrepos) - break; - repo = pool->repos[repoid]; - } - map_free(&donemap); - queue_free(&fileprovidesq); - map_free(&cbd->providedids); - if (cbd->dirs) - { - for (i = 0; i < cbd->nfiles; i++) - solv_free(cbd->dirs[i]); - cbd->dirs = solv_free(cbd->dirs); - cbd->names = solv_free(cbd->names); - } -} - void -pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst) -{ - Solvable *s; - Repo *installed, *repo; - struct searchfiles sf, isf, *isfp; - struct addfileprovides_cbdata cbd; - int i; - unsigned int now; - - installed = pool->installed; - now = solv_timems(0); - memset(&sf, 0, sizeof(sf)); - map_init(&sf.seen, pool->ss.nstrings + pool->nrels); - memset(&isf, 0, sizeof(isf)); - map_init(&isf.seen, pool->ss.nstrings + pool->nrels); - pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2; - - if (idq) - queue_empty(idq); - if (idqinst) - queue_empty(idqinst); - isfp = installed ? &isf : 0; - for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) - { - repo = s->repo; - if (!repo) - continue; - if (s->obsoletes) - pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); - if (s->conflicts) - pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); - if (s->requires) - pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); - if (s->recommends) - pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); - if (s->suggests) - pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); - if (s->supplements) - pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); - if (s->enhances) - pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); - } - map_free(&sf.seen); - map_free(&isf.seen); - POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); - cbd.dids = 0; - if (sf.nfiles) - { -#if 0 - for (i = 0; i < sf.nfiles; i++) - POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i])); -#endif - pool_addfileprovides_search(pool, &cbd, &sf, 0); - if (idq) - for (i = 0; i < sf.nfiles; i++) - queue_push(idq, sf.ids[i]); - if (idqinst) - for (i = 0; i < sf.nfiles; i++) - queue_push(idqinst, sf.ids[i]); - solv_free(sf.ids); - } - if (isf.nfiles) - { -#if 0 - for (i = 0; i < isf.nfiles; i++) - POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i])); -#endif - if (installed) - pool_addfileprovides_search(pool, &cbd, &isf, installed); - if (installed && idqinst) - for (i = 0; i < isf.nfiles; i++) - queue_pushunique(idqinst, isf.ids[i]); - solv_free(isf.ids); - } - solv_free(cbd.dids); - pool_freewhatprovides(pool); /* as we have added provides */ - POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now)); -} - -void -pool_addfileprovides(Pool *pool) -{ - pool_addfileprovides_queue(pool, 0, 0); -} - -void -pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata) +pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata) { if (p) { @@ -1784,7 +1646,6 @@ pool_clear_pos(Pool *pool) memset(&pool->pos, 0, sizeof(pool->pos)); } - void pool_set_languages(Pool *pool, const char **languages, int nlanguages) { @@ -1951,548 +1812,6 @@ pool_bin2hex(Pool *pool, const unsigned char *buf, int len) return s; } -/*******************************************************************/ - -struct mptree { - Id sibling; - Id child; - const char *comp; - int compl; - Id mountpoint; -}; - -struct ducbdata { - DUChanges *mps; - struct mptree *mptree; - int addsub; - int hasdu; - - Id *dirmap; - int nmap; - Repodata *olddata; -}; - - -static int -solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) -{ - struct ducbdata *cbd = cbdata; - Id mp; - - if (data != cbd->olddata) - { - Id dn, mp, comp, *dirmap, *dirs; - int i, compl; - const char *compstr; - struct mptree *mptree; - - /* create map from dir to mptree */ - cbd->dirmap = solv_free(cbd->dirmap); - cbd->nmap = 0; - dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); - mptree = cbd->mptree; - mp = 0; - for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) - { - comp = *dirs++; - if (comp <= 0) - { - mp = dirmap[-comp]; - continue; - } - if (mp < 0) - { - /* unconnected */ - dirmap[dn] = mp; - continue; - } - if (!mptree[mp].child) - { - dirmap[dn] = -mp; - continue; - } - if (data->localpool) - compstr = stringpool_id2str(&data->spool, comp); - else - compstr = pool_id2str(data->repo->pool, comp); - compl = strlen(compstr); - for (i = mptree[mp].child; i; i = mptree[i].sibling) - if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) - break; - dirmap[dn] = i ? i : -mp; - } - /* change dirmap to point to mountpoint instead of mptree */ - for (dn = 0; dn < data->dirpool.ndirs; dn++) - { - mp = dirmap[dn]; - dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; - } - cbd->dirmap = dirmap; - cbd->nmap = data->dirpool.ndirs; - cbd->olddata = data; - } - cbd->hasdu = 1; - if (value->id < 0 || value->id >= cbd->nmap) - return 0; - mp = cbd->dirmap[value->id]; - if (mp < 0) - return 0; - if (cbd->addsub > 0) - { - cbd->mps[mp].kbytes += value->num; - cbd->mps[mp].files += value->num2; - } - else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) - { - cbd->mps[mp].kbytes -= value->num; - cbd->mps[mp].files -= value->num2; - } - return 0; -} - -static void -propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) -{ - int i; - if (mptree[pos].mountpoint == -1) - mptree[pos].mountpoint = mountpoint; - else - mountpoint = mptree[pos].mountpoint; - for (i = mptree[pos].child; i; i = mptree[i].sibling) - propagate_mountpoints(mptree, i, mountpoint); -} - -#define MPTREE_BLOCK 15 - -static struct mptree * -create_mptree(DUChanges *mps, int nmps) -{ - int i, nmptree; - struct mptree *mptree; - int pos, compl; - int mp; - const char *p, *path, *compstr; - - mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); - - /* our root node */ - mptree[0].sibling = 0; - mptree[0].child = 0; - mptree[0].comp = 0; - mptree[0].compl = 0; - mptree[0].mountpoint = -1; - nmptree = 1; - - /* create component tree */ - for (mp = 0; mp < nmps; mp++) - { - mps[mp].kbytes = 0; - mps[mp].files = 0; - pos = 0; - path = mps[mp].path; - while(*path == '/') - path++; - while (*path) - { - if ((p = strchr(path, '/')) == 0) - { - compstr = path; - compl = strlen(compstr); - path += compl; - } - else - { - compstr = path; - compl = p - path; - path = p + 1; - while(*path == '/') - path++; - } - for (i = mptree[pos].child; i; i = mptree[i].sibling) - if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) - break; - if (!i) - { - /* create new node */ - mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); - i = nmptree++; - mptree[i].sibling = mptree[pos].child; - mptree[i].child = 0; - mptree[i].comp = compstr; - mptree[i].compl = compl; - mptree[i].mountpoint = -1; - mptree[pos].child = i; - } - pos = i; - } - mptree[pos].mountpoint = mp; - } - - propagate_mountpoints(mptree, 0, mptree[0].mountpoint); - -#if 0 - for (i = 0; i < nmptree; i++) - { - printf("#%d sibling: %d\n", i, mptree[i].sibling); - printf("#%d child: %d\n", i, mptree[i].child); - printf("#%d comp: %s\n", i, mptree[i].comp); - printf("#%d compl: %d\n", i, mptree[i].compl); - printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); - } -#endif - - return mptree; -} - -void -pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) -{ - struct mptree *mptree; - struct ducbdata cbd; - Solvable *s; - int i, sp; - Map ignoredu; - Repo *oldinstalled = pool->installed; - int haveonlyadd = 0; - - map_init(&ignoredu, 0); - mptree = create_mptree(mps, nmps); - - for (i = 0; i < nmps; i++) - if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) - haveonlyadd = 1; - cbd.mps = mps; - cbd.dirmap = 0; - cbd.nmap = 0; - cbd.olddata = 0; - cbd.mptree = mptree; - cbd.addsub = 1; - for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) - { - if (!s->repo || (oldinstalled && s->repo == oldinstalled)) - continue; - if (!MAPTST(installedmap, sp)) - continue; - cbd.hasdu = 0; - repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - if (!cbd.hasdu && oldinstalled) - { - Id op, opp; - int didonlyadd = 0; - /* no du data available, ignore data of all installed solvables we obsolete */ - if (!ignoredu.size) - map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); - FOR_PROVIDES(op, opp, s->name) - { - Solvable *s2 = pool->solvables + op; - if (!pool->implicitobsoleteusesprovides && s->name != s2->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - if (op >= oldinstalled->start && op < oldinstalled->end) - { - MAPSET(&ignoredu, op - oldinstalled->start); - if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) - { - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = -1; - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = 1; - didonlyadd = 1; - } - } - } - if (s->obsoletes) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - FOR_PROVIDES(op, opp, obs) - { - Solvable *s2 = pool->solvables + op; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) - continue; - if (op >= oldinstalled->start && op < oldinstalled->end) - { - MAPSET(&ignoredu, op - oldinstalled->start); - if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) - { - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = -1; - repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - cbd.addsub = 1; - didonlyadd = 1; - } - } - } - } - } - } - cbd.addsub = -1; - if (oldinstalled) - { - /* assumes we allways have du data for installed solvables */ - FOR_REPO_SOLVABLES(oldinstalled, sp, s) - { - if (MAPTST(installedmap, sp)) - continue; - if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) - continue; - repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); - } - } - map_free(&ignoredu); - solv_free(cbd.dirmap); - solv_free(mptree); -} - -int -pool_calc_installsizechange(Pool *pool, Map *installedmap) -{ - Id sp; - Solvable *s; - int change = 0; - Repo *oldinstalled = pool->installed; - - for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) - { - if (!s->repo || (oldinstalled && s->repo == oldinstalled)) - continue; - if (!MAPTST(installedmap, sp)) - continue; - change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); - } - if (oldinstalled) - { - FOR_REPO_SOLVABLES(oldinstalled, sp, s) - { - if (MAPTST(installedmap, sp)) - continue; - change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); - } - } - return change; -} - -/* map: - * 1: installed - * 2: conflicts with installed - * 8: interesting (only true if installed) - * 16: undecided - */ - -static inline Id dep2name(Pool *pool, Id dep) -{ - while (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - dep = rd->name; - } - return dep; -} - -static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) -{ - Id p, pp; - Solvable *sn = pool->solvables + n; - - FOR_PROVIDES(p, pp, sn->name) - { - Solvable *s = pool->solvables + p; - if (s->name != sn->name || s->arch != sn->arch) - continue; - if ((map[p] & 9) != 9) - continue; - if (pool_match_nevr(pool, pool->solvables + p, con)) - continue; - return 1; /* found installed package that doesn't conflict */ - } - return 0; -} - -static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap) -{ - Id p, pp; - int r = 0; - FOR_PROVIDES(p, pp, dep) - { - if (p == SYSTEMSOLVABLE) - return 1; /* always boring, as never constraining */ - if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) - continue; - if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep)) - if (providedbyinstalled_multiversion(pool, map, p, dep)) - continue; - if ((map[p] & 9) == 9) - return 9; - r |= map[p] & 17; - } - return r; -} - -/* - * pool_trivial_installable - calculate if a set of solvables is - * trivial installable without any other installs/deinstalls of - * packages not belonging to the set. - * - * the state is returned in the result queue: - * 1: solvable is installable without any other package changes - * 0: solvable is not installable - * -1: solvable is installable, but doesn't constrain any installed packages - */ - -void -pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap) -{ - int i, r, m, did; - Id p, *dp, con, *conp, req, *reqp; - unsigned char *map; - Solvable *s; - - map = solv_calloc(pool->nsolvables, 1); - for (p = 1; p < pool->nsolvables; p++) - { - if (!MAPTST(installedmap, p)) - continue; - map[p] |= 9; - s = pool->solvables + p; - if (!s->conflicts) - continue; - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - dp = pool_whatprovides_ptr(pool, con); - for (; *dp; dp++) - map[p] |= 2; /* XXX: self conflict ? */ - } - } - for (i = 0; i < pkgs->count; i++) - map[pkgs->elements[i]] = 16; - - for (i = 0, did = 0; did < pkgs->count; i++, did++) - { - if (i == pkgs->count) - i = 0; - p = pkgs->elements[i]; - if ((map[p] & 16) == 0) - continue; - if ((map[p] & 2) != 0) - { - map[p] = 2; - continue; - } - s = pool->solvables + p; - m = 1; - if (s->requires) - { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) - { - if (req == SOLVABLE_PREREQMARKER) - continue; - r = providedbyinstalled(pool, map, req, 0, 0); - if (!r) - { - /* decided and miss */ - map[p] = 2; - did = 0; - break; - } - if (r == 16) - break; /* undecided */ - m |= r; /* 1 | 9 | 17 */ - } - if (req) - continue; - if ((m & 9) == 9) - m = 9; - } - if (s->conflicts) - { - int ispatch = 0; /* see solver.c patch handling */ - - if (!strncmp("patch:", pool_id2str(pool, s->name), 6)) - ispatch = 1; - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0) - { - map[p] = 2; - did = 0; - break; - } - if ((m == 1 || m == 17) && ISRELDEP(con)) - { - con = dep2name(pool, con); - if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0) - m = 9; - } - } - if (con) - continue; /* found a conflict */ - } -#if 0 - if (s->repo && s->repo != oldinstalled) - { - Id p2, obs, *obsp, *pp; - Solvable *s2; - if (s->obsoletes) - { - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0) - { - map[p] = 2; - break; - } - } - if (obs) - continue; - } - FOR_PROVIDES(p2, pp, s->name) - { - s2 = pool->solvables + p2; - if (s2->name == s->name && (map[p2] & 1) != 0) - { - map[p] = 2; - break; - } - } - if (p2) - continue; - } -#endif - if (m != map[p]) - { - map[p] = m; - did = 0; - } - } - queue_free(res); - queue_init_clone(res, pkgs); - for (i = 0; i < pkgs->count; i++) - { - m = map[pkgs->elements[i]]; - if ((m & 9) == 9) - r = 1; - else if (m & 1) - r = -1; - else - r = 0; - res->elements[i] = r; - } - free(map); -} - -void -pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res) -{ - pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0); -} - const char * pool_lookup_str(Pool *pool, Id entry, Id keyname) { @@ -2578,24 +1897,66 @@ pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp) return loc; } +void +pool_set_whatprovides(Pool *pool, Id id, Id providers) +{ + int d, nrels = pool->nrels; + Reldep *rd; + Map m; + + /* set new entry */ + if (ISRELDEP(id)) + { + d = GETRELID(id); + pool->whatprovides_rel[d] = providers; + d++; + } + else + { + pool->whatprovides[id] = providers; + if (id < pool->whatprovidesauxoff) + pool->whatprovidesaux[id] = 0; /* sorry */ + d = 1; + } + if (!pool->whatprovides_rel) + return; + /* clear cache of all rels that use it */ + map_init(&m, 0); + for (rd = pool->rels + d; d < nrels; d++, rd++) + { + if (rd->name == id || rd->evr == id || + (m.size && ISRELDEP(rd->name) && MAPTST(&m, GETRELID(rd->name))) || + (m.size && ISRELDEP(rd->evr) && MAPTST(&m, GETRELID(rd->evr)))) + { + pool->whatprovides_rel[d] = 0; /* clear cache */ + if (!m.size) + map_init(&m, nrels); + MAPSET(&m, d); + } + } + map_free(&m); +} + static void add_new_provider(Pool *pool, Id id, Id p) { Queue q; Id *pp; + /* find whatprovides entry */ while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); id = rd->name; } + /* add new provider to existing list keeping it sorted */ queue_init(&q); for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++) { if (*pp == p) { - queue_free(&q); + queue_free(&q); /* already have it */ return; } if (*pp > p) @@ -2607,9 +1968,7 @@ add_new_provider(Pool *pool, Id id, Id p) } if (p) queue_push(&q, p); - pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q); - if (id < pool->whatprovidesauxoff) - pool->whatprovidesaux[id] = 0; /* sorry */ + pool_set_whatprovides(pool, id, pool_queuetowhatprovides(pool, &q)); queue_free(&q); } @@ -2636,9 +1995,7 @@ pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts) continue; s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER); if (pool->whatprovides) - add_new_provider(pool, fn, p); - if (pool->whatprovides_rel) - pool->whatprovides_rel[GETRELID(id)] = 0; /* clear cache */ + add_new_provider(pool, id, p); s = pool->solvables + q; if (!s->repo) continue; diff --git a/libsolv-0.6.15/src/pool.h b/libsolv-0.7.2/src/pool.h similarity index 85% rename from libsolv-0.6.15/src/pool.h rename to libsolv-0.7.2/src/pool.h index 4a2089d..37583a1 100644 --- a/libsolv-0.6.15/src/pool.h +++ b/libsolv-0.7.2/src/pool.h @@ -34,43 +34,48 @@ extern "C" { #define SYSTEMSOLVABLE 1 -/* how many strings to maintain (round robin) */ -#define POOL_TMPSPACEBUF 16 - /*----------------------------------------------- */ -struct _Repo; -struct _Repodata; -struct _Repokey; -struct _KeyValue; +struct s_Repo; +struct s_Repodata; +struct s_Repokey; +struct s_KeyValue; -typedef struct _Datapos { - struct _Repo *repo; +typedef struct s_Datapos { + struct s_Repo *repo; Id solvid; Id repodataid; Id schema; Id dp; } Datapos; -struct _Pool_tmpspace { + +#ifdef LIBSOLV_INTERNAL + +/* how many strings to maintain (round robin) */ +#define POOL_TMPSPACEBUF 16 + +struct s_Pool_tmpspace { char *buf[POOL_TMPSPACEBUF]; int len[POOL_TMPSPACEBUF]; int n; }; -struct _Pool { +#endif + +struct s_Pool { void *appdata; /* application private pointer */ - struct _Stringpool ss; + struct s_Stringpool ss; Reldep *rels; /* table of rels: Id -> Reldep */ int nrels; /* number of unique rels */ - struct _Repo **repos; + struct s_Repo **repos; int nrepos; /* repos allocated */ int urepos; /* repos in use */ - struct _Repo *installed; /* packages considered installed */ + struct s_Repo *installed; /* packages considered installed */ Solvable *solvables; int nsolvables; /* solvables allocated */ @@ -83,7 +88,7 @@ struct _Pool { Id *id2arch; /* map arch ids to scores */ unsigned char *id2color; /* map arch ids to colors */ - Id lastarch; /* last valid entry in id2arch/id2color */ + Id lastarch; /* size of the id2arch/id2color arrays */ Queue vendormap; /* map vendor to vendorclasses mask */ const char **vendorclasses; /* vendor equivalence classes */ @@ -104,16 +109,16 @@ struct _Pool { Map *considered; /* callback for REL_NAMESPACE dependencies handled by the application */ - Id (*nscallback)(struct _Pool *, void *data, Id name, Id evr); + Id (*nscallback)(struct s_Pool *, void *data, Id name, Id evr); void *nscallbackdata; /* debug mask and callback */ int debugmask; - void (*debugcallback)(struct _Pool *, void *data, int type, const char *str); + void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str); void *debugcallbackdata; /* load callback */ - int (*loadcallback)(struct _Pool *, struct _Repodata *, void *); + int (*loadcallback)(struct s_Pool *, struct s_Repodata *, void *); void *loadcallbackdata; /* search position */ @@ -143,14 +148,14 @@ struct _Pool { int languagecacheother; /* our tmp space string space */ - struct _Pool_tmpspace tmpspace; + struct s_Pool_tmpspace tmpspace; char *errstr; /* last error string */ int errstra; /* allocated space for errstr */ char *rootdir; - int (*custom_vendorcheck)(struct _Pool *, Solvable *, Solvable *); + int (*custom_vendorcheck)(struct s_Pool *, Solvable *, Solvable *); int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */ int addedfileprovides; /* true: application called addfileprovides */ @@ -218,11 +223,14 @@ struct _Pool { #define REL_NAMESPACE 19 #define REL_ARCH 20 #define REL_FILECONFLICT 21 -#define REL_COND 22 +#define REL_COND 22 /* OR_NOT */ #define REL_COMPAT 23 #define REL_KIND 24 /* for filters only */ #define REL_MULTIARCH 25 /* debian multiarch annotation */ -#define REL_ELSE 26 /* only as evr part of REL_COND */ +#define REL_ELSE 26 /* only as evr part of REL_COND/REL_UNLESS */ +#define REL_ERROR 27 /* parse errors and the like */ +#define REL_WITHOUT 28 +#define REL_UNLESS 29 /* AND_NOT */ #if !defined(__GNUC__) && !defined(__attribute__) # define __attribute__(x) @@ -238,13 +246,13 @@ extern int pool_set_flag(Pool *pool, int flag, int value); extern int pool_get_flag(Pool *pool, int flag); extern void pool_debug(Pool *pool, int type, const char *format, ...) __attribute__((format(printf, 3, 4))); -extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata); +extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata); extern void pool_setdebugmask(Pool *pool, int mask); -extern void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata); -extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata); +extern void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata); +extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata); extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr); -extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct _Pool *, Solvable *, Solvable *)); +extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *)); extern char *pool_alloctmpspace(Pool *pool, int len); @@ -253,7 +261,7 @@ extern char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const extern char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3); extern const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len); -extern void pool_set_installed(Pool *pool, struct _Repo *repo); +extern void pool_set_installed(Pool *pool, struct s_Repo *repo); extern int pool_error(Pool *pool, int ret, const char *format, ...) __attribute__((format(printf, 3, 4))); extern char *pool_errstr(Pool *pool); @@ -274,6 +282,10 @@ static inline Solvable *pool_id2solvable(const Pool *pool, Id p) { return pool->solvables + p; } +static inline Id pool_solvable2id(const Pool *pool, Solvable *s) +{ + return s - pool->solvables; +} extern const char *pool_solvable2str(Pool *pool, Solvable *s); static inline const char *pool_solvid2str(Pool *pool, Id p) @@ -284,14 +296,7 @@ static inline const char *pool_solvid2str(Pool *pool, Id p) void pool_set_languages(Pool *pool, const char **languages, int nlanguages); Id pool_id2langid(Pool *pool, Id id, const char *lang, int create); -int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap); -int solvable_trivial_installable_repo(Solvable *s, struct _Repo *installed, Map *multiversionmap); -int solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap); -int solvable_is_irrelevant_patch(Solvable *s, Map *installedmap); - -void pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap); - -int pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr); +int pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, Id evr); int pool_match_dep(Pool *pool, Id d1, Id d2); /* semi private, used in pool_match_nevr */ @@ -342,31 +347,21 @@ static inline Id *pool_whatprovides_ptr(Pool *pool, Id d) } void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker); +void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker); +void pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker); +void pool_set_whatprovides(Pool *pool, Id id, Id providers); + /* search the pool. the following filters are available: * p - search just this solvable * key - search only this key * match - key must match this string */ -void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata); +void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata); void pool_clear_pos(Pool *pool); - -#define DUCHANGES_ONLYADD 1 - -typedef struct _DUChanges { - const char *path; - int kbytes; - int files; - int flags; -} DUChanges; - -void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps); -int pool_calc_installsizechange(Pool *pool, Map *installedmap); -void pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res); -void pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap); - +/* lookup functions */ const char *pool_lookup_str(Pool *pool, Id entry, Id keyname); Id pool_lookup_id(Pool *pool, Id entry, Id keyname); unsigned long long pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound); @@ -376,6 +371,21 @@ int pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q); const char *pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep); const char *pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp); + +#define DUCHANGES_ONLYADD 1 + +typedef struct s_DUChanges { + const char *path; + long long kbytes; + long long files; + int flags; +} DUChanges; + + +void pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap); +void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps); +long long pool_calc_installsizechange(Pool *pool, Map *installedmap); + void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts); @@ -397,14 +407,13 @@ void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts); continue; \ else -#ifdef ENABLE_COMPS -#define ISCONDDEP(id) (ISRELDEP(id) && (GETRELDEP(pool, id))->flags == REL_COND) -#define MODIFYCONDDEP(id, tst) do { Reldep *condrd = GETRELDEP(pool, id); Id condp, condpp; FOR_PROVIDES(condrd->evr, condp, condpp) if (tst) break; id = condp ? condrd->name : 0;} while(0) -#endif - #define POOL_DEBUG(type, ...) do {if ((pool->debugmask & (type)) != 0) pool_debug(pool, (type), __VA_ARGS__);} while (0) #define IF_POOLDEBUG(type) if ((pool->debugmask & (type)) != 0) +/* weird suse stuff */ +void pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap); +void pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res); + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/poolarch.c b/libsolv-0.7.2/src/poolarch.c similarity index 79% rename from libsolv-0.6.15/src/poolarch.c rename to libsolv-0.7.2/src/poolarch.c index 788646b..6727760 100644 --- a/libsolv-0.6.15/src/poolarch.c +++ b/libsolv-0.7.2/src/poolarch.c @@ -29,41 +29,30 @@ static const char *archpolicies[] = { "i686", "i686:i586:i486:i386", "i586", "i586:i486:i386", "i486", "i486:i386", - "i386", "i386", "s390x", "s390x:s390", - "s390", "s390", - "ppc64le", "ppc64le", "ppc64", "ppc64:ppc", - "ppc", "ppc", "ppc64p7", "ppc64p7:ppc64:ppc", "ia64", "ia64:i686:i586:i486:i386", - "aarch64", "aarch64", - "armv6hl", "armv6hl", + "armv8hcnl", "armv8hcnl:armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl", + "armv8hnl", "armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl", + "armv8hl", "armv8hl:armv7hl:armv6hl", + "armv8l", "armv8l:armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l", "armv7hnl", "armv7hnl:armv7hl:armv6hl", "armv7hl", "armv7hl:armv6hl", - "armv7l", "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l", - "armv6l", "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l", - "armv5tejl", "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l", - "armv5tel", "armv5tel:armv5l:armv4tl:armv4l:armv3l", - "armv5tl", "armv5l:armv4tl:armv4l:armv3l", + "armv7l", "armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l", + "armv6l", "armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l", + "armv5tejl", "armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l", + "armv5tel", "armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l", + "armv5tl", "armv5tl:armv5l:armv4tl:armv4l:armv3l", "armv5l", "armv5l:armv4tl:armv4l:armv3l", "armv4tl", "armv4tl:armv4l:armv3l", "armv4l", "armv4l:armv3l", - "armv3l", "armv3l", - "sh3", "sh3", - "sh4", "sh4", "sh4a", "sh4a:sh4", "sparc64v", "sparc64v:sparc64:sparcv9v:sparcv9:sparcv8:sparc", "sparc64", "sparc64:sparcv9:sparcv8:sparc", "sparcv9v", "sparcv9v:sparcv9:sparcv8:sparc", "sparcv9", "sparcv9:sparcv8:sparc", "sparcv8", "sparcv8:sparc", - "sparc", "sparc", - "mips", "mips", - "mipsel", "mipsel", - "mips64", "mips64", - "mips64el", "mips64el", - "m68k", "m68k", #if defined(FEDORA) || defined(MAGEIA) "ia32e", "ia32e:x86_64:athlon:i686:i586:i486:i386", "athlon", "athlon:i686:i586:i486:i386", @@ -81,15 +70,13 @@ pool_setarch(Pool *pool, const char *arch) if (arch) { int i; - /* convert arch to known policy */ for (i = 0; archpolicies[i]; i += 2) if (!strcmp(archpolicies[i], arch)) - break; - if (archpolicies[i]) - arch = archpolicies[i + 1]; - else - arch = ""; + { + arch = archpolicies[i + 1]; + break; + } } pool_setarchpolicy(pool, arch); } @@ -121,6 +108,9 @@ pool_setarchpolicy(Pool *pool, const char *arch) } id = pool->noarchid; lastarch = id + 255; + /* note that we overallocate one element to be compatible with + * old versions that accessed id2arch[lastarch]. + * id2arch[lastarch] will always be zero */ id2arch = solv_calloc(lastarch + 1, sizeof(Id)); id2arch[id] = 1; /* the "noarch" class */ @@ -131,7 +121,7 @@ pool_setarchpolicy(Pool *pool, const char *arch) if (l) { id = pool_strn2id(pool, arch, l, 1); - if (id > lastarch) + if (id >= lastarch) { id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id)); memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id)); @@ -160,7 +150,7 @@ pool_arch2color_slow(Pool *pool, Id arch) const char *s; unsigned char color; - if (arch > pool->lastarch) + if ((unsigned int)arch >= (unsigned int)pool->lastarch) return ARCHCOLOR_ALL; if (!pool->id2color) pool->id2color = solv_calloc(pool->lastarch + 1, 1); diff --git a/libsolv-0.6.15/src/poolarch.h b/libsolv-0.7.2/src/poolarch.h similarity index 81% rename from libsolv-0.6.15/src/poolarch.h rename to libsolv-0.7.2/src/poolarch.h index 3fe5f02..787883b 100644 --- a/libsolv-0.6.15/src/poolarch.h +++ b/libsolv-0.7.2/src/poolarch.h @@ -24,7 +24,7 @@ extern unsigned char pool_arch2color_slow(Pool *pool, Id arch); static inline unsigned char pool_arch2color(Pool *pool, Id arch) { - if (arch > pool->lastarch) + if ((unsigned int)arch >= (unsigned int)pool->lastarch) return ARCHCOLOR_ALL; if (pool->id2color && pool->id2color[arch]) return pool->id2color[arch]; @@ -40,6 +40,10 @@ static inline int pool_colormatch(Pool *pool, Solvable *s1, Solvable *s2) return 0; } +static inline unsigned int pool_arch2score(const Pool *pool, Id arch) { + return (unsigned int)arch < (unsigned int)pool->lastarch ? (unsigned int)pool->id2arch[arch] : 0; +} + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/poolid.c b/libsolv-0.7.2/src/poolid.c similarity index 75% rename from libsolv-0.6.15/src/poolid.c rename to libsolv-0.7.2/src/poolid.c index 2138c42..3b55f76 100644 --- a/libsolv-0.6.15/src/poolid.c +++ b/libsolv-0.7.2/src/poolid.c @@ -51,39 +51,58 @@ pool_strn2id(Pool *pool, const char *str, unsigned int len, int create) return id; } +void +pool_resize_rels_hash(Pool *pool, int numnew) +{ + Hashval h, hh, hashmask; + Hashtable hashtbl; + int i; + Reldep *rd; + + if (numnew <= 0) + return; + hashmask = mkmask(pool->nrels + numnew); + if (hashmask <= pool->relhashmask) + return; /* same as before */ + + /* realloc hash table */ + pool->relhashmask = hashmask; + solv_free(pool->relhashtbl); + pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id)); + + /* rehash all rels into new hashtable */ + for (i = 1, rd = pool->rels + i; i < pool->nrels; i++, rd++) + { + h = relhash(rd->name, rd->evr, rd->flags) & hashmask; + hh = HASHCHAIN_START; + while (hashtbl[h]) + h = HASHCHAIN_NEXT(h, hh, hashmask); + hashtbl[h] = i; + } +} + Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create) { Hashval h, hh, hashmask; - int i; Id id; Hashtable hashtbl; Reldep *ran; - hashmask = pool->relhashmask; - hashtbl = pool->relhashtbl; - ran = pool->rels; /* extend hashtable if needed */ + hashmask = pool->relhashmask; if ((Hashval)pool->nrels * 2 > hashmask) { - solv_free(pool->relhashtbl); - pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK); - pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id)); - /* rehash all rels into new hashtable */ - for (i = 1; i < pool->nrels; i++) - { - h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask; - hh = HASHCHAIN_START; - while (hashtbl[h]) - h = HASHCHAIN_NEXT(h, hh, hashmask); - hashtbl[h] = i; - } + pool_resize_rels_hash(pool, REL_BLOCK); + hashmask = pool->relhashmask; } + hashtbl = pool->relhashtbl; /* compute hash and check for match */ h = relhash(name, evr, flags) & hashmask; hh = HASHCHAIN_START; + ran = pool->rels; while ((id = hashtbl[h]) != 0) { if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags) @@ -173,11 +192,13 @@ pool_id2rel(const Pool *pool, Id id) return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags]; #endif case REL_AND: - return " & "; + return pool->disttype == DISTTYPE_RPM ? " and " : " & "; case REL_OR: - return " | "; + return pool->disttype == DISTTYPE_RPM ? " or " : " | "; case REL_WITH: - return " + "; + return pool->disttype == DISTTYPE_RPM ? " with " : " + "; + case REL_WITHOUT: + return pool->disttype == DISTTYPE_RPM ? " without " : " - "; case REL_NAMESPACE: return " NAMESPACE "; /* actually not used in dep2str */ case REL_ARCH: @@ -187,13 +208,17 @@ pool_id2rel(const Pool *pool, Id id) case REL_FILECONFLICT: return " FILECONFLICT "; case REL_COND: - return " IF "; + return pool->disttype == DISTTYPE_RPM ? " if " : " IF "; + case REL_UNLESS: + return pool->disttype == DISTTYPE_RPM ? " unless " : " UNLESS "; case REL_COMPAT: return " compat >= "; case REL_KIND: return " KIND "; case REL_ELSE: - return " ELSE "; + return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE "; + case REL_ERROR: + return " ERROR "; default: break; } @@ -235,9 +260,10 @@ dep2strcpy(const Pool *pool, char *p, Id id, int oldrel) while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); - if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH) - if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH) - if (oldrel != rd->flags) + int rel = rd->flags; + if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_WITHOUT || oldrel == REL_COND || oldrel == REL_UNLESS || oldrel == REL_ELSE || oldrel == -1) + if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_WITHOUT || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) + if ((oldrel != rel || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) && !((oldrel == REL_COND || oldrel == REL_UNLESS) && rel == REL_ELSE)) { *p++ = '('; dep2strcpy(pool, p, rd->name, rd->flags); @@ -286,19 +312,32 @@ pool_dep2str(Pool *pool, Id id) if (!ISRELDEP(id)) return pool->ss.stringspace + pool->ss.strings[id]; p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1); - dep2strcpy(pool, p, id, 0); + dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0); return p; } +static void +pool_free_rels_hash(Pool *pool) +{ + pool->relhashtbl = solv_free(pool->relhashtbl); + pool->relhashmask = 0; +} + void pool_shrink_strings(Pool *pool) { + /* free excessive big hashes */ + if (pool->ss.stringhashmask && pool->ss.stringhashmask > mkmask(pool->ss.nstrings + 8192)) + stringpool_freehash(&pool->ss); stringpool_shrink(&pool->ss); } void pool_shrink_rels(Pool *pool) { + /* free excessive big hashes */ + if (pool->relhashmask && pool->relhashmask > mkmask(pool->nrels + 4096)) + pool_free_rels_hash(pool); pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK); } @@ -307,8 +346,7 @@ void pool_freeidhashes(Pool *pool) { stringpool_freehash(&pool->ss); - pool->relhashtbl = solv_free(pool->relhashtbl); - pool->relhashmask = 0; + pool_free_rels_hash(pool); } /* EOF */ diff --git a/libsolv-0.6.15/src/poolid.h b/libsolv-0.7.2/src/poolid.h similarity index 92% rename from libsolv-0.6.15/src/poolid.h rename to libsolv-0.7.2/src/poolid.h index 2363595..f832ff4 100644 --- a/libsolv-0.6.15/src/poolid.h +++ b/libsolv-0.7.2/src/poolid.h @@ -24,7 +24,7 @@ extern "C" { * Ids with relation */ -typedef struct _Reldep { +typedef struct s_Reldep { Id name; /* "package" */ Id evr; /* "0:42-3" */ int flags; /* operation/relation, see REL_x in pool.h */ @@ -41,6 +41,7 @@ extern const char *pool_dep2str(Pool *pool, Id); /* might alloc tmpspace */ extern void pool_shrink_strings(Pool *pool); extern void pool_shrink_rels(Pool *pool); extern void pool_freeidhashes(Pool *pool); +extern void pool_resize_rels_hash(Pool *pool, int numnew); #ifdef __cplusplus } diff --git a/libsolv-0.6.15/src/poolid_private.h b/libsolv-0.7.2/src/poolid_private.h similarity index 100% rename from libsolv-0.6.15/src/poolid_private.h rename to libsolv-0.7.2/src/poolid_private.h diff --git a/libsolv-0.6.15/src/pooltypes.h b/libsolv-0.7.2/src/pooltypes.h similarity index 88% rename from libsolv-0.6.15/src/pooltypes.h rename to libsolv-0.7.2/src/pooltypes.h index 64a3b87..e1f77b0 100644 --- a/libsolv-0.6.15/src/pooltypes.h +++ b/libsolv-0.7.2/src/pooltypes.h @@ -27,11 +27,11 @@ #define SOLV_FLAG_PREFIX_POOL 4 #define SOLV_FLAG_SIZE_BYTES 8 -struct _Stringpool; -typedef struct _Stringpool Stringpool; +struct s_Stringpool; +typedef struct s_Stringpool Stringpool; -struct _Pool; -typedef struct _Pool Pool; +struct s_Pool; +typedef struct s_Pool Pool; /* identifier for string values */ typedef int Id; /* must be signed!, since negative Id is used in solver rules to denote negation */ diff --git a/libsolv-0.6.15/src/poolvendor.c b/libsolv-0.7.2/src/poolvendor.c similarity index 99% rename from libsolv-0.6.15/src/poolvendor.c rename to libsolv-0.7.2/src/poolvendor.c index ec25f9d..adb84d8 100644 --- a/libsolv-0.6.15/src/poolvendor.c +++ b/libsolv-0.7.2/src/poolvendor.c @@ -5,15 +5,14 @@ * for further information */ -#include -#include -#include - /* we need FNM_CASEFOLD */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include +#include +#include #include #include "pool.h" diff --git a/libsolv-0.6.15/src/poolvendor.h b/libsolv-0.7.2/src/poolvendor.h similarity index 100% rename from libsolv-0.6.15/src/poolvendor.h rename to libsolv-0.7.2/src/poolvendor.h diff --git a/libsolv-0.6.15/src/problems.c b/libsolv-0.7.2/src/problems.c similarity index 81% rename from libsolv-0.6.15/src/problems.c rename to libsolv-0.7.2/src/problems.c index b57d980..2b5cefd 100644 --- a/libsolv-0.6.15/src/problems.c +++ b/libsolv-0.7.2/src/problems.c @@ -24,7 +24,6 @@ #include "evr.h" #include "solverdebug.h" - /**********************************************************************************/ /* a problem is an item on the solver's problem list. It can either be >0, in that @@ -32,10 +31,9 @@ * consisting of multiple job rules. */ -void +static void solver_disableproblem(Solver *solv, Id v) { - Rule *r; int i; Id *jp; @@ -62,30 +60,30 @@ solver_disableproblem(Solver *solv, Id v) return; } solver_disablerule(solv, solv->rules + v); -#if 0 - /* XXX: doesn't work */ - if (v >= solv->updaterules && v < solv->updaterules_end) - { - /* enable feature rule if we disabled the update rule */ - r = solv->rules + (v - solv->updaterules + solv->featurerules); - if (r->p) - solver_enablerule(solv, r); - } -#endif return; } v = -(v + 1); jp = solv->ruletojob.elements; - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++) + if (solv->bestrules_pkg) + { + int ni = solv->bestrules_up - solv->bestrules; + for (i = 0; i < ni; i++) + { + int j = solv->bestrules_pkg[i]; + if (j < 0 && jp[-j - solv->jobrules] == v) + solver_disablerule(solv, solv->rules + solv->bestrules + i); + } + } + for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++) if (*jp == v) - solver_disablerule(solv, r); + solver_disablerule(solv, solv->rules + i); } /*------------------------------------------------------------------- * enableproblem */ -void +static void solver_enableproblem(Solver *solv, Id v) { Rule *r; @@ -133,9 +131,189 @@ solver_enableproblem(Solver *solv, Id v) } v = -(v + 1); jp = solv->ruletojob.elements; - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++) + if (solv->bestrules_pkg) + { + int ni = solv->bestrules_up - solv->bestrules; + for (i = 0; i < ni; i++) + { + int j = solv->bestrules_pkg[i]; + if (j < 0 && jp[-j - solv->jobrules] == v) + solver_enablerule(solv, solv->rules + solv->bestrules + i); + } + } + for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++) if (*jp == v) - solver_enablerule(solv, r); + solver_enablerule(solv, solv->rules + i); +} + + +/*------------------------------------------------------------------- + * turn a problem rule into a problem id by normalizing it + */ +static Id +solver_ruletoproblem(Solver *solv, Id rid) +{ + if (rid >= solv->jobrules && rid < solv->jobrules_end) + rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1); + else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0) + rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1); + else if (rid > solv->infarchrules && rid < solv->infarchrules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[rid].p].name; + while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name) + rid--; + } + else if (rid > solv->duprules && rid < solv->duprules_end) + { + Pool *pool = solv->pool; + Id name = pool->solvables[-solv->rules[rid].p].name; + while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name) + rid--; + } + return rid; +} + +/*------------------------------------------------------------------- + * when the solver runs into a problem, it needs to disable all + * involved non-pkg rules and record the rules for solution + * generation. + */ +void +solver_recordproblem(Solver *solv, Id rid) +{ + Id v = solver_ruletoproblem(solv, rid); + /* return if problem already countains our rule */ + if (solv->problems.count) + { + int i; + for (i = solv->problems.count - 1; i >= 0; i--) + if (solv->problems.elements[i] == 0) /* end of last problem reached? */ + break; + else if (solv->problems.elements[i] == v) + return; + } + queue_push(&solv->problems, v); +} + +/*------------------------------------------------------------------- + * this is called when a problem is solved by disabling a rule. + * It calls disableproblem and then re-enables policy rules + */ +void +solver_fixproblem(Solver *solv, Id rid) +{ + Id v = solver_ruletoproblem(solv, rid); + solver_disableproblem(solv, v); + if (v < 0) + solver_reenablepolicyrules(solv, -v); +} + +/*------------------------------------------------------------------- + * disable a set of problems + */ +void +solver_disableproblemset(Solver *solv, int start) +{ + int i; + for (i = start + 1; i < solv->problems.count - 1; i++) + solver_disableproblem(solv, solv->problems.elements[i]); +} + +/*------------------------------------------------------------------- + * try to fix a problem by auto-uninstalling packages + */ +Id +solver_autouninstall(Solver *solv, int start) +{ + Pool *pool = solv->pool; + int i; + int lastfeature = 0, lastupdate = 0; + Id v; + Id extraflags = -1; + Map *m = 0; + + if (!solv->allowuninstall && !solv->allowuninstall_all) + { + if (!solv->allowuninstallmap.size) + return 0; /* why did we get called? */ + m = &solv->allowuninstallmap; + } + for (i = start + 1; i < solv->problems.count - 1; i++) + { + v = solv->problems.elements[i]; + if (v < 0) + extraflags &= solv->job.elements[-v - 1]; + if (v >= solv->updaterules && v < solv->updaterules_end) + { + Rule *r; + Id p = solv->installed->start + (v - solv->updaterules); + if (m && !MAPTST(m, v - solv->updaterules)) + continue; + if (pool->considered && !MAPTST(pool->considered, p)) + continue; /* do not uninstalled disabled packages */ + if (solv->bestrules_pkg && solv->bestrules_end > solv->bestrules) + { + int j; + for (j = start + 1; j < solv->problems.count - 1; j++) + { + Id vv = solv->problems.elements[j]; + if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_pkg[vv - solv->bestrules] == p) + break; + } + if (j < solv->problems.count - 1) + continue; /* best rule involved, do not uninstall */ + } + /* check if identical to feature rule, we don't like that (except for orphans) */ + r = solv->rules + solv->featurerules + (v - solv->updaterules); + if (!r->p) + { + /* update rule == feature rule */ + if (v > lastfeature) + lastfeature = v; + /* prefer orphaned packages in dup mode */ + if (solv->keep_orphans) + { + r = solv->rules + v; + if (!r->d && !r->w2 && r->p == p) + { + lastfeature = v; + lastupdate = 0; + break; + } + } + continue; + } + if (v > lastupdate) + lastupdate = v; + } + } + if (!lastupdate && !lastfeature) + return 0; + v = lastupdate ? lastupdate : lastfeature; + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling "); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v); + /* should really be solver_fixproblem, but we know v is an update/feature rule */ + solver_disableproblem(solv, v); + if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size) + { + /* add the package to the updatepkgs list, this will automatically turn + * on cleandeps mode */ + Id p = solv->rules[v].p; + if (!solv->cleandeps_updatepkgs) + { + solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue)); + queue_init(solv->cleandeps_updatepkgs); + } + if (p > 0) + { + int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count; + queue_pushunique(solv->cleandeps_updatepkgs, p); + if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt) + solver_disablepolicyrules(solv); + } + } + return v; } @@ -202,7 +380,6 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti queue_empty(refined); if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0) return; - queue_init(&disabled); queue_push(refined, sug); /* re-enable all problem rules with the exception of "sug"(gestion) */ @@ -211,10 +388,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti for (i = 0; problem[i]; i++) if (problem[i] != sug) solver_enableproblem(solv, problem[i]); - if (sug < 0) solver_reenablepolicyrules(solv, -sug); - else if (sug >= solv->updaterules && sug < solv->updaterules_end) + + /* here is where the feature rules come into play: if we disabled an + * update rule, we enable the corresponding feature rule if there is + * one. We do this to make the solver downgrade packages instead of + * deinstalling them */ + if (sug >= solv->updaterules && sug < solv->updaterules_end) { /* enable feature rule */ Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules); @@ -224,11 +405,15 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti enableweakrules(solv); + /* disabled contains all of the rules we disabled in the refinement process */ + queue_init(&disabled); for (;;) { - int njob, nfeature, nupdate, pass; + int nother, nfeature, nupdate, pass; queue_empty(&solv->problems); solver_reset(solv); + /* we set disablerules to zero because we are only interested in + * the first problem and we don't want the solver to disable the problems */ solver_run_sat(solv, 0, 0); if (!solv->problems.count) @@ -237,16 +422,18 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti break; /* great, no more problems */ } disabledcnt = disabled.count; - /* start with 1 to skip over proof index */ - njob = nfeature = nupdate = 0; + nother = nfeature = nupdate = 0; for (pass = 0; pass < 2; pass++) { + /* start with 1 to skip over proof index */ for (i = 1; i < solv->problems.count - 1; i++) { /* ignore solutions in refined */ v = solv->problems.elements[i]; if (v == 0) break; /* end of problem reached */ + if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0) + continue; /* not that one! */ if (sug != v) { /* check if v is in the given problems list @@ -260,14 +447,10 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti } if (v >= solv->featurerules && v < solv->featurerules_end) nfeature++; - else if (v > 0) + else if (v > solv->updaterules && v < solv->updaterules_end) nupdate++; else - { - if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0) - continue; /* not that one! */ - njob++; - } + nother++; queue_push(&disabled, v); } if (disabled.count != disabledcnt) @@ -280,7 +463,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti refined->count = 0; break; } - if (!njob && nupdate && nfeature) + if (!nother && nupdate && nfeature) { /* got only update rules, filter out feature rules */ POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n"); @@ -300,14 +483,14 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti if (!nfeature && v != sug) queue_push(refined, v); /* do not record feature rules */ solver_disableproblem(solv, v); + if (v < 0) + solver_reenablepolicyrules(solv, -v); if (v >= solv->updaterules && v < solv->updaterules_end) { Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules); if (r->p) solver_enablerule(solv, r); /* enable corresponding feature rule */ } - if (v < 0) - solver_reenablepolicyrules(solv, -v); } else { @@ -339,6 +522,7 @@ refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essenti for (i = 0; i < disabled.count; i++) solver_enableproblem(solv, disabled.elements[i]); queue_free(&disabled); + /* reset policy rules */ for (i = 0; problem[i]; i++) solver_enableproblem(solv, problem[i]); @@ -454,13 +638,6 @@ convertsolution(Solver *solv, Id why, Queue *solutionq) return; /* false alarm */ p = solv->installed->start + (why - solv->updaterules); - if (solv->dupmap_all && solv->rules[why].p != p && solv->decisionmap[p] > 0) - { - /* distupgrade case, allow to keep old package */ - queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE); - queue_push(solutionq, p); - return; - } if (solv->decisionmap[p] > 0) return; /* false alarm, turned out we can keep the package */ rr = solv->rules + solv->featurerules + (why - solv->updaterules); @@ -588,17 +765,12 @@ create_solutions(Solver *solv, int probnr, int solidx) { Pool *pool = solv->pool; Queue redoq; - Queue problem, solution, problems_save, branches_save; + Queue problem, solution, problems_save, branches_save, decisionq_reason_save; int i, j, nsol; int essentialok; unsigned int now; int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0; Id extraflags = -1; - int decisioncnt_update; - int decisioncnt_keep; - int decisioncnt_resolve; - int decisioncnt_weak; - int decisioncnt_orphan; now = solv_timems(0); queue_init(&redoq); @@ -610,20 +782,19 @@ create_solutions(Solver *solv, int probnr, int solidx) queue_push(&redoq, solv->decisionq_why.elements[i]); queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]); } - decisioncnt_update = solv->decisioncnt_update; - decisioncnt_keep = solv->decisioncnt_keep; - decisioncnt_resolve = solv->decisioncnt_resolve; - decisioncnt_weak = solv->decisioncnt_weak; - decisioncnt_orphan = solv->decisioncnt_orphan; /* save problems queue */ problems_save = solv->problems; memset(&solv->problems, 0, sizeof(solv->problems)); /* save branches queue */ - branches_save = solv->problems; + branches_save = solv->branches; memset(&solv->branches, 0, sizeof(solv->branches)); + /* save decisionq_reason */ + decisionq_reason_save = solv->decisionq_reason; + memset(&solv->decisionq_reason, 0, sizeof(solv->decisionq_reason)); + /* extract problem from queue */ queue_init(&problem); for (i = solidx + 1; i < solv->solutions.count; i++) @@ -711,11 +882,10 @@ create_solutions(Solver *solv, int probnr, int solidx) solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2]; } queue_free(&redoq); - solv->decisioncnt_update = decisioncnt_update; - solv->decisioncnt_keep = decisioncnt_keep; - solv->decisioncnt_resolve = decisioncnt_resolve; - solv->decisioncnt_weak = decisioncnt_weak; - solv->decisioncnt_orphan = decisioncnt_orphan; + + /* restore decision reasons */ + queue_free(&solv->decisionq_reason); + solv->decisionq_reason = decisionq_reason_save; /* restore problems */ queue_free(&solv->problems); @@ -962,8 +1132,11 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, { if (*reqrp > 0 && r->p < -1) { + Pool *pool = solv->pool; Id op = -solv->rules[*reqrp].p; - if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch) + if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch && + pool->solvables[op].arch != pool->noarchid && + pool->solvables[-r->p].arch != pool->noarchid) continue; /* different arch, skip */ } /* prefer assertions */ @@ -1093,6 +1266,7 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ { Pool *pool = solv->pool; char *s; + Solvable *ss; switch (type) { case SOLVER_RULE_DISTUPGRADE: @@ -1118,6 +1292,12 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0); return "cannot install the best candidate for the job"; case SOLVER_RULE_PKG_NOT_INSTALLABLE: + ss = pool->solvables + source; + if (pool_disabled_solvable(pool, ss)) + return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is disabled"); + if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC && + pool->id2arch && pool_arch2score(pool, ss->arch) == 0) + return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " does not have a compatible architecture"); return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable"); case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP: s = pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0); diff --git a/libsolv-0.7.2/src/problems.h b/libsolv-0.7.2/src/problems.h new file mode 100644 index 0000000..37021e1 --- /dev/null +++ b/libsolv-0.7.2/src/problems.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007-2009, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * problems.h + * + */ + +#ifndef LIBSOLV_PROBLEMS_H +#define LIBSOLV_PROBLEMS_H + +#include "rules.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct s_Solver; + +#define SOLVER_SOLUTION_JOB (0) +#define SOLVER_SOLUTION_DISTUPGRADE (-1) +#define SOLVER_SOLUTION_INFARCH (-2) +#define SOLVER_SOLUTION_BEST (-3) +#define SOLVER_SOLUTION_POOLJOB (-4) + +void solver_recordproblem(struct s_Solver *solv, Id rid); +void solver_fixproblem(struct s_Solver *solv, Id rid); +Id solver_autouninstall(struct s_Solver *solv, int start); +void solver_disableproblemset(struct s_Solver *solv, int start); + +int solver_prepare_solutions(struct s_Solver *solv); + +unsigned int solver_problem_count(struct s_Solver *solv); +Id solver_next_problem(struct s_Solver *solv, Id problem); +unsigned int solver_solution_count(struct s_Solver *solv, Id problem); +Id solver_next_solution(struct s_Solver *solv, Id problem, Id solution); +unsigned int solver_solutionelement_count(struct s_Solver *solv, Id problem, Id solution); +Id solver_solutionelement_internalid(struct s_Solver *solv, Id problem, Id solution); +Id solver_solutionelement_extrajobflags(struct s_Solver *solv, Id problem, Id solution); +Id solver_next_solutionelement(struct s_Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp); + +void solver_take_solutionelement(struct s_Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job); +void solver_take_solution(struct s_Solver *solv, Id problem, Id solution, Queue *job); + +Id solver_findproblemrule(struct s_Solver *solv, Id problem); +void solver_findallproblemrules(struct s_Solver *solv, Id problem, Queue *rules); + +extern const char *solver_problemruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep); +extern const char *solver_problem2str(struct s_Solver *solv, Id problem); +extern const char *solver_solutionelement2str(struct s_Solver *solv, Id p, Id rp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libsolv-0.6.15/src/qsort_r.c b/libsolv-0.7.2/src/qsort_r.c similarity index 100% rename from libsolv-0.6.15/src/qsort_r.c rename to libsolv-0.7.2/src/qsort_r.c diff --git a/libsolv-0.6.15/src/queue.c b/libsolv-0.7.2/src/queue.c similarity index 65% rename from libsolv-0.6.15/src/queue.c rename to libsolv-0.7.2/src/queue.c index 37ea381..6d5e531 100644 --- a/libsolv-0.6.15/src/queue.c +++ b/libsolv-0.7.2/src/queue.c @@ -16,8 +16,17 @@ #include "queue.h" #include "util.h" -#define EXTRA_SPACE 8 -#define EXTRA_SPACE_HEAD 8 +static inline int +queue_extra_space(int size) +{ + if (size < 32) + return 8; + if (size < 64) + return 16; + if (size < 128) + return 32; + return 64; +} void queue_init(Queue *q) @@ -27,19 +36,21 @@ queue_init(Queue *q) } void -queue_init_clone(Queue *t, Queue *s) +queue_init_clone(Queue *target, const Queue *source) { - if (!s->elements) + int extra_space; + if (!source->elements) { - t->alloc = t->elements = 0; - t->count = t->left = 0; + target->alloc = target->elements = 0; + target->count = target->left = 0; return; } - t->alloc = t->elements = solv_malloc2(s->count + EXTRA_SPACE, sizeof(Id)); - if (s->count) - memcpy(t->alloc, s->elements, s->count * sizeof(Id)); - t->count = s->count; - t->left = EXTRA_SPACE; + extra_space = queue_extra_space(source->count); + target->alloc = target->elements = solv_malloc2(source->count + extra_space, sizeof(Id)); + if (source->count) + memcpy(target->alloc, source->elements, source->count * sizeof(Id)); + target->count = source->count; + target->left = extra_space; } void @@ -60,19 +71,13 @@ queue_free(Queue *q) q->count = q->left = 0; } +/* make room for one element at the tail of the queue */ void queue_alloc_one(Queue *q) { - if (!q->alloc) - { - q->alloc = solv_malloc2(q->count + EXTRA_SPACE, sizeof(Id)); - if (q->count) - memcpy(q->alloc, q->elements, q->count * sizeof(Id)); - q->elements = q->alloc; - q->left = EXTRA_SPACE; - } - else if (q->alloc != q->elements) + if (q->alloc && q->alloc != q->elements) { + /* there's room at the front. just move data */ int l = q->elements - q->alloc; if (q->count) memmove(q->alloc, q->elements, q->count * sizeof(Id)); @@ -81,8 +86,17 @@ queue_alloc_one(Queue *q) } else { - q->elements = q->alloc = solv_realloc2(q->alloc, q->count + EXTRA_SPACE, sizeof(Id)); - q->left = EXTRA_SPACE; + int extra_space = queue_extra_space(q->count); + if (!q->alloc) + { + q->alloc = solv_malloc2(q->count + extra_space, sizeof(Id)); + if (q->count) + memcpy(q->alloc, q->elements, q->count * sizeof(Id)); + } + else + q->alloc = solv_realloc2(q->alloc, q->count + extra_space, sizeof(Id)); + q->elements = q->alloc; + q->left = extra_space; } } @@ -90,10 +104,11 @@ queue_alloc_one(Queue *q) void queue_alloc_one_head(Queue *q) { - int l; + int l, extra_space; if (!q->alloc || !q->left) - queue_alloc_one(q); - l = q->left > EXTRA_SPACE_HEAD ? EXTRA_SPACE_HEAD : q->left; + queue_alloc_one(q); /* easy way to make room */ + extra_space = queue_extra_space(q->count); + l = q->left > extra_space ? extra_space : q->left; if (q->count) memmove(q->elements + l, q->elements, q->count * sizeof(Id)); q->elements += l; @@ -153,22 +168,14 @@ queue_delete2(Queue *q, int pos) } void -queue_insertn(Queue *q, int pos, int n, Id *elements) +queue_insertn(Queue *q, int pos, int n, const Id *elements) { if (n <= 0) return; if (pos > q->count) pos = q->count; if (q->left < n) - { - int off; - if (!q->alloc) - queue_alloc_one(q); - off = q->elements - q->alloc; - q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id)); - q->elements = q->alloc + off; - q->left = n + EXTRA_SPACE; - } + queue_prealloc(q, n); if (pos < q->count) memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id)); if (elements) @@ -192,18 +199,19 @@ queue_deleten(Queue *q, int pos, int n) q->count -= n; } -/* allocate room for n more elements */ +/* pre-allocate room for n more elements */ void queue_prealloc(Queue *q, int n) { - int off; + int off, extra_space; if (n <= 0 || q->left >= n) return; if (!q->alloc) queue_alloc_one(q); off = q->elements - q->alloc; - q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id)); + extra_space = queue_extra_space(q->count + n); + q->alloc = solv_realloc2(q->alloc, off + q->count + n + extra_space, sizeof(Id)); q->elements = q->alloc + off; - q->left = n + EXTRA_SPACE; + q->left = n + extra_space; } diff --git a/libsolv-0.6.15/src/queue.h b/libsolv-0.7.2/src/queue.h similarity index 93% rename from libsolv-0.6.15/src/queue.h rename to libsolv-0.7.2/src/queue.h index 4785e67..8b1ef08 100644 --- a/libsolv-0.6.15/src/queue.h +++ b/libsolv-0.7.2/src/queue.h @@ -19,7 +19,7 @@ extern "C" { #endif -typedef struct _Queue { +typedef struct s_Queue { Id *elements; /* pointer to elements */ int count; /* current number of elements in queue */ Id *alloc; /* this is whats actually allocated, elements > alloc if shifted */ @@ -109,12 +109,12 @@ queue_truncate(Queue *q, int n) extern void queue_init(Queue *q); extern void queue_init_buffer(Queue *q, Id *buf, int size); -extern void queue_init_clone(Queue *t, Queue *s); +extern void queue_init_clone(Queue *target, const Queue *source); extern void queue_free(Queue *q); extern void queue_insert(Queue *q, int pos, Id id); extern void queue_insert2(Queue *q, int pos, Id id1, Id id2); -extern void queue_insertn(Queue *q, int pos, int n, Id *elements); +extern void queue_insertn(Queue *q, int pos, int n, const Id *elements); extern void queue_delete(Queue *q, int pos); extern void queue_delete2(Queue *q, int pos); extern void queue_deleten(Queue *q, int pos, int n); diff --git a/libsolv-0.6.15/src/repo.c b/libsolv-0.7.2/src/repo.c similarity index 76% rename from libsolv-0.6.15/src/repo.c rename to libsolv-0.7.2/src/repo.c index 15e7e80..d163f13 100644 --- a/libsolv-0.6.15/src/repo.c +++ b/libsolv-0.7.2/src/repo.c @@ -666,241 +666,18 @@ repo_reserve_ids(Repo *repo, Offset olddeps, int num) /***********************************************************************/ -/* - * some SUSE specific fixups, should go into a separate file - */ - -Offset -repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens) -{ - Pool *pool = repo->pool; - Id id, idp, idl; - char buf[1024], *p, *dep; - int i, l; - - if (provides) - { - for (i = provides; repo->idarraydata[i]; i++) - { - id = repo->idarraydata[i]; - if (ISRELDEP(id)) - continue; - dep = (char *)pool_id2str(pool, id); - if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2) - { - idp = 0; - strcpy(buf + 2, dep); - dep = buf + 2 + 7; - if ((p = strchr(dep, ':')) != 0 && p != dep) - { - *p++ = 0; - idp = pool_str2id(pool, dep, 1); - dep = p; - } - id = 0; - while ((p = strchr(dep, ';')) != 0) - { - if (p == dep) - { - dep = p + 1; - continue; - } - *p++ = 0; - idl = pool_str2id(pool, dep, 1); - idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); - if (id) - id = pool_rel2id(pool, id, idl, REL_OR, 1); - else - id = idl; - dep = p; - } - if (dep[0] && dep[1]) - { - for (p = dep; *p && *p != ')'; p++) - ; - *p = 0; - idl = pool_str2id(pool, dep, 1); - idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); - if (id) - id = pool_rel2id(pool, id, idl, REL_OR, 1); - else - id = idl; - } - if (idp) - id = pool_rel2id(pool, idp, id, REL_AND, 1); - if (id) - supplements = repo_addid_dep(repo, supplements, id, 0); - } - else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf)) - { - strcpy(buf, dep); - p = buf + (p - dep); - *p++ = 0; - idp = pool_str2id(pool, buf, 1); - /* strip trailing slashes */ - l = strlen(p); - while (l > 1 && p[l - 1] == '/') - p[--l] = 0; - id = pool_str2id(pool, p, 1); - id = pool_rel2id(pool, idp, id, REL_WITH, 1); - id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1); - supplements = repo_addid_dep(repo, supplements, id, 0); - } - } - } - if (supplements) - { - for (i = supplements; repo->idarraydata[i]; i++) - { - id = repo->idarraydata[i]; - if (ISRELDEP(id)) - continue; - dep = (char *)pool_id2str(pool, id); - if (!strncmp(dep, "system:modalias(", 16)) - dep += 7; - if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf)) - { - strcpy(buf, dep); - p = strchr(buf + 9, ':'); - if (p && p != buf + 9 && strchr(p + 1, ':')) - { - *p++ = 0; - idp = pool_str2id(pool, buf + 9, 1); - p[strlen(p) - 1] = 0; - id = pool_str2id(pool, p, 1); - id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); - id = pool_rel2id(pool, idp, id, REL_AND, 1); - } - else - { - p = buf + 9; - p[strlen(p) - 1] = 0; - id = pool_str2id(pool, p, 1); - id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); - } - if (id) - repo->idarraydata[i] = id; - } - else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf)) - { - strcpy(buf, dep); - id = 0; - dep = buf + 11; - while ((p = strchr(dep, ':')) != 0) - { - if (p == dep) - { - dep = p + 1; - continue; - } - /* argh, allow pattern: prefix. sigh */ - if (p - dep == 7 && !strncmp(dep, "pattern", 7)) - { - p = strchr(p + 1, ':'); - if (!p) - break; - } - *p++ = 0; - idp = pool_str2id(pool, dep, 1); - if (id) - id = pool_rel2id(pool, id, idp, REL_AND, 1); - else - id = idp; - dep = p; - } - if (dep[0] && dep[1]) - { - dep[strlen(dep) - 1] = 0; - idp = pool_str2id(pool, dep, 1); - if (id) - id = pool_rel2id(pool, id, idp, REL_AND, 1); - else - id = idp; - } - if (id) - repo->idarraydata[i] = id; - } - else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf)) - { - strcpy(buf, dep + 11); - if ((p = strrchr(buf, ')')) != 0) - *p = 0; - id = pool_str2id(pool, buf, 1); - id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1); - repo->idarraydata[i] = id; - } - } - } - if (freshens && repo->idarraydata[freshens]) - { - Id idsupp = 0, idfresh = 0; - if (!supplements || !repo->idarraydata[supplements]) - return freshens; - for (i = supplements; repo->idarraydata[i]; i++) - { - if (!idsupp) - idsupp = repo->idarraydata[i]; - else - idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1); - } - for (i = freshens; repo->idarraydata[i]; i++) - { - if (!idfresh) - idfresh = repo->idarraydata[i]; - else - idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1); - } - if (!idsupp) - idsupp = idfresh; - else - idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1); - supplements = repo_addid_dep(repo, 0, idsupp, 0); - } - return supplements; -} - -Offset -repo_fix_conflicts(Repo *repo, Offset conflicts) -{ - char buf[1024], *p, *dep; - Pool *pool = repo->pool; - Id id; - int i; - - if (!conflicts) - return conflicts; - for (i = conflicts; repo->idarraydata[i]; i++) - { - id = repo->idarraydata[i]; - if (ISRELDEP(id)) - continue; - dep = (char *)pool_id2str(pool, id); - if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2) - { - strcpy(buf, dep + 15); - if ((p = strchr(buf, ')')) != 0) - *p = 0; - id = pool_str2id(pool, buf, 1); - id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1); - repo->idarraydata[i] = id; - } - } - return conflicts; -} - -/***********************************************************************/ - struct matchdata { Pool *pool; int flags; Datamatcher matcher; int stop; + Id *keyskip; int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv); void *callback_data; }; -int +static int repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) { struct matchdata *md = cbdata; @@ -916,6 +693,12 @@ repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValu if (!datamatcher_match(&md->matcher, str)) return 0; } + else + { + /* stringify filelist if requested */ + if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0) + repodata_stringify(md->pool, data, key, kv, md->flags); + } md->stop = md->callback(md->callback_data, s, data, key, kv); return md->stop; } @@ -960,8 +743,9 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) KeyValue kv; Pool *pool = repo->pool; Repodata *data; - int i, j, flags; + int i, flags; Solvable *s; + Id *keyskip; kv.parent = 0; md->stop = 0; @@ -976,12 +760,10 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) } return; } - else if (p < 0) - /* The callback only supports solvables, so we can't iterate over the - extra things. */ - return; + if (p < 0 && p != SOLVID_META) + return; /* SOLVID_POS not supported yet */ flags = md->flags; - if (!(flags & SEARCH_NO_STORAGE_SOLVABLE)) + if (p > 0 && !(flags & SEARCH_NO_STORAGE_SOLVABLE)) { s = pool->solvables + p; switch(keyname) @@ -1074,42 +856,23 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) } } + if (keyname) + { + if (keyname == SOLVABLE_FILELIST) + data = repo_lookup_filelist_repodata(repo, p, &md->matcher); + else + data = repo_lookup_repodata_opt(repo, p, keyname); + if (data) + repodata_search(data, p, keyname, md->flags, repo_matchvalue, md); + return; + } + + keyskip = repo_create_keyskip(repo, p, &md->keyskip); FOR_REPODATAS(repo, i, data) { - if (p < data->start || p >= data->end) - continue; - if (keyname && !repodata_precheck_keyname(data, keyname)) - continue; - if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST)) - { - /* do not search filelist extensions */ - if (data->state != REPODATA_AVAILABLE) - continue; - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - break; - if (j == data->nkeys) - continue; - } - if (data->state == REPODATA_STUB) - { - if (keyname) - { - for (j = 1; j < data->nkeys; j++) - if (keyname == data->keys[j].name) - break; - if (j == data->nkeys) - continue; - } - /* load it */ - if (data->loadcallback) - data->loadcallback(data); - else - data->state = REPODATA_ERROR; - } - if (data->state == REPODATA_ERROR) + if (p != SOLVID_META && (p < data->start || p >= data->end)) continue; - repodata_search(data, p, keyname, md->flags, repo_matchvalue, md); + repodata_search_keyskip(data, p, keyname, md->flags, keyskip, repo_matchvalue, md); if (md->stop > SEARCH_NEXT_KEY) break; } @@ -1132,18 +895,181 @@ repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*ca repo_search_md(repo, p, keyname, &md); if (match) datamatcher_free(&md.matcher); + solv_free(md.keyskip); +} + +Repodata * +repo_lookup_repodata(Repo *repo, Id entry, Id keyname) +{ + Repodata *data; + int rdid; + Id type; + + if (entry == SOLVID_POS) + { + Pool *pool = repo->pool; + return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0; + } + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) + { + if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) + continue; + if (!repodata_precheck_keyname(data, keyname)) + continue; + if ((type = repodata_lookup_type(data, entry, keyname)) != 0) + return type == REPOKEY_TYPE_DELETED ? 0 : data; + } + return 0; +} + +/* like repo_lookup_repodata, but may return a repodata that contains no match instead of NULL */ +Repodata * +repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname) +{ + Repodata *data, *found = 0; + int rdid; + Id type; + + if (entry == SOLVID_POS) + { + Pool *pool = repo->pool; + return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0; + } + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) + { + if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) + continue; + if (!repodata_precheck_keyname(data, keyname)) + continue; + if (found && (type = repodata_lookup_type(found, entry, keyname)) != 0) + return type == REPOKEY_TYPE_DELETED ? 0 : found; + found = data; + } + return found; +} + +Repodata * +repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher) +{ + Repodata *data; + int haveextension; + int rdid; + Id type; + + if (entry <= 0 || !matcher || !matcher->match || ((matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING + && (matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)) + return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST); /* cannot use filtered filelist */ + + haveextension = 0; + for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--) + { + if (entry < data->start || entry >= data->end) + continue; + if (data->filelisttype == REPODATA_FILELIST_FILTERED) + { + if (data->state != REPODATA_AVAILABLE) + { + if (data->state != REPODATA_STUB) + continue; + repodata_load(data); + if (data->state != REPODATA_AVAILABLE || entry < data->start || entry >= data->end) + continue; + } + /* does this contain any data about the solvable we're looking for? */ + if (!data->incoreoffset[entry - data->start]) + continue; /* no, ignore */ + if (haveextension && repodata_filelistfilter_matches(data, matcher->match)) + return data; + break; /* fall back to normal code */ + } + if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) + continue; + if (data->filelisttype == REPODATA_FILELIST_EXTENSION) + { + haveextension++; + continue; + } + if ((type = repodata_lookup_type(data, entry, SOLVABLE_FILELIST)) != 0) + { + if (haveextension) + break; /* need to look in extension */ + return type == REPOKEY_TYPE_DELETED ? 0 : data; + } + } + /* cannot use filtered filelist */ + return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST); +} + + +/* the keyskip array has the following format: + * 0: keyname area size + * 1: repoid base + * 2: repoid end + * 3: entry for keyname 0 + * 4: entry for keyname 1 + * ... + */ +Id * +repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip) +{ + Repodata *data, *last = 0; + Id *keyskip; + int rdid, cnt = 0; + + if (repo->nrepodata <= 2) + return 0; /* just one repodata, nothing to filter */ + keyskip = oldkeyskip ? *oldkeyskip : 0; + if (keyskip) + { + if (keyskip[1] >= 0x10000000) + keyskip = solv_free(keyskip); + else + keyskip[1] = keyskip[2]; + } + FOR_REPODATAS(repo, rdid, data) + { + if (entry != SOLVID_META) + { + if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING) + { + if (data->state != REPODATA_STUB) + continue; + repodata_load(data); + if (data->state != REPODATA_AVAILABLE) + continue; + } + if ((entry < data->start || entry >= data->end)) + continue; + if (!data->incoreoffset[entry - data->start]) + continue; + } + if (last) + keyskip = repodata_fill_keyskip(last, entry, keyskip); + last = data; + cnt++; + } + if (cnt <= 1) + { + if (oldkeyskip) + *oldkeyskip = keyskip; + return 0; + } + keyskip = repodata_fill_keyskip(last, entry, keyskip); + if (keyskip) + keyskip[2] = keyskip[1] + repo->nrepodata; + if (oldkeyskip) + *oldkeyskip = keyskip; + return keyskip; } const char * repo_lookup_str(Repo *repo, Id entry, Id keyname) { - Pool *pool = repo->pool; Repodata *data; - int i; - const char *str; if (entry >= 0) { + Pool *pool = repo->pool; switch (keyname) { case SOLVABLE_NAME: @@ -1156,31 +1082,15 @@ repo_lookup_str(Repo *repo, Id entry, Id keyname) return pool_id2str(pool, pool->solvables[entry].vendor); } } - else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname); - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - str = repodata_lookup_str(data, entry, keyname); - if (str) - return str; - if (repodata_lookup_type(data, entry, keyname)) - return 0; - } - return 0; + data = repo_lookup_repodata_opt(repo, entry, keyname); + return data ? repodata_lookup_str(data, entry, keyname) : 0; } unsigned long long repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound) { - Pool *pool = repo->pool; Repodata *data; - int i; - unsigned long long value; if (entry >= 0) { @@ -1191,28 +1101,14 @@ repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound) return notfound; } } - else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, &value) ? value : notfound; - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - if (repodata_lookup_num(data, entry, keyname, &value)) - return value; - if (repodata_lookup_type(data, entry, keyname)) - return notfound; - } - return notfound; + data = repo_lookup_repodata_opt(repo, entry, keyname); + return data ? repodata_lookup_num(data, entry, keyname, notfound) : notfound; } Id repo_lookup_id(Repo *repo, Id entry, Id keyname) { - Pool *pool = repo->pool; Repodata *data; - int i; Id id; if (entry >= 0) @@ -1229,24 +1125,9 @@ repo_lookup_id(Repo *repo, Id entry, Id keyname) return repo->pool->solvables[entry].vendor; } } - else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - { - Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid; - Id id = repodata_lookup_id(data, entry, keyname); - return data->localpool ? repodata_globalize_id(data, id, 1) : id; - } - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - id = repodata_lookup_id(data, entry, keyname); - if (id) - return data->localpool ? repodata_globalize_id(data, id, 1) : id; - if (repodata_lookup_type(data, entry, keyname)) - return 0; - } + data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data && (id = repodata_lookup_id(data, entry, keyname)) != 0) + return data->localpool ? repodata_globalize_id(data, id, 1) : id; return 0; } @@ -1265,7 +1146,6 @@ lookup_idarray_solvable(Repo *repo, Offset off, Queue *q) int repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q) { - Pool *pool = repo->pool; Repodata *data; int i; if (entry >= 0) @@ -1290,36 +1170,15 @@ repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q) return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q); } } - else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - { - Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid; - if (repodata_lookup_idarray(data, entry, keyname, q)) - { - if (data->localpool) - { - for (i = 0; i < q->count; i++) - q->elements[i] = repodata_globalize_id(data, q->elements[i], 1); - } - return 1; - } - } - FOR_REPODATAS(repo, i, data) + data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data && repodata_lookup_idarray(data, entry, keyname, q)) { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - if (repodata_lookup_idarray(data, entry, keyname, q)) + if (data->localpool) { - if (data->localpool) - { - for (i = 0; i < q->count; i++) - q->elements[i] = repodata_globalize_id(data, q->elements[i], 1); - } - return 1; + for (i = 0; i < q->count; i++) + q->elements[i] = repodata_globalize_id(data, q->elements[i], 1); } - if (repodata_lookup_type(data, entry, keyname)) - break; + return 1; } queue_empty(q); return 0; @@ -1363,25 +1222,10 @@ repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker) const unsigned char * repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep) { - Pool *pool = repo->pool; - Repodata *data; - int i; const unsigned char *chk; - - if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, typep); - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - chk = repodata_lookup_bin_checksum(data, entry, keyname, typep); - if (chk) - return chk; - if (repodata_lookup_type(data, entry, keyname)) - return 0; - } + Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data && (chk = repodata_lookup_bin_checksum(data, entry, keyname, typep)) != 0) + return chk; *typep = 0; return 0; } @@ -1396,69 +1240,29 @@ repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep) int repo_lookup_void(Repo *repo, Id entry, Id keyname) { - Pool *pool = repo->pool; - Repodata *data; - int i; - Id type; - - if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname); - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - type = repodata_lookup_type(data, entry, keyname); - if (type) - return type == REPOKEY_TYPE_VOID; - } + Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data) + return repodata_lookup_void(data, entry, keyname); return 0; } Id repo_lookup_type(Repo *repo, Id entry, Id keyname) { - Pool *pool = repo->pool; - Repodata *data; - int i; Id type; - - if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_type(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname); - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - type = repodata_lookup_type(data, entry, keyname); - if (type) - return type == REPOKEY_TYPE_DELETED ? 0 : type; - } + Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data && (type = repodata_lookup_type(data, entry, keyname)) != 0 && type != REPOKEY_TYPE_DELETED) + return type; return 0; } const void * repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp) { - Pool *pool = repo->pool; - Repodata *data; - int i; const void *bin; - - if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid) - return repodata_lookup_binary(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, lenp); - FOR_REPODATAS(repo, i, data) - { - if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) - continue; - if (!repodata_precheck_keyname(data, keyname)) - continue; - bin = repodata_lookup_binary(data, entry, keyname, lenp); - if (bin) - return bin; - } + Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname); + if (data && (bin = repodata_lookup_binary(data, entry, keyname, lenp)) != 0) + return bin; *lenp = 0; return 0; } diff --git a/libsolv-0.6.15/src/repo.h b/libsolv-0.7.2/src/repo.h similarity index 86% rename from libsolv-0.6.15/src/repo.h rename to libsolv-0.7.2/src/repo.h index 952dbeb..58704f1 100644 --- a/libsolv-0.6.15/src/repo.h +++ b/libsolv-0.7.2/src/repo.h @@ -15,6 +15,7 @@ #include "pooltypes.h" #include "pool.h" +#include "poolarch.h" #include "repodata.h" #include "dataiterator.h" #include "hash.h" @@ -23,7 +24,7 @@ extern "C" { #endif -typedef struct _Repo { +typedef struct s_Repo { const char *name; /* name pointer */ Id repoid; /* our id */ void *appdata; /* application private pointer */ @@ -72,8 +73,6 @@ extern Id repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo extern Offset repo_addid(Repo *repo, Offset olddeps, Id id); extern Offset repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker); extern Offset repo_reserve_ids(Repo *repo, Offset olddeps, int num); -extern Offset repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens); -extern Offset repo_fix_conflicts(Repo *repo, Offset conflicts); static inline const char *repo_name(const Repo *repo) { @@ -100,13 +99,20 @@ static inline int pool_disabled_solvable(const Pool *pool, Solvable *s) return 0; } +static inline int pool_badarch_solvable(const Pool *pool, Solvable *s) +{ + if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0)) + return 1; + return 0; +} + static inline int pool_installable(const Pool *pool, Solvable *s) { - if (!s->arch || s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) return 0; if (s->repo && s->repo->disabled) return 0; - if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch])) + if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0)) return 0; if (pool->considered) { @@ -117,6 +123,14 @@ static inline int pool_installable(const Pool *pool, Solvable *s) return 1; } +/* not in solvable.h because we need the repo definition */ +static inline Solvable *solvable_free(Solvable *s, int reuseids) +{ + if (s && s->repo) + repo_free_solvable(s->repo, s - s->repo->pool->solvables, reuseids); + return 0; +} + /* search callback values */ #define SEARCH_NEXT_KEY 1 #define SEARCH_NEXT_SOLVABLE 2 @@ -138,6 +152,11 @@ Repodata *repo_last_repodata(Repo *repo); void repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata); +/* returns the last repodata that contains the key */ +Repodata *repo_lookup_repodata(Repo *repo, Id entry, Id keyname); +Repodata *repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname); +Repodata *repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher); + /* returns the string value of the attribute, or NULL if not found */ Id repo_lookup_type(Repo *repo, Id entry, Id keyname); const char *repo_lookup_str(Repo *repo, Id entry, Id keyname); @@ -165,6 +184,8 @@ void repo_unset(Repo *repo, Id p, Id keyname); void repo_internalize(Repo *repo); void repo_disable_paging(Repo *repo); +Id *repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip); + /* iterator macros */ #define FOR_REPO_SOLVABLES(r, p, s) \ @@ -181,6 +202,11 @@ void repo_disable_paging(Repo *repo); for (rdid = 1; rdid < repo->nrepodata && (data = repo_id2repodata(repo, rdid)); rdid++) #endif +/* weird suse stuff, do not use */ +extern Offset repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens); +extern Offset repo_fix_conflicts(Repo *repo, Offset conflicts); +extern void repo_rewrite_suse_deps(Solvable *s, Offset freshens); + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/repo_solv.c b/libsolv-0.7.2/src/repo_solv.c similarity index 93% rename from libsolv-0.6.15/src/repo_solv.c rename to libsolv-0.7.2/src/repo_solv.c index 86c851c..be33967 100644 --- a/libsolv-0.6.15/src/repo_solv.c +++ b/libsolv-0.7.2/src/repo_solv.c @@ -223,7 +223,7 @@ data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *da data->error = SOLV_ERROR_ID_RANGE; break; } - *store++ = x; + *store++ = map ? map[x] : x; if ((c & 64) == 0) break; x = 0; @@ -478,7 +478,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) int oldnstrings = pool->ss.nstrings; int oldnrels = pool->nrels; - struct _Stringpool *spool; + struct s_Stringpool *spool; Repodata *parent = 0; Repodata data; @@ -612,7 +612,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) unsigned int pfsize = read_u32(&data); char *prefix = solv_malloc(pfsize); char *pp = prefix; - char *old_str = 0; + char *old_str = strsp; char *dest = strsp; int freesp = sizeid; @@ -682,35 +682,16 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) /* alloc id map for name and rel Ids. this maps ids in the solv files * to the ids in our pool */ idmap = solv_calloc(numid + numrel, sizeof(Id)); - - /* grow hash if needed, otherwise reuse */ - hashmask = mkmask(spool->nstrings + numid); + stringpool_resize_hash(spool, numid); + hashtbl = spool->stringhashtbl; + hashmask = spool->stringhashmask; #if 0 POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid); - POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d, old %d\n", hashmask + 1, spool->stringhashmask + 1); + POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1); #endif - if (hashmask > spool->stringhashmask) - { - spool->stringhashtbl = solv_free(spool->stringhashtbl); - spool->stringhashmask = hashmask; - spool->stringhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id)); - for (i = 1; i < spool->nstrings; i++) - { - h = strhash(spool->stringspace + spool->strings[i]) & hashmask; - hh = HASHCHAIN_START; - while (hashtbl[h]) - h = HASHCHAIN_NEXT(h, hh, hashmask); - hashtbl[h] = i; - } - } - else - { - hashtbl = spool->stringhashtbl; - hashmask = spool->stringhashmask; - } - /* * run over strings and merge with pool. + * we could use stringpool_str2id, but this is faster. * also populate id map (maps solv Id -> pool Id) */ for (i = 1; i < numid; i++) @@ -758,11 +739,6 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) idmap[i] = id; /* repo relative -> pool relative */ sp += l; /* next string */ } - if (hashmask > mkmask(spool->nstrings + 8192)) - { - spool->stringhashtbl = solv_free(spool->stringhashtbl); - spool->stringhashmask = 0; - } stringpool_shrink(spool); /* vacuum */ } @@ -780,31 +756,13 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep)); ran = pool->rels; - /* grow hash if needed, otherwise reuse */ - hashmask = mkmask(pool->nrels + numrel); + pool_resize_rels_hash(pool, numrel); + hashtbl = pool->relhashtbl; + hashmask = pool->relhashmask; #if 0 POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel); - POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d, old %d\n", hashmask + 1, pool->relhashmask + 1); + POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1); #endif - if (hashmask > pool->relhashmask) - { - pool->relhashtbl = solv_free(pool->relhashtbl); - pool->relhashmask = hashmask; - pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id)); - for (i = 1; i < pool->nrels; i++) - { - h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask; - hh = HASHCHAIN_START; - while (hashtbl[h]) - h = HASHCHAIN_NEXT(h, hh, hashmask); - hashtbl[h] = i; - } - } - else - { - hashtbl = pool->relhashtbl; - hashmask = pool->relhashmask; - } /* * read RelDeps from repo @@ -837,11 +795,6 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) } idmap[i + numid] = MAKERELDEP(id); /* fill Id map */ } - if (hashmask > mkmask(pool->nrels + 4096)) - { - pool->relhashtbl = solv_free(pool->relhashtbl); - pool->relhashmask = 0; - } pool_shrink_rels(pool); /* vacuum */ } @@ -873,11 +826,20 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) { id = read_id(&data, i + numid); if (id >= numid) - data.dirpool.dirs[i] = -(id - numid); - else if (idmap) - data.dirpool.dirs[i] = idmap[id]; - else - data.dirpool.dirs[i] = id; + { + data.dirpool.dirs[i++] = -(id - numid); + if (i >= numdir) + { + data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "last dir entry is not a component"); + break; + } + id = read_id(&data, numid); + } + if (idmap) + id = idmap[id]; + data.dirpool.dirs[i] = id; + if (id <= 0) + data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "bad dir component"); } } @@ -897,7 +859,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) type = idmap[type]; else if ((flags & REPO_LOCALPOOL) != 0) type = pool_str2id(pool, stringpool_id2str(spool, type), 1); - if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_FLEXARRAY) + if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_DELETED) { data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type)); type = REPOKEY_TYPE_VOID; @@ -917,6 +879,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags) data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage); keys[i].storage = KEY_STORAGE_SOLVABLE; } + if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && keys[i].storage != KEY_STORAGE_INCORE) + data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n"); /* cannot handle rel idarrays in incore/vertical */ if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE) data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE"); @@ -1254,12 +1218,9 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key } /* FALLTHROUGH */ default: - if (id == RPM_RPMDBID && s && (keys[key].type == REPOKEY_TYPE_U32 || keys[key].type == REPOKEY_TYPE_NUM)) + if (id == RPM_RPMDBID && s && keys[key].type == REPOKEY_TYPE_NUM) { - if (keys[key].type == REPOKEY_TYPE_U32) - dp = data_read_u32(dp, (unsigned int *)&id); - else - dp = data_read_id_max(dp, &id, 0, 0, &data); + dp = data_read_id_max(dp, &id, 0, 0, &data); if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); repo->rpmdbid[(s - pool->solvables) - repo->start] = id; @@ -1308,7 +1269,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key keys[i].type = REPOKEY_TYPE_IDARRAY; for (i = 1; i < numkeys; i++) - if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET) + if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size) break; if (i < numkeys && !data.error) { @@ -1348,6 +1309,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key /* overwrite stub repodata */ repodata_freedata(parent); data.repodataid = parent->repodataid; + data.loadcallback = parent->loadcallback; *parent = data; } else @@ -1364,6 +1326,17 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key repo->repodata[repo->nrepodata++] = data; } + if ((flags & REPO_EXTEND_SOLVABLES) != 0) + { + if (repodata_has_keyname(&data, SOLVABLE_FILELIST)) + repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_EXTENSION); + } + else + { + if (repodata_lookup_type(&data, SOLVID_META, REPOSITORY_FILTEREDFILELIST)) + repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_FILTERED); + } + /* create stub repodata entries for all external */ if (!(flags & SOLV_ADD_NO_STUBS) && !parent) { @@ -1371,7 +1344,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY) break; if (key < data.nkeys) - repodata_create_stubs(repo->repodata + (repo->nrepodata - 1)); + repodata_create_stubs(repo->repodata + data.repodataid); } POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now)); diff --git a/libsolv-0.6.15/src/repo_solv.h b/libsolv-0.7.2/src/repo_solv.h similarity index 100% rename from libsolv-0.6.15/src/repo_solv.h rename to libsolv-0.7.2/src/repo_solv.h diff --git a/libsolv-0.6.15/src/repo_write.c b/libsolv-0.7.2/src/repo_write.c similarity index 57% rename from libsolv-0.6.15/src/repo_write.c rename to libsolv-0.7.2/src/repo_write.c index 210636c..d3b8a83 100644 --- a/libsolv-0.6.15/src/repo_write.c +++ b/libsolv-0.7.2/src/repo_write.c @@ -38,7 +38,7 @@ typedef struct needid { } NeedId; -#define RELOFF(id) (needid[0].map + GETRELID(id)) +#define NEEDIDOFF(id) (ISRELDEP(id) ? (needid[0].map + GETRELID(id)) : id) /* * increment need Id @@ -49,44 +49,22 @@ typedef struct needid { * */ -static void -incneedid(Pool *pool, Id id, NeedId *needid) +static inline void +incneedid(Id id, NeedId *needid) { - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - needid[RELOFF(id)].need++; - if (ISRELDEP(rd->evr)) - incneedid(pool, rd->evr, needid); - else - needid[rd->evr].need++; - id = rd->name; - } - needid[id].need++; + needid[NEEDIDOFF(id)].need++; } static int -incneedidarray(Pool *pool, Id *idarray, NeedId *needid) +incneedidarray(Id *idarray, NeedId *needid) { Id id; int n = 0; - if (!idarray) - return 0; while ((id = *idarray++) != 0) { n++; - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - needid[RELOFF(id)].need++; - if (ISRELDEP(rd->evr)) - incneedid(pool, rd->evr, needid); - else - needid[rd->evr].need++; - id = rd->name; - } - needid[id].need++; + needid[NEEDIDOFF(id)].need++; } return n + 1; } @@ -248,7 +226,7 @@ write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids) { id = *ids++; if (needid) - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + id = needid[NEEDIDOFF(id)].need; if (id >= 64) id = (id & 63) | ((id & ~63) << 1); if (!*ids) @@ -260,129 +238,27 @@ write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids) } } -static int -cmp_ids(const void *pa, const void *pb, void *dp) -{ - Id a = *(Id *)pa; - Id b = *(Id *)pb; - return a - b; -} - -#if 0 -static void -write_idarray_sort(Repodata *data, Pool *pool, NeedId *needid, Id *ids, Id marker) -{ - int len, i; - Id lids[64], *sids; - - if (!ids) - return; - if (!*ids) - { - write_u8(data, 0); - return; - } - for (len = 0; len < 64 && ids[len]; len++) - { - Id id = ids[len]; - if (needid) - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; - lids[len] = id; - } - if (ids[len]) - { - for (i = len + 1; ids[i]; i++) - ; - sids = solv_malloc2(i, sizeof(Id)); - memcpy(sids, lids, 64 * sizeof(Id)); - for (; ids[len]; len++) - { - Id id = ids[len]; - if (needid) - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; - sids[len] = id; - } - } - else - sids = lids; - - /* That bloody solvable:prereqmarker needs to stay in position :-( */ - if (needid) - marker = needid[marker].need; - for (i = 0; i < len; i++) - if (sids[i] == marker) - break; - if (i > 1) - solv_sort(sids, i, sizeof(Id), cmp_ids, 0); - if ((len - i) > 2) - solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0); - - Id id, old = 0; - - /* The differencing above produces many runs of ones and twos. I tried - fairly elaborate schemes to RLE those, but they give only very mediocre - improvements in compression, as coding the escapes costs quite some - space. Even if they are coded only as bits in IDs. The best improvement - was about 2.7% for the whole .solv file. It's probably better to - invest some complexity into sharing idarrays, than RLEing. */ - for (i = 0; i < len - 1; i++) - { - id = sids[i]; - /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker, - hence all real differences are offsetted by 1. Otherwise we would - have to handle negative differences, which would cost code space for - the encoding of the sign. We loose the exact mapping of prereq here, - but we know the result, so we can recover from that in the reader. */ - if (id == marker) - id = old = 0; - else - { - id = id - old + 1; - old = sids[i]; - } - /* XXX If difference is zero we have multiple equal elements, - we might want to skip writing them out. */ - if (id >= 64) - id = (id & 63) | ((id & ~63) << 1); - write_id(data, id | 64); - } - id = sids[i]; - if (id == marker) - id = 0; - else - id = id - old + 1; - if (id >= 64) - id = (id & 63) | ((id & ~63) << 1); - write_id(data, id); - if (sids != lids) - solv_free(sids); -} -#endif - - struct extdata { unsigned char *buf; int len; }; struct cbdata { + Pool *pool; Repo *repo; Repodata *target; Stringpool *ownspool; Dirpool *owndirpool; + int clonepool; /* are the pool ids cloned into ownspool? */ - Id *keymap; - int nkeymap; - Id *keymapstart; + Id *keymap; /* keymap for this repodata */ NeedId *needid; Id *schema; /* schema construction space */ Id *sp; /* pointer in above */ - Id *oldschema, *oldsp; - Id *solvschemata; Id *subschemata; int nsubschemata; int current_sub; @@ -391,18 +267,20 @@ struct cbdata { Id *dirused; - Id vstart; + Id vstart; /* offset of key in vertical data */ Id maxdata; Id lastlen; int doingsolvables; /* working on solvables data */ int filelistmode; + + Id lastdirid; /* last dir id seen in this repodata */ + Id lastdirid_own; /* last dir id put in own pool */ }; -#define NEEDED_BLOCK 1023 +#define NEEDID_BLOCK 1023 #define SCHEMATA_BLOCK 31 -#define SCHEMATADATA_BLOCK 255 #define EXTDATA_BLOCK 4095 static inline void @@ -482,8 +360,19 @@ data_addid64(struct extdata *xd, unsigned int x, unsigned int hx) data_addid(xd, (Id)x); } +#define USE_REL_IDARRAY +#ifdef USE_REL_IDARRAY + +static int +cmp_ids(const void *pa, const void *pb, void *dp) +{ + Id a = *(Id *)pa; + Id b = *(Id *)pb; + return a - b; +} + static void -data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker) +data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker) { int len, i; Id lids[64], *sids; @@ -500,7 +389,7 @@ data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id { Id id = ids[len]; if (needid) - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + id = needid[NEEDIDOFF(id)].need; lids[len] = id; } if (ids[len]) @@ -513,7 +402,7 @@ data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id { Id id = ids[len]; if (needid) - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + id = needid[NEEDIDOFF(id)].need; sids[len] = id; } } @@ -568,6 +457,27 @@ data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id solv_free(sids); } +#else + +static void +data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker) +{ + Id id; + if (!ids || !*ids) + { + data_addid(xd, 0); + return; + } + while ((id = *ids++) != 0) + { + if (needid) + id = needid[NEEDIDOFF(id)].need; + data_addideof(xd, id, *ids ? 0 : 1); + } +} + +#endif + static inline void data_addblob(struct extdata *xd, unsigned char *blob, int len) { @@ -576,73 +486,53 @@ data_addblob(struct extdata *xd, unsigned char *blob, int len) xd->len += len; } -static inline void -data_addu32(struct extdata *xd, unsigned int num) +/* grow needid array so that it contains the specified id */ +static void +grow_needid(struct cbdata *cbdata, Id id) { - unsigned char d[4]; - d[0] = num >> 24; - d[1] = num >> 16; - d[2] = num >> 8; - d[3] = num; - data_addblob(xd, d, 4); + int oldoff = cbdata->needid[0].map; + int newoff = (id + 1 + NEEDID_BLOCK) & ~NEEDID_BLOCK; + int nrels = cbdata->pool->nrels; + cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId)); + if (nrels) + memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId)); + memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId)); + cbdata->needid[0].map = newoff; } static Id -putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id) +putinownpool(struct cbdata *cbdata, Repodata *data, Id id) { + Stringpool *ss = data->localpool ? &data->spool : &cbdata->pool->ss; const char *str = stringpool_id2str(ss, id); id = stringpool_str2id(cbdata->ownspool, str, 1); if (id >= cbdata->needid[0].map) - { - int oldoff = cbdata->needid[0].map; - int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK; - int nrels = cbdata->repo->pool->nrels; - cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId)); - if (nrels) - memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId)); - memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId)); - cbdata->needid[0].map = newoff; - } + grow_needid(cbdata, id); return id; } static Id -putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir) +putinowndirpool_slow(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir) { Id compid, parent; parent = dirpool_parent(dp, dir); if (parent) - parent = putinowndirpool(cbdata, data, dp, parent); - compid = dp->dirs[dir]; - if (cbdata->ownspool && compid > 1) - compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid); + parent = putinowndirpool_slow(cbdata, data, dp, parent); + compid = dirpool_compid(dp, dir); + if (cbdata->ownspool && compid > 1 && (!cbdata->clonepool || data->localpool)) + compid = putinownpool(cbdata, data, compid); return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1); } -/* - * collect usage information about the dirs - * 1: dir used, no child of dir used - * 2: dir used as parent of another used dir - */ -static inline void -setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir) +static inline Id +putinowndirpool(struct cbdata *cbdata, Repodata *data, Id dir) { - if (cbdata->dirused[dir]) - return; - cbdata->dirused[dir] = 1; - while ((dir = dirpool_parent(dp, dir)) != 0) - { - if (cbdata->dirused[dir] == 2) - return; - if (cbdata->dirused[dir]) - { - cbdata->dirused[dir] = 2; - return; - } - cbdata->dirused[dir] = 2; - } - cbdata->dirused[0] = 2; + if (dir && dir == cbdata->lastdirid) + return cbdata->lastdirid_own; + cbdata->lastdirid = dir; + cbdata->lastdirid_own = putinowndirpool_slow(cbdata, data, &data->dirpool, dir); + return cbdata->lastdirid_own; } /* @@ -650,26 +540,24 @@ setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir) * collect key/id/dirid usage information, create needed schemas */ static int -repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv) +collect_needed_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) { + struct cbdata *cbdata = vcbdata; Id id; int rm; +#if 0 + fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? (int)(s - cbdata->pool->solvables) : 0, s ? pool_id2str(cbdata->pool, s->name) : "", key->name, pool_id2str(cbdata->pool, key->name), key->type); +#endif if (key->name == REPOSITORY_SOLVABLES) return SEARCH_NEXT_KEY; /* we do not want this one */ - /* hack: ignore some keys, see BUGS */ - if (data->repodataid != data->repo->nrepodata - 1) - if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION) - return SEARCH_NEXT_KEY; - - rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)]; + rm = cbdata->keymap[key - data->keys]; if (!rm) return SEARCH_NEXT_KEY; /* we do not want this one */ /* record key in schema */ - if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0) - && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm)) + if (cbdata->sp[-1] != rm) *cbdata->sp++ = rm; switch(key->type) @@ -677,51 +565,20 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep case REPOKEY_TYPE_ID: case REPOKEY_TYPE_IDARRAY: id = kv->id; - if (!ISRELDEP(id) && cbdata->ownspool && id > 1) - id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id); - incneedid(repo->pool, id, cbdata->needid); + if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool)) + id = putinownpool(cbdata, data, id); + incneedid(id, cbdata->needid); break; case REPOKEY_TYPE_DIR: case REPOKEY_TYPE_DIRNUMNUMARRAY: case REPOKEY_TYPE_DIRSTRARRAY: id = kv->id; if (cbdata->owndirpool) - putinowndirpool(cbdata, data, &data->dirpool, id); + putinowndirpool(cbdata, data, id); else - setdirused(cbdata, &data->dirpool, id); + cbdata->dirused[id] = 1; break; case REPOKEY_TYPE_FIXARRAY: - if (kv->eof == 0) - { - if (cbdata->oldschema) - { - cbdata->target->error = pool_error(cbdata->repo->pool, -1, "nested fixarray structs not yet implemented"); - return SEARCH_NEXT_KEY; - } - cbdata->oldschema = cbdata->schema; - cbdata->oldsp = cbdata->sp; - cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id)); - cbdata->sp = cbdata->schema; - } - else if (kv->eof == 1) - { - cbdata->current_sub++; - *cbdata->sp = 0; - cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK); - cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1); -#if 0 - fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]); -#endif - cbdata->sp = cbdata->schema; - } - else - { - solv_free(cbdata->schema); - cbdata->schema = cbdata->oldschema; - cbdata->sp = cbdata->oldsp; - cbdata->oldsp = cbdata->oldschema = 0; - } - break; case REPOKEY_TYPE_FLEXARRAY: if (kv->entry == 0) { @@ -730,13 +587,16 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep } else { - /* just finished a schema, rewind */ + /* just finished a schema, rewind to start */ Id *sp = cbdata->sp - 1; *sp = 0; while (sp[-1]) sp--; - cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK); - cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1); + if (kv->entry == 1 || key->type == REPOKEY_TYPE_FLEXARRAY) + { + cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK); + cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1); + } cbdata->sp = kv->eof == 2 ? sp - 1: sp; } break; @@ -746,17 +606,82 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep return 0; } -static int -repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +static void +collect_needed_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap) { - struct cbdata *cbdata = vcbdata; - Repo *repo = data->repo; - -#if 0 - if (s) - fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? pool_id2str(repo->pool, s->name) : "", key->name, pool_id2str(repo->pool, key->name), key->type); -#endif - return repo_write_collect_needed(cbdata, repo, data, key, kv); + /* set schema info, keep in sync with collect_data_solvable */ + Repo *repo = s->repo; + Id *sp = cbdata->sp; + NeedId *needid = cbdata->needid; + Repodata *target = cbdata->target; + Id *idarraydata = repo->idarraydata; + + if (keymap[SOLVABLE_NAME]) + { + *sp++ = keymap[SOLVABLE_NAME]; + needid[s->name].need++; + } + if (keymap[SOLVABLE_ARCH]) + { + *sp++ = keymap[SOLVABLE_ARCH]; + needid[s->arch].need++; + } + if (keymap[SOLVABLE_EVR]) + { + *sp++ = keymap[SOLVABLE_EVR]; + needid[s->evr].need++; + } + if (s->vendor && keymap[SOLVABLE_VENDOR]) + { + *sp++ = keymap[SOLVABLE_VENDOR]; + needid[s->vendor].need++; + } + if (s->provides && keymap[SOLVABLE_PROVIDES]) + { + *sp++ = keymap[SOLVABLE_PROVIDES]; + target->keys[keymap[SOLVABLE_PROVIDES]].size += incneedidarray(idarraydata + s->provides, needid); + } + if (s->obsoletes && keymap[SOLVABLE_OBSOLETES]) + { + *sp++ = keymap[SOLVABLE_OBSOLETES]; + target->keys[keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(idarraydata + s->obsoletes, needid); + } + if (s->conflicts && keymap[SOLVABLE_CONFLICTS]) + { + *sp++ = keymap[SOLVABLE_CONFLICTS]; + target->keys[keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(idarraydata + s->conflicts, needid); + } + if (s->requires && keymap[SOLVABLE_REQUIRES]) + { + *sp++ = keymap[SOLVABLE_REQUIRES]; + target->keys[keymap[SOLVABLE_REQUIRES]].size += incneedidarray(idarraydata + s->requires, needid); + } + if (s->recommends && keymap[SOLVABLE_RECOMMENDS]) + { + *sp++ = keymap[SOLVABLE_RECOMMENDS]; + target->keys[keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(idarraydata + s->recommends, needid); + } + if (s->suggests && keymap[SOLVABLE_SUGGESTS]) + { + *sp++ = keymap[SOLVABLE_SUGGESTS]; + target->keys[keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(idarraydata + s->suggests, needid); + } + if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS]) + { + *sp++ = keymap[SOLVABLE_SUPPLEMENTS]; + target->keys[keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(idarraydata + s->supplements, needid); + } + if (s->enhances && keymap[SOLVABLE_ENHANCES]) + { + *sp++ = keymap[SOLVABLE_ENHANCES]; + target->keys[keymap[SOLVABLE_ENHANCES]].size += incneedidarray(idarraydata + s->enhances, needid); + } + if (repo->rpmdbid && keymap[RPM_RPMDBID]) + { + *sp++ = keymap[RPM_RPMDBID]; + target->keys[keymap[RPM_RPMDBID]].size++; + } + cbdata->sp = sp; } @@ -764,57 +689,51 @@ repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, K * pass 2 callback: * encode all of the data into the correct buffers */ - static int -repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv) +collect_data_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) { + struct cbdata *cbdata = vcbdata; int rm; - Id id; - unsigned int u32; - unsigned char v[4]; + Id id, storage; struct extdata *xd; NeedId *needid; if (key->name == REPOSITORY_SOLVABLES) return SEARCH_NEXT_KEY; - /* hack: ignore some keys, see BUGS */ - if (data->repodataid != data->repo->nrepodata - 1) - if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION) - return SEARCH_NEXT_KEY; - - rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)]; + rm = cbdata->keymap[key - data->keys]; if (!rm) return SEARCH_NEXT_KEY; /* we do not want this one */ + storage = cbdata->target->keys[rm].storage; - if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET) + xd = cbdata->extdata + 0; /* incore buffer */ + if (storage == KEY_STORAGE_VERTICAL_OFFSET) { - xd = cbdata->extdata + rm; /* vertical buffer */ + xd += rm; /* vertical buffer */ if (cbdata->vstart == -1) cbdata->vstart = xd->len; } - else - xd = cbdata->extdata + 0; /* incore buffer */ switch(key->type) { + case REPOKEY_TYPE_DELETED: case REPOKEY_TYPE_VOID: case REPOKEY_TYPE_CONSTANT: case REPOKEY_TYPE_CONSTANTID: break; case REPOKEY_TYPE_ID: id = kv->id; - if (!ISRELDEP(id) && cbdata->ownspool && id > 1) - id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); - needid = cbdata->needid; - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool)) + id = putinownpool(cbdata, data, id); + needid = cbdata->needid; + id = needid[NEEDIDOFF(id)].need; data_addid(xd, id); break; case REPOKEY_TYPE_IDARRAY: id = kv->id; - if (!ISRELDEP(id) && cbdata->ownspool && id > 1) - id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id); - needid = cbdata->needid; - id = needid[ISRELDEP(id) ? RELOFF(id) : id].need; + if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool)) + id = putinownpool(cbdata, data, id); + needid = cbdata->needid; + id = needid[NEEDIDOFF(id)].need; data_addideof(xd, id, kv->eof); break; case REPOKEY_TYPE_STR: @@ -838,13 +757,6 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue case REPOKEY_TYPE_SHA512: data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA512); break; - case REPOKEY_TYPE_U32: - u32 = kv->num; - v[0] = u32 >> 24; - v[1] = u32 >> 16; - v[2] = u32 >> 8; - v[3] = u32; - data_addblob(xd, v, 4); break; case REPOKEY_TYPE_NUM: data_addid64(xd, kv->num, kv->num2); @@ -852,7 +764,7 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue case REPOKEY_TYPE_DIR: id = kv->id; if (cbdata->owndirpool) - id = putinowndirpool(cbdata, data, &data->dirpool, id); + id = putinowndirpool(cbdata, data, id); id = cbdata->dirused[id]; data_addid(xd, id); break; @@ -864,7 +776,7 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue case REPOKEY_TYPE_DIRNUMNUMARRAY: id = kv->id; if (cbdata->owndirpool) - id = putinowndirpool(cbdata, data, &data->dirpool, id); + id = putinowndirpool(cbdata, data, id); id = cbdata->dirused[id]; data_addid(xd, id); data_addid(xd, kv->num); @@ -873,39 +785,22 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue case REPOKEY_TYPE_DIRSTRARRAY: id = kv->id; if (cbdata->owndirpool) - id = putinowndirpool(cbdata, data, &data->dirpool, id); + id = putinowndirpool(cbdata, data, id); id = cbdata->dirused[id]; - if (cbdata->filelistmode > 0) + if (rm == cbdata->filelistmode) { + /* postpone adding to xd, just update len to get the correct offsets into the incore data*/ xd->len += data_addideof_len(id) + strlen(kv->str) + 1; break; } data_addideof(xd, id, kv->eof); data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); - if (cbdata->filelistmode < 0) - return 0; break; case REPOKEY_TYPE_FIXARRAY: - if (kv->eof == 0) - { - if (kv->num) - { - data_addid(xd, kv->num); - data_addid(xd, cbdata->subschemata[cbdata->current_sub]); -#if 0 - fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]); -#endif - } - } - else if (kv->eof == 1) - { - cbdata->current_sub++; - } - break; case REPOKEY_TYPE_FLEXARRAY: if (!kv->entry) data_addid(xd, kv->num); - if (kv->eof != 2) + if (kv->eof != 2 && (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY)) data_addid(xd, cbdata->subschemata[cbdata->current_sub++]); if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables) { @@ -915,10 +810,10 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue } break; default: - cbdata->target->error = pool_error(cbdata->repo->pool, -1, "unknown type for %d: %d\n", key->name, key->type); + cbdata->target->error = pool_error(cbdata->pool, -1, "unknown type for %d: %d\n", key->name, key->type); break; } - if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof) + if (storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof) { /* we can re-use old data in the blob here! */ data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */ @@ -928,11 +823,63 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue return 0; } +/* special version of collect_data_cb that collects just one single REPOKEY_TYPE_DIRSTRARRAY vertical data */ static int -repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) +collect_filelist_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) { struct cbdata *cbdata = vcbdata; - return repo_write_adddata(cbdata, data, key, kv); + int rm; + Id id; + struct extdata *xd; + + rm = cbdata->keymap[key - data->keys]; + if (rm != cbdata->filelistmode) + return SEARCH_NEXT_KEY; /* we do not want this one */ + id = kv->id; + if (cbdata->owndirpool) + id = putinowndirpool(cbdata, data, id); + id = cbdata->dirused[id]; + xd = cbdata->extdata + rm; /* vertical buffer */ + data_addideof(xd, id, kv->eof); + data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1); + return 0; +} + +static void +collect_data_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap) +{ + Repo *repo = s->repo; + Pool *pool = repo->pool; + struct extdata *xd = cbdata->extdata; + NeedId *needid = cbdata->needid; + Id *idarraydata = repo->idarraydata; + + if (keymap[SOLVABLE_NAME]) + data_addid(xd, needid[s->name].need); + if (keymap[SOLVABLE_ARCH]) + data_addid(xd, needid[s->arch].need); + if (keymap[SOLVABLE_EVR]) + data_addid(xd, needid[s->evr].need); + if (s->vendor && keymap[SOLVABLE_VENDOR]) + data_addid(xd, needid[s->vendor].need); + if (s->provides && keymap[SOLVABLE_PROVIDES]) + data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER); + if (s->obsoletes && keymap[SOLVABLE_OBSOLETES]) + data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0); + if (s->conflicts && keymap[SOLVABLE_CONFLICTS]) + data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0); + if (s->requires && keymap[SOLVABLE_REQUIRES]) + data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER); + if (s->recommends && keymap[SOLVABLE_RECOMMENDS]) + data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0); + if (s->suggests && keymap[SOLVABLE_SUGGESTS]) + data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0); + if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS]) + data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0); + if (s->enhances && keymap[SOLVABLE_ENHANCES]) + data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0); + if (repo->rpmdbid && keymap[RPM_RPMDBID]) + data_addid(xd, repo->rpmdbid[(s - pool->solvables) - repo->start]); } /* traverse through directory with first child "dir" */ @@ -955,6 +902,10 @@ traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used) dirmap[n++] = sib; } + /* check if our block has some content */ + if (parent == n) + return n - 1; /* nope, drop parent id again */ + /* now go through all the siblings we just added and * do recursive calls on them */ lastn = n; @@ -1036,24 +987,6 @@ repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata) return KEY_STORAGE_INCORE; } -/* - * return true if the repodata contains the filelist (and just - * the filelist). The same code is used in the dataiterator. The way - * it is used is completely wrong, of course, as having the filelist - * key does not mean it is used for a specific solvable. Nevertheless - * it is better to have it than to write broken solv files. - */ -static inline int -is_filelist_extension(Repodata *data) -{ - int j; - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - return 0; - return 1; -} - - static int write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vpage, int lpage) { @@ -1077,10 +1010,109 @@ write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vp return lpage; } + +static Id * +create_keyskip(Repo *repo, Id entry, unsigned char *repodataused, Id **oldkeyskip) +{ + Repodata *data, *last = 0; + Id *keyskip; + int rdid, cnt = 0; + + if (repo->nrepodata <= 2) + return 0; + keyskip = *oldkeyskip; + if (keyskip) + { + if (keyskip[1] >= 0x10000000) + keyskip = solv_free(keyskip); + else + keyskip[1] = keyskip[2]; + } + FOR_REPODATAS(repo, rdid, data) + { + if (!repodataused[rdid]) + continue; + if (entry != SOLVID_META) + { + if (entry < data->start || entry >= data->end) + continue; + /* if repodataused is set we know that the state is AVAILABLE */ + if (!data->incoreoffset[entry - data->start]) + continue; + } + if (last) + keyskip = repodata_fill_keyskip(last, entry, keyskip); + last = data; + cnt++; + } + if (cnt <= 1) /* just one repodata means we don't need a keyskip */ + { + *oldkeyskip = keyskip; + return 0; + } + keyskip = repodata_fill_keyskip(last, entry, keyskip); + if (keyskip) + keyskip[2] = keyskip[1] + repo->nrepodata; + *oldkeyskip = keyskip; + return keyskip; +} + /* * Repo */ +Repowriter * +repowriter_create(Repo *repo) +{ + Repowriter *writer = solv_calloc(1, sizeof(*writer)); + writer->repo = repo; + writer->keyfilter = repo_write_stdkeyfilter; + writer->repodatastart = 1; + writer->repodataend = repo->nrepodata; + writer->solvablestart = repo->start; + writer->solvableend = repo->end; + return writer; +} + +Repowriter * +repowriter_free(Repowriter *writer) +{ + return solv_free(writer); +} + +void +repowriter_set_flags(Repowriter *writer, int flags) +{ + writer->flags = flags; +} + +void +repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata) +{ + writer->keyfilter = keyfilter; + writer->kfdata = kfdata; +} + +void +repowriter_set_keyqueue(Repowriter *writer, Queue *keyq) +{ + writer->keyq = keyq; +} + +void +repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend) +{ + writer->repodatastart = repodatastart; + writer->repodataend = repodataend; +} + +void +repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend) +{ + writer->solvablestart = solvablestart; + writer->solvableend = solvableend; +} + /* * the code works the following way: * @@ -1093,31 +1125,43 @@ write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vp * 5) write everything to disk */ int -repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) +repowriter_write(Repowriter *writer, FILE *fp) { + Repo *repo = writer->repo; Pool *pool = repo->pool; - int i, j, n, lastfilelistn; + int i, j, n; Solvable *s; - NeedId *needid; + NeedId *needid, *needidp; int nstrings, nrels; unsigned int sizeid; unsigned int solv_flags; - Reldep *ran; - Id *idarraydata; + Id *oldkeyskip = 0; + Id *keyskip = 0; + int searchflags = 0; Id id, *sp; + Id *keymap; /* maps repo key to my key, 0 -> not used */ + int nkeymap; + int *keymapstart; /* maps repo number to keymap offset */ + Id *dirmap; int ndirmap; Id *keyused; + unsigned char *repodataused; int anyrepodataused = 0; + + int solvablestart, solvableend; + Id *solvschemata; int anysolvableused = 0; + int nsolvables; struct cbdata cbdata; + int clonepool; Repokey *key; - int poolusage, dirpoolusage, idused, dirused; + int poolusage, dirpoolusage; int reloff; Repodata *data, *dirpooldata; @@ -1127,14 +1171,15 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * Stringpool *spool; Dirpool *dirpool; - Id mainschema; + Id mainschema, *mainschemakeys; struct extdata *xd; - Id type_constantid = REPOKEY_TYPE_CONSTANTID; + Id type_constantid = 0; memset(&cbdata, 0, sizeof(cbdata)); + cbdata.pool = pool; cbdata.repo = repo; cbdata.target = ⌖ @@ -1142,44 +1187,50 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * /* go through all repodata and find the keys we need */ /* also unify keys */ - /* keymapstart - maps repo number to keymap offset */ - /* keymap - maps repo key to my key, 0 -> not used */ /* start with all KEY_STORAGE_SOLVABLE ids */ n = ID_NUM_INTERNAL; FOR_REPODATAS(repo, i, data) n += data->nkeys; - cbdata.keymap = solv_calloc(n, sizeof(Id)); - cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id)); + nkeymap = n; + keymap = solv_calloc(nkeymap, sizeof(Id)); + keymapstart = solv_calloc(repo->nrepodata, sizeof(Id)); repodataused = solv_calloc(repo->nrepodata, 1); clonepool = 0; poolusage = 0; - /* add keys for STORAGE_SOLVABLE */ - for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++) + if (!(writer->flags & REPOWRITER_NO_STORAGE_SOLVABLE)) { - Repokey keyd; - keyd.name = i; - if (i < SOLVABLE_PROVIDES) - keyd.type = REPOKEY_TYPE_ID; - else if (i < RPM_RPMDBID) - keyd.type = REPOKEY_TYPE_REL_IDARRAY; - else - keyd.type = REPOKEY_TYPE_NUM; - keyd.size = 0; - keyd.storage = KEY_STORAGE_SOLVABLE; - if (keyfilter) + /* add keys for STORAGE_SOLVABLE */ + for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++) { - keyd.storage = keyfilter(repo, &keyd, kfdata); - if (keyd.storage == KEY_STORAGE_DROPPED) - continue; + Repokey keyd; + keyd.name = i; + if (i < SOLVABLE_PROVIDES) + keyd.type = REPOKEY_TYPE_ID; + else if (i < RPM_RPMDBID) +#ifdef USE_REL_IDARRAY + keyd.type = REPOKEY_TYPE_REL_IDARRAY; +#else + keyd.type = REPOKEY_TYPE_IDARRAY; +#endif + else + keyd.type = REPOKEY_TYPE_NUM; + keyd.size = 0; keyd.storage = KEY_STORAGE_SOLVABLE; + if (writer->keyfilter) + { + keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata); + if (keyd.storage == KEY_STORAGE_DROPPED) + continue; + keyd.storage = KEY_STORAGE_SOLVABLE; + } + poolusage = 1; + clonepool = 1; + keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); } - poolusage = 1; - clonepool = 1; - cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); } if (repo->nsolvables) @@ -1189,7 +1240,7 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * keyd.type = REPOKEY_TYPE_FLEXARRAY; keyd.size = 0; keyd.storage = KEY_STORAGE_INCORE; - cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); + keymap[keyd.name] = repodata_key2id(&target, &keyd, 1); } dirpoolusage = 0; @@ -1198,35 +1249,37 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * dirpool = 0; dirpooldata = 0; n = ID_NUM_INTERNAL; - lastfilelistn = 0; FOR_REPODATAS(repo, i, data) { - cbdata.keymapstart[i] = n; - cbdata.keymap[n++] = 0; /* key 0 */ - idused = 0; - dirused = 0; - if (keyfilter) + int idused, dirused; + if (i < writer->repodatastart || i >= writer->repodataend) + continue; + if (writer->keyfilter && (writer->flags & REPOWRITER_LEGACY) != 0) { + /* ask keyfilter if we want this repodata */ Repokey keyd; /* check if we want this repodata */ memset(&keyd, 0, sizeof(keyd)); keyd.name = 1; keyd.type = 1; keyd.size = i; - if (keyfilter(repo, &keyd, kfdata) == -1) + if (writer->keyfilter(repo, &keyd, writer->kfdata) == -1) continue; } + keymapstart[i] = n; + keymap[n++] = 0; /* key 0 */ + idused = dirused = 0; for (j = 1; j < data->nkeys; j++, n++) { key = data->keys + j; if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY) { - cbdata.keymap[n] = cbdata.keymap[key->name]; + keymap[n] = keymap[key->name]; continue; } - if (key->type == REPOKEY_TYPE_DELETED) + if (key->type == REPOKEY_TYPE_DELETED && (writer->flags & REPOWRITER_KEEP_TYPE_DELETED) == 0) { - cbdata.keymap[n] = 0; + keymap[n] = 0; continue; } if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool) @@ -1239,43 +1292,48 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * id = repodata_key2id(&target, key, 0); if (!id) { + /* a new key. ask keyfilter if we want it before creating it */ Repokey keyd = *key; keyd.storage = KEY_STORAGE_INCORE; if (keyd.type == REPOKEY_TYPE_CONSTANTID) keyd.size = repodata_globalize_id(data, key->size, 1); else if (keyd.type != REPOKEY_TYPE_CONSTANT) keyd.size = 0; - if (keyfilter) + if (writer->keyfilter) { - keyd.storage = keyfilter(repo, &keyd, kfdata); + keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata); if (keyd.storage == KEY_STORAGE_DROPPED) { - cbdata.keymap[n] = 0; + keymap[n] = 0; continue; } } - id = repodata_key2id(&target, &keyd, 1); + if (data->state != REPODATA_STUB) + id = repodata_key2id(&target, &keyd, 1); } - cbdata.keymap[n] = id; + keymap[n] = id; /* load repodata if not already loaded */ if (data->state == REPODATA_STUB) { - if (data->loadcallback) - data->loadcallback(data); - else - data->state = REPODATA_ERROR; - if (data->state != REPODATA_ERROR) + int oldnkeys = data->nkeys; + repodata_load(data); + if (oldnkeys != data->nkeys) + { + nkeymap += data->nkeys - oldnkeys; /* grow/shrink keymap */ + keymap = solv_realloc2(keymap, nkeymap, sizeof(Id)); + } + if (data->state == REPODATA_AVAILABLE) { /* redo this repodata! */ j = 0; - n = cbdata.keymapstart[i]; + n = keymapstart[i]; continue; } } - if (data->state == REPODATA_ERROR) + if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING) { /* too bad! */ - cbdata.keymap[n] = 0; + keymap[n] = 0; continue; } @@ -1289,20 +1347,6 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * idused = 1; /* dirs also use ids */ dirused = 1; } - if (key->type == REPOKEY_TYPE_DIRSTRARRAY && key->name == SOLVABLE_FILELIST) - { - /* is this a file list extension */ - if (is_filelist_extension(data)) - { - /* hmm, we have a file list extension. Kill filelist of other repodata. - * XXX: this is wrong, as the extension does not need to cover all - * solvables of the other repodata */ - if (lastfilelistn) - cbdata.keymap[lastfilelistn] = 0; - } - else - lastfilelistn = n; - } } if (idused) { @@ -1336,20 +1380,24 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * } } } - cbdata.nkeymap = n; + nkeymap = n; /* update */ /* 0: no pool needed at all */ /* 1: use global pool */ /* 2: use repodata local pool */ /* 3: need own pool */ + if (poolusage != 3) + clonepool = 0; if (poolusage == 3) { spool = &target.spool; + target.localpool = 1; /* so we can use repodata_translate */ /* hack: reuse global pool data so we don't have to map pool ids */ if (clonepool) { stringpool_free(spool); stringpool_clone(spool, &pool->ss); + cbdata.clonepool = 1; } cbdata.ownspool = spool; } @@ -1361,6 +1409,10 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * if (dirpoolusage == 3) { + /* dirpoolusage == 3 means that at least two repodata + * areas have dir keys. This means that two areas have + * idused set to 1, which results in poolusage being + * either 1 (global pool) or 3 (own pool) */ dirpool = &target.dirpool; dirpooldata = 0; cbdata.owndirpool = dirpool; @@ -1373,196 +1425,110 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey * #if 0 fprintf(stderr, "poolusage: %d\n", poolusage); fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage); +fprintf(stderr, "clonepool: %d\n", clonepool); fprintf(stderr, "nkeys: %d\n", target.nkeys); for (i = 1; i < target.nkeys; i++) fprintf(stderr, " %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage); #endif - /* copy keys if requested */ - if (keyq) - { - queue_empty(keyq); - for (i = 1; i < target.nkeys; i++) - queue_push2(keyq, target.keys[i].name, target.keys[i].type); - } - - if (poolusage > 1) - { - /* put all the keys we need in our string pool */ - /* put mapped ids right into target.keys */ - for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++) - { - key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1); - if (key->type == REPOKEY_TYPE_CONSTANTID) - { - key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1); - type_constantid = key->type; - key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1); - } - else - key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1); - } - if (poolusage == 2) - stringpool_freehash(spool); /* free some mem */ - } - - /********************************************************************/ + searchflags = SEARCH_SUB|SEARCH_ARRAYSENTINEL; + if ((writer->flags & REPOWRITER_KEEP_TYPE_DELETED) != 0) + searchflags |= SEARCH_KEEP_TYPE_DELETED; + /* set needed count of all strings and rels, * find which keys are used in the solvables * put all strings in own spool */ reloff = spool->nstrings; - if (poolusage == 3) - reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK; + if (cbdata.ownspool) + reloff = (reloff + NEEDID_BLOCK) & ~NEEDID_BLOCK; + else if (poolusage == 2) + { + /* we'll need to put the key data into the spool, + * so leave some room. 3 * nkeys is an upper bound */ + reloff += 3 * target.nkeys; + } needid = calloc(reloff + pool->nrels, sizeof(*needid)); - needid[0].map = reloff; + needid[0].map = reloff; /* remember size in case we need to grow */ cbdata.needid = needid; - cbdata.schema = solv_calloc(target.nkeys, sizeof(Id)); - cbdata.sp = cbdata.schema; - cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id)); + cbdata.schema = solv_calloc(target.nkeys + 2, sizeof(Id)); /* create main schema */ - cbdata.sp = cbdata.schema; - /* collect all other data from all repodatas */ + cbdata.sp = cbdata.schema + 1; + + /* collect meta data from all repodatas */ /* XXX: merge arrays of equal keys? */ + keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip); FOR_REPODATAS(repo, j, data) { if (!repodataused[j]) continue; - repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata); + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; /* clear dir mapping cache */ + repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_needed_cb, &cbdata); } + needid = cbdata.needid; /* maybe relocated */ sp = cbdata.sp; /* add solvables if needed (may revert later) */ if (repo->nsolvables) { - *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES]; - target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++; + *sp++ = keymap[REPOSITORY_SOLVABLES]; + target.keys[keymap[REPOSITORY_SOLVABLES]].size++; } *sp = 0; - mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1); - - idarraydata = repo->idarraydata; + /* stash away main schema (including terminating zero) */ + mainschemakeys = solv_memdup2(cbdata.schema + 1, sp - cbdata.schema, sizeof(Id)); + /* collect data for all solvables */ + solvschemata = solv_calloc(repo->nsolvables, sizeof(Id)); /* allocate upper bound */ + solvablestart = writer->solvablestart < repo->start ? repo->start : writer->solvablestart; + solvableend = writer->solvableend > repo->end ? repo->end : writer->solvableend; anysolvableused = 0; + nsolvables = 0; /* solvables we are going to write, will be <= repo->nsolvables */ cbdata.doingsolvables = 1; - for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) + for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++) { if (s->repo != repo) continue; - /* set schema info, keep in sync with further down */ - sp = cbdata.schema; - if (cbdata.keymap[SOLVABLE_NAME]) - { - *sp++ = cbdata.keymap[SOLVABLE_NAME]; - needid[s->name].need++; - } - if (cbdata.keymap[SOLVABLE_ARCH]) - { - *sp++ = cbdata.keymap[SOLVABLE_ARCH]; - needid[s->arch].need++; - } - if (cbdata.keymap[SOLVABLE_EVR]) - { - *sp++ = cbdata.keymap[SOLVABLE_EVR]; - needid[s->evr].need++; - } - if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) - { - *sp++ = cbdata.keymap[SOLVABLE_VENDOR]; - needid[s->vendor].need++; - } - if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) - { - *sp++ = cbdata.keymap[SOLVABLE_PROVIDES]; - target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid); - } - if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) - { - *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES]; - target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid); - } - if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) - { - *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS]; - target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid); - } - if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) - { - *sp++ = cbdata.keymap[SOLVABLE_REQUIRES]; - target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid); - } - if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) - { - *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS]; - target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid); - } - if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) - { - *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS]; - target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid); - } - if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) - { - *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS]; - target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid); - } - if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) - { - *sp++ = cbdata.keymap[SOLVABLE_ENHANCES]; - target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid); - } - if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) - { - *sp++ = cbdata.keymap[RPM_RPMDBID]; - target.keys[cbdata.keymap[RPM_RPMDBID]].size++; - } - cbdata.sp = sp; + cbdata.sp = cbdata.schema + 1; + collect_needed_solvable(&cbdata, s, keymap); if (anyrepodataused) { + keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip); FOR_REPODATAS(repo, j, data) { - if (!repodataused[j]) - continue; - if (i < data->start || i >= data->end) + if (!repodataused[j] || i < data->start || i >= data->end) continue; - repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata); - needid = cbdata.needid; + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; + repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_needed_cb, &cbdata); } + needid = cbdata.needid; /* maybe relocated */ } *cbdata.sp = 0; - cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1); - if (cbdata.solvschemata[n]) + solvschemata[nsolvables] = repodata_schema2id(cbdata.target, cbdata.schema + 1, 1); + if (solvschemata[nsolvables]) anysolvableused = 1; - n++; + nsolvables++; } cbdata.doingsolvables = 0; - assert(n == repo->nsolvables); if (repo->nsolvables && !anysolvableused) { - /* strip off solvable from the main schema */ - target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0; - sp = cbdata.schema; - for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++) - { - *sp = target.schemadata[target.schemata[mainschema] + i]; - if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES]) - sp++; - } - assert(target.schemadatalen == target.schemata[mainschema] + i + 1); - *sp = 0; - target.schemadatalen = target.schemata[mainschema]; - target.nschemata--; - repodata_free_schemahash(&target); - mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1); + /* strip off REPOSITORY_SOLVABLES from the main schema */ + for (sp = mainschemakeys; *sp; sp++) + ; + sp[-1] = 0; /* strip last entry */ } + mainschema = repodata_schema2id(cbdata.target, mainschemakeys, 1); + mainschemakeys = solv_free(mainschemakeys); /********************************************************************/ @@ -1575,32 +1541,78 @@ for (i = 1; i < target.nkeys; i++) { if (!keyused[i]) continue; - keyused[i] = n; if (i != n) - { - target.keys[n] = target.keys[i]; - if (keyq) - { - keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2]; - keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1]; - } - } - n++; + target.keys[n] = target.keys[i]; + keyused[i] = n++; } target.nkeys = n; - if (keyq) - queue_truncate(keyq, 2 * n - 2); /* update schema data to the new key ids */ for (i = 1; i < (int)target.schemadatalen; i++) target.schemadata[i] = keyused[target.schemadata[i]]; /* update keymap to the new key ids */ - for (i = 0; i < cbdata.nkeymap; i++) - cbdata.keymap[i] = keyused[cbdata.keymap[i]]; + for (i = 0; i < nkeymap; i++) + keymap[i] = keyused[keymap[i]]; keyused = solv_free(keyused); - /* increment needid of the used keys, they are already mapped to - * the correct string pool */ + /* copy keys if requested */ + if (writer->keyq) + { + queue_empty(writer->keyq); + for (i = 1; i < target.nkeys; i++) + queue_push2(writer->keyq, target.keys[i].name, target.keys[i].type); + } + +/********************************************************************/ + + /* check if we can do the special filelist memory optimization + * we do the check before the keys are mapped. + * The optimization is done if there is just one vertical key and + * it is of type REPOKEY_TYPE_DIRSTRARRAY */ + if (anysolvableused && anyrepodataused) + { + for (i = 1; i < target.nkeys; i++) + { + if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET) + continue; + if (target.keys[i].type != REPOKEY_TYPE_DIRSTRARRAY || cbdata.filelistmode != 0) + { + cbdata.filelistmode = 0; + break; + } + cbdata.filelistmode = i; + } + } + +/********************************************************************/ + + if (poolusage > 1) + { + /* put all the keys in our string pool */ + /* put mapped ids right into target.keys */ + for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++) + { + key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1); + id = stringpool_str2id(spool, pool_id2str(pool, key->type), 1); + if (key->type == REPOKEY_TYPE_CONSTANTID) + { + type_constantid = id; + key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1); + } + key->type = id; + } + if (poolusage == 2) + stringpool_freehash(spool); /* free some mem */ + if (cbdata.ownspool && spool->nstrings > needid[0].map) + { + grow_needid(&cbdata, spool->nstrings - 1); + needid = cbdata.needid; /* we relocated */ + } + } + else + type_constantid = REPOKEY_TYPE_CONSTANTID; + + /* increment needid of the keys */ for (i = 1; i < target.nkeys; i++) { if (target.keys[i].type == type_constantid) @@ -1611,41 +1623,116 @@ for (i = 1; i < target.nkeys; i++) /********************************************************************/ - if (dirpool && cbdata.dirused && !cbdata.dirused[0]) + /* increment need id of all relations + * if we refer to another relation, make sure that the + * need value is it is bigger than our value so that + * ordering works. + */ + reloff = needid[0].map; + for (i = pool->nrels - 1, needidp = needid + (reloff + i); i > 0; i--, needidp--) + if (needidp->need) + break; + if (i) { - /* no dirs used at all */ - cbdata.dirused = solv_free(cbdata.dirused); - dirpool = 0; - } + /* we have some relations with a non-zero need */ + Reldep *rd; + + for (rd = pool->rels + i; i > 0; i--, rd--) + { + int need = needid[reloff + i].need; + if (!need) + continue; + id = rd->name; + if (ISRELDEP(id)) + { + id = GETRELID(id); + if (needid[reloff + id].need < need + 1) + needid[reloff + id].need = need + 1; + } + else + { + if (cbdata.ownspool && id > 1 && !cbdata.clonepool) + { + id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1); + if (id >= cbdata.needid[0].map) + { + grow_needid(&cbdata, id); + needid = cbdata.needid; /* we relocated */ + reloff = needid[0].map; /* we have a new offset */ + } + } + needid[id].need++; + } + + id = rd->evr; + if (ISRELDEP(id)) + { + id = GETRELID(id); + if (needid[reloff + id].need < need + 1) + needid[reloff + id].need = need + 1; + } + else + { + if (cbdata.ownspool && id > 1 && !cbdata.clonepool) + { + id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1); + if (id >= cbdata.needid[0].map) + { + grow_needid(&cbdata, id); + needid = cbdata.needid; /* we relocated */ + reloff = needid[0].map; /* we have a new offset */ + } + } + needid[id].need++; + } + } + } + +/********************************************************************/ /* increment need id for used dir components */ - if (dirpool) + if (cbdata.owndirpool) { /* if we have own dirpool, all entries in it are used. also, all comp ids are already mapped by putinowndirpool(), so we can simply increment needid. (owndirpool != 0, dirused == 0, dirpooldata == 0) */ + for (i = 1; i < dirpool->ndirs; i++) + { + id = dirpool->dirs[i]; + if (id <= 0) + continue; + needid[id].need++; + } + } + else if (dirpool) + { + Id parent; /* else we re-use a dirpool of repodata "dirpooldata". dirused tells us which of the ids are used. we need to map comp ids if we generate a new pool. (owndirpool == 0, dirused != 0, dirpooldata != 0) */ - for (i = 1; i < dirpool->ndirs; i++) + for (i = dirpool->ndirs - 1; i > 0; i--) { -#if 0 -fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); -#endif - if (cbdata.dirused && !cbdata.dirused[i]) + if (!cbdata.dirused[i]) continue; + parent = dirpool_parent(dirpool, i); /* always < i */ + cbdata.dirused[parent] = 2; /* 2: used as parent */ id = dirpool->dirs[i]; if (id <= 0) continue; - if (dirpooldata && cbdata.ownspool && id > 1) + if (cbdata.ownspool && id > 1 && (!cbdata.clonepool || dirpooldata->localpool)) { - id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id); + id = putinownpool(&cbdata, dirpooldata, id); needid = cbdata.needid; } needid[id].need++; } + if (!cbdata.dirused[0]) + { + cbdata.dirused = solv_free(cbdata.dirused); + dirpool = 0; + } } @@ -1666,13 +1753,9 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); for (i = 1; i < reloff + pool->nrels; i++) needid[i].map = i; -#if 0 - solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool); -#else /* make first entry '' */ needid[1].need = 1; solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool); -#endif solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0); /* now needid is in new order, needid[newid].map -> oldid */ @@ -1712,7 +1795,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); ndirmap = 0; dirmap = 0; - if (dirpool) + if (dirpool && dirpool->ndirs) { /* create our new target directory structure by traversing through all * used dirs. This will concatenate blocks with the same parent @@ -1721,7 +1804,10 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); * we will change this in the second step below */ /* (dirpooldata and dirused are 0 if we have our own dirpool) */ if (cbdata.dirused && !cbdata.dirused[1]) - cbdata.dirused[1] = 1; /* always want / entry */ + { + cbdata.dirused[1] = 1; /* always want / entry */ + cbdata.dirused[0] = 2; /* always want / entry */ + } dirmap = solv_calloc(dirpool->ndirs, sizeof(Id)); dirmap[0] = 0; ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused); @@ -1738,7 +1824,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); cbdata.dirused[dirmap[i]] = i; id = dirpool->dirs[dirmap[i]]; if (dirpooldata && cbdata.ownspool && id > 1) - id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id); + id = putinownpool(&cbdata, dirpooldata, id); dirmap[i] = needid[id].need; } /* now the new target directory structure is complete (dirmap), and we have @@ -1749,6 +1835,8 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); /* collect all data * we use extdata[0] for incore data and extdata[keyid] for vertical data + * + * this must match the code above that creates the schema data! */ cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata)); @@ -1759,77 +1847,41 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); cbdata.lastlen = 0; data_addid(xd, mainschema); -#if 1 + keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip); FOR_REPODATAS(repo, j, data) { if (!repodataused[j]) continue; - repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata); + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; + repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_data_cb, &cbdata); } -#endif - if (xd->len - cbdata.lastlen > cbdata.maxdata) cbdata.maxdata = xd->len - cbdata.lastlen; cbdata.lastlen = xd->len; if (anysolvableused) { - data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */ + data_addid(xd, nsolvables); /* FLEXARRAY nentries */ cbdata.doingsolvables = 1; - /* check if we can do the special filelist memory optimization */ - if (anyrepodataused) - { - for (i = 1; i < target.nkeys; i++) - if (target.keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET) - cbdata.filelistmode |= cbdata.filelistmode == 0 && target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY ? 1 : 2; - else if (target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY) - cbdata.filelistmode = 2; - if (cbdata.filelistmode != 1) - cbdata.filelistmode = 0; - } - - for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++) + for (i = solvablestart, s = pool->solvables + i, n = 0; i < solvableend; i++, s++) { if (s->repo != repo) continue; - data_addid(xd, cbdata.solvschemata[n]); - if (cbdata.keymap[SOLVABLE_NAME]) - data_addid(xd, needid[s->name].need); - if (cbdata.keymap[SOLVABLE_ARCH]) - data_addid(xd, needid[s->arch].need); - if (cbdata.keymap[SOLVABLE_EVR]) - data_addid(xd, needid[s->evr].need); - if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR]) - data_addid(xd, needid[s->vendor].need); - if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER); - if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0); - if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0); - if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER); - if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0); - if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0); - if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0); - if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES]) - data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0); - if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID]) - data_addid(xd, repo->rpmdbid[i - repo->start]); + data_addid(xd, solvschemata[n]); + collect_data_solvable(&cbdata, s, keymap); if (anyrepodataused) { + keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip); cbdata.vstart = -1; FOR_REPODATAS(repo, j, data) { - if (!repodataused[j]) - continue; - if (i < data->start || i >= data->end) + if (!repodataused[j] || i < data->start || i >= data->end) continue; - repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata); + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; + repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_data_cb, &cbdata); } } if (xd->len - cbdata.lastlen > cbdata.maxdata) @@ -1841,11 +1893,8 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); } assert(cbdata.current_sub == cbdata.nsubschemata); - if (cbdata.subschemata) - { - cbdata.subschemata = solv_free(cbdata.subschemata); - cbdata.nsubschemata = 0; - } + cbdata.subschemata = solv_free(cbdata.subschemata); + cbdata.nsubschemata = 0; /********************************************************************/ @@ -1862,7 +1911,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); write_u32(&target, nstrings); write_u32(&target, nrels); write_u32(&target, ndirmap); - write_u32(&target, anysolvableused ? repo->nsolvables : 0); + write_u32(&target, anysolvableused ? nsolvables : 0); write_u32(&target, target.nkeys); write_u32(&target, target.nschemata); solv_flags = 0; @@ -1917,9 +1966,9 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); */ for (i = 0; i < nrels; i++) { - ran = pool->rels + (needid[reloff + i].map - reloff); - write_id(&target, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need); - write_id(&target, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need); + Reldep *ran = pool->rels + (needid[reloff + i].map - reloff); + write_id(&target, needid[NEEDIDOFF(ran->name)].need); + write_id(&target, needid[NEEDIDOFF(ran->evr)].need); write_u8(&target, ran->flags); } @@ -1961,52 +2010,60 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); for (i = 1; i < target.nschemata; i++) write_idarray(&target, pool, 0, repodata_id2schema(&target, i)); -/********************************************************************/ - + /* + * write incore data + */ write_id(&target, cbdata.maxdata); write_id(&target, cbdata.extdata[0].len); if (cbdata.extdata[0].len) write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len); solv_free(cbdata.extdata[0].buf); - /* do we have vertical data? */ + /* + * write vertical data if we have any + */ for (i = 1; i < target.nkeys; i++) if (cbdata.extdata[i].len) break; if (i < target.nkeys) { - /* yes, write it in pages */ + /* have vertical data, write it in pages */ unsigned char vpage[REPOPAGE_BLOBSIZE]; int lpage = 0; write_u32(&target, REPOPAGE_BLOBSIZE); - for (i = 1; i < target.nkeys; i++) - if (cbdata.extdata[i].len) - { - if (cbdata.filelistmode) - break; - lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage); - } - if (cbdata.filelistmode && i < target.nkeys) + if (!cbdata.filelistmode) { - /* ok, just this single extdata, which is a filelist */ + for (i = 1; i < target.nkeys; i++) + if (cbdata.extdata[i].len) + lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage); + } + else + { + /* ok, just one single extdata which is of type REPOKEY_TYPE_DIRSTRARRAY */ xd = cbdata.extdata + i; xd->len = 0; - cbdata.filelistmode = -1; - for (j = 0; j < cbdata.nkeymap; j++) - if (cbdata.keymap[j] != i) - cbdata.keymap[j] = 0; - for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++) + keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip); + FOR_REPODATAS(repo, j, data) + { + if (!repodataused[j]) + continue; + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; + repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_filelist_cb, &cbdata); + } + for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++) { if (s->repo != repo) continue; + keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip); FOR_REPODATAS(repo, j, data) { - if (!repodataused[j]) - continue; - if (i < data->start || i >= data->end) + if (!repodataused[j] || i < data->start || i >= data->end) continue; - repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata); + cbdata.keymap = keymap + keymapstart[j]; + cbdata.lastdirid = 0; + repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_filelist_cb, &cbdata); } if (xd->len > 1024 * 1024) { @@ -2029,56 +2086,64 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1); repodata_freedata(&target); solv_free(needid); - solv_free(cbdata.solvschemata); + solv_free(solvschemata); solv_free(cbdata.schema); - solv_free(cbdata.keymap); - solv_free(cbdata.keymapstart); + solv_free(keymap); + solv_free(keymapstart); solv_free(cbdata.dirused); solv_free(repodataused); + solv_free(oldkeyskip); return target.error; } -struct repodata_write_data { - int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata); - void *kfdata; - int repodataid; -}; - -static int -repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata) +int +repo_write(Repo *repo, FILE *fp) { - struct repodata_write_data *wd = kfdata; - - /* XXX: special repodata selection hack */ - if (key->name == 1 && key->size != wd->repodataid) - return -1; - if (key->storage == KEY_STORAGE_SOLVABLE) - return KEY_STORAGE_DROPPED; /* not part of this repodata */ - if (wd->keyfilter) - return (*wd->keyfilter)(repo, key, wd->kfdata); - return key->storage; + int res; + Repowriter *writer = repowriter_create(repo); + res = repowriter_write(writer, fp); + repowriter_free(writer); + return res; } int -repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) +repodata_write(Repodata *data, FILE *fp) { - struct repodata_write_data wd; - - wd.keyfilter = keyfilter; - wd.kfdata = kfdata; - wd.repodataid = data->repodataid; - return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq); + int res; + Repowriter *writer = repowriter_create(data->repo); + repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1); + repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE); + res = repowriter_write(writer, fp); + repowriter_free(writer); + return res; } +/* deprecated functions, do not use in new code! */ int -repodata_write(Repodata *data, FILE *fp) +repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) { - return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0); + int res; + Repowriter *writer = repowriter_create(repo); + repowriter_set_flags(writer, REPOWRITER_LEGACY); + repowriter_set_keyfilter(writer, keyfilter, kfdata); + repowriter_set_keyqueue(writer, keyq); + res = repowriter_write(writer, fp); + repowriter_free(writer); + return res; } int -repo_write(Repo *repo, FILE *fp) +repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq) { - return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0); + int res; + Repowriter *writer = repowriter_create(data->repo); + repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1); + repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE | REPOWRITER_LEGACY); + repowriter_set_keyfilter(writer, keyfilter, kfdata); + repowriter_set_keyqueue(writer, keyq); + res = repowriter_write(writer, fp); + repowriter_free(writer); + return res; } + diff --git a/libsolv-0.7.2/src/repo_write.h b/libsolv-0.7.2/src/repo_write.h new file mode 100644 index 0000000..3471670 --- /dev/null +++ b/libsolv-0.7.2/src/repo_write.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * repo_write.h + * + */ + +#ifndef REPO_WRITE_H +#define REPO_WRITE_H + +#include + +#include "repo.h" +#include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct s_Repowriter { + Repo *repo; + int flags; + int repodatastart; + int repodataend; + int solvablestart; + int solvableend; + int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata); + void *kfdata; + Queue *keyq; +} Repowriter; + +/* repowriter flags */ +#define REPOWRITER_NO_STORAGE_SOLVABLE (1 << 0) +#define REPOWRITER_KEEP_TYPE_DELETED (1 << 1) +#define REPOWRITER_LEGACY (1 << 30) + +Repowriter *repowriter_create(Repo *repo); +Repowriter *repowriter_free(Repowriter *writer); +void repowriter_set_flags(Repowriter *writer, int flags); +void repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata); +void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq); +void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend); +void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend); +int repowriter_write(Repowriter *writer, FILE *fp); + +/* convenience functions */ +extern int repo_write(Repo *repo, FILE *fp); +extern int repodata_write(Repodata *data , FILE *fp); + +extern int repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata); + +/* deprecated functions, do not use in new code! */ +extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq); +extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libsolv-0.6.15/src/repodata.c b/libsolv-0.7.2/src/repodata.c similarity index 85% rename from libsolv-0.6.15/src/repodata.c rename to libsolv-0.7.2/src/repodata.c index ad3e71a..71e8175 100644 --- a/libsolv-0.6.15/src/repodata.c +++ b/libsolv-0.7.2/src/repodata.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Novell Inc. + * Copyright (c) 2018, SUSE LLC. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -94,6 +94,8 @@ repodata_freedata(Repodata *data) solv_free(data->attrnum64data); solv_free(data->dircache); + + repodata_free_filelistfilter(data); } void @@ -268,17 +270,13 @@ repodata_str2dir(Repodata *data, const char *dir, int create) #endif const char *dire; - parent = 0; if (!*dir) - return 0; + return data->dirpool.ndirs ? 0 : dirpool_add_dir(&data->dirpool, 0, 0, create); while (*dir == '/' && dir[1] == '/') dir++; if (*dir == '/' && !dir[1]) - { - if (data->dirpool.ndirs) - return 1; - return dirpool_add_dir(&data->dirpool, 0, 1, create); - } + return data->dirpool.ndirs ? 1 : dirpool_add_dir(&data->dirpool, 0, 1, create); + parent = 0; #ifdef DIRCACHE_SIZE dirs = dir; if (data->dircache) @@ -355,6 +353,8 @@ repodata_dir2str(Repodata *data, Id did, const char *suf) if (!did) return suf ? suf : ""; + if (did == 1 && !suf) + return "/"; parent = did; while (parent) { @@ -520,17 +520,36 @@ get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance) return 0; } -static int -load_repodata(Repodata *data) +void +repodata_load(Repodata *data) { + if (data->state != REPODATA_STUB) + return; if (data->loadcallback) + data->loadcallback(data); + else + data->state = REPODATA_ERROR; +} + +static int +maybe_load_repodata_stub(Repodata *data, Id keyname) +{ + if (data->state != REPODATA_STUB) { - data->loadcallback(data); - if (data->state == REPODATA_AVAILABLE) - return 1; + data->state = REPODATA_ERROR; + return 0; } - data->state = REPODATA_ERROR; - return 0; + if (keyname) + { + int i; + for (i = 1; i < data->nkeys; i++) + if (keyname == data->keys[i].name) + break; + if (i == data->nkeys) + return 0; + } + repodata_load(data); + return data->state == REPODATA_AVAILABLE ? 1 : 0; } static inline int @@ -538,28 +557,11 @@ maybe_load_repodata(Repodata *data, Id keyname) { if (keyname && !repodata_precheck_keyname(data, keyname)) return 0; /* do not bother... */ - switch(data->state) - { - case REPODATA_STUB: - if (keyname) - { - int i; - for (i = 1; i < data->nkeys; i++) - if (keyname == data->keys[i].name) - break; - if (i == data->nkeys) - return 0; - } - return load_repodata(data); - case REPODATA_ERROR: - return 0; - case REPODATA_AVAILABLE: - case REPODATA_LOADING: - return 1; - default: - data->state = REPODATA_ERROR; - return 0; - } + if (data->state == REPODATA_AVAILABLE || data->state == REPODATA_LOADING) + return 1; + if (data->state == REPODATA_ERROR) + return 0; + return maybe_load_repodata_stub(data, keyname); } static inline unsigned char * @@ -628,6 +630,53 @@ find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp) return get_data(data, key, &dp, 0); } +static const Id * +repodata_lookup_schemakeys(Repodata *data, Id solvid) +{ + Id schema; + if (!maybe_load_repodata(data, 0)) + return 0; + if (!solvid2data(data, solvid, &schema)) + return 0; + return data->schemadata + data->schemata[schema]; +} + +static Id * +alloc_keyskip() +{ + Id *keyskip = solv_calloc(3 + 256, sizeof(Id)); + keyskip[0] = 256; + keyskip[1] = keyskip[2] = 1; + return keyskip; +} + +Id * +repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip) +{ + const Id *keyp; + Id maxkeyname, value; + keyp = repodata_lookup_schemakeys(data, solvid); + if (!keyp) + return keyskip; /* no keys for this solvid */ + if (!keyskip) + keyskip = alloc_keyskip(); + maxkeyname = keyskip[0]; + value = keyskip[1] + data->repodataid; + for (; *keyp; keyp++) + { + Id keyname = data->keys[*keyp].name; + if (keyname >= maxkeyname) + { + int newmax = (keyname | 255) + 1; + keyskip = solv_realloc2(keyskip, 3 + newmax, sizeof(Id)); + memset(keyskip + (3 + maxkeyname), 0, (newmax - maxkeyname) * sizeof(Id)); + keyskip[0] = maxkeyname = newmax; + } + keyskip[3 + keyname] = value; + } + return keyskip; +} + Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname) { @@ -684,52 +733,32 @@ repodata_lookup_str(Repodata *data, Id solvid, Id keyname) return pool_id2str(data->repo->pool, id); } -int -repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value) +unsigned long long +repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound) { unsigned char *dp; Repokey *key; unsigned int high, low; - *value = 0; dp = find_key_data(data, solvid, keyname, &key); if (!dp) - return 0; + return notfound; switch (key->type) { case REPOKEY_TYPE_NUM: data_read_num64(dp, &low, &high); - *value = (unsigned long long)high << 32 | low; - return 1; - case REPOKEY_TYPE_U32: - data_read_u32(dp, &low); - *value = low; - return 1; + return (unsigned long long)high << 32 | low; case REPOKEY_TYPE_CONSTANT: - *value = key->size; - return 1; + return key->size; default: - return 0; + return notfound; } } int repodata_lookup_void(Repodata *data, Id solvid, Id keyname) { - Id schema; - Id *keyp; - unsigned char *dp; - - if (!maybe_load_repodata(data, keyname)) - return 0; - dp = solvid2data(data, solvid, &schema); - if (!dp) - return 0; - /* can't use find_key_data as we need to test the type */ - for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++) - if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID) - return 1; - return 0; + return repodata_lookup_type(data, solvid, keyname) == REPOKEY_TYPE_VOID ? 1 : 0; } const unsigned char * @@ -762,9 +791,7 @@ repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q) queue_empty(q); dp = find_key_data(data, solvid, keyname, &key); - if (!dp) - return 0; - if (key->type != REPOKEY_TYPE_IDARRAY) + if (!dp || key->type != REPOKEY_TYPE_IDARRAY) return 0; for (;;) { @@ -794,6 +821,48 @@ repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp) return dp; } +/* highly specialized function to speed up fileprovides adding. + * - repodata must be available + * - solvid must be >= data->start and < data->end + * - returns NULL is not found, a "" entry if wrong type + * - also returns wrong type for REPOKEY_TYPE_DELETED + */ +const unsigned char * +repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname) +{ + static unsigned char wrongtype[2] = { 0x00 /* dir id 0 */, 0 /* "" */ }; + unsigned char *dp; + Id schema, *keyp, *kp; + Repokey *key; + + if (!data->incoredata || !data->incoreoffset[solvid - data->start]) + return 0; + dp = data->incoredata + data->incoreoffset[solvid - data->start]; + dp = data_read_id(dp, &schema); + keyp = data->schemadata + data->schemata[schema]; + for (kp = keyp; *kp; kp++) + if (data->keys[*kp].name == keyname) + break; + if (!*kp) + return 0; + key = data->keys + *kp; + if (key->type != REPOKEY_TYPE_DIRSTRARRAY) + return wrongtype; + dp = forward_to_key(data, *kp, keyp, dp); + if (key->storage == KEY_STORAGE_INCORE) + return dp; + if (key->storage == KEY_STORAGE_VERTICAL_OFFSET && dp) + { + Id off, len; + dp = data_read_id(dp, &off); + data_read_id(dp, &len); + return get_vertical_data(data, key, off, len); + } + return 0; +} + +/* id translation functions */ + Id repodata_globalize_id(Repodata *data, Id id, int create) { @@ -813,72 +882,172 @@ repodata_localize_id(Repodata *data, Id id, int create) Id repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create) { + const char *s; if (!id || !data || !fromdata) return id; - if (!data->localpool || !fromdata->localpool) + if (data == fromdata || (!data->localpool && !fromdata->localpool)) + return id; + if (fromdata->localpool) + s = stringpool_id2str(&fromdata->spool, id); + else + s = pool_id2str(data->repo->pool, id); + if (data->localpool) + return stringpool_str2id(&data->spool, s, create); + else + return pool_str2id(data->repo->pool, s, create); +} + +Id +repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache) +{ + Id parent, compid; + if (!dir) { - if (fromdata->localpool) - id = repodata_globalize_id(fromdata, id, create); - if (data->localpool) - id = repodata_localize_id(data, id, create); - return id; + /* make sure that the dirpool has an entry */ + if (create && !data->dirpool.ndirs) + dirpool_add_dir(&data->dirpool, 0, 0, create); + return 0; + } + parent = dirpool_parent(&fromdata->dirpool, dir); + if (parent) + { + if (!(parent = repodata_translate_dir(data, fromdata, parent, create, cache))) + return 0; + } + compid = dirpool_compid(&fromdata->dirpool, dir); + if (compid > 1 && (data->localpool || fromdata->localpool)) + { + if (!(compid = repodata_translate_id(data, fromdata, compid, create))) + return 0; } - /* localpool is set in both data and fromdata */ - return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create); + if (!(compid = dirpool_add_dir(&data->dirpool, parent, compid, create))) + return 0; + if (cache) + { + cache[(dir & 255) * 2] = dir; + cache[(dir & 255) * 2 + 1] = compid; + } + return compid; } -Id -repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid) +/************************************************************************ + * uninternalized lookup / search + */ + +static void +data_fetch_uninternalized(Repodata *data, Repokey *key, Id value, KeyValue *kv) +{ + Id *array; + kv->eof = 1; + switch (key->type) + { + case REPOKEY_TYPE_STR: + kv->str = (const char *)data->attrdata + value; + return; + case REPOKEY_TYPE_CONSTANT: + kv->num2 = 0; + kv->num = key->size; + return; + case REPOKEY_TYPE_CONSTANTID: + kv->id = key->size; + return; + case REPOKEY_TYPE_NUM: + kv->num2 = 0; + kv->num = value; + if (value & 0x80000000) + { + kv->num = (unsigned int)data->attrnum64data[value ^ 0x80000000]; + kv->num2 = (unsigned int)(data->attrnum64data[value ^ 0x80000000] >> 32); + } + return; + case_CHKSUM_TYPES: + kv->num = 0; /* not stringified */ + kv->str = (const char *)data->attrdata + value; + return; + case REPOKEY_TYPE_BINARY: + kv->str = (const char *)data_read_id(data->attrdata + value, (Id *)&kv->num); + return; + case REPOKEY_TYPE_IDARRAY: + array = data->attriddata + (value + kv->entry); + kv->id = array[0]; + kv->eof = array[1] ? 0 : 1; + return; + case REPOKEY_TYPE_DIRSTRARRAY: + kv->num = 0; /* not stringified */ + array = data->attriddata + (value + kv->entry * 2); + kv->id = array[0]; + kv->str = (const char *)data->attrdata + array[1]; + kv->eof = array[2] ? 0 : 1; + return; + case REPOKEY_TYPE_DIRNUMNUMARRAY: + array = data->attriddata + (value + kv->entry * 3); + kv->id = array[0]; + kv->num = array[1]; + kv->num2 = array[2]; + kv->eof = array[3] ? 0 : 1; + return; + case REPOKEY_TYPE_FIXARRAY: + case REPOKEY_TYPE_FLEXARRAY: + array = data->attriddata + (value + kv->entry); + kv->id = array[0]; /* the handle */ + kv->eof = array[1] ? 0 : 1; + return; + default: + kv->id = value; + return; + } +} + +Repokey * +repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, KeyValue *kv) { Id *ap; - if (!data->attrs) + if (!data->attrs || solvid < data->start || solvid >= data->end) return 0; ap = data->attrs[solvid - data->start]; if (!ap) return 0; for (; *ap; ap += 2) { - if (data->keys[*ap].name != keyname) + Repokey *key = data->keys + *ap; + if (key->name != keyname) continue; - if (data->keys[*ap].type == REPOKEY_TYPE_VOID) - return voidid; - if (data->keys[*ap].type == REPOKEY_TYPE_ID) - return ap[1]; - return 0; + data_fetch_uninternalized(data, key, ap[1], kv); + return key; } return 0; } -const char * -repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp) +void +repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) { - Id *ap, did; - Id iter = *iterp; - if (iter == 0) /* find key data */ - { - if (!data->attrs) - return 0; - ap = data->attrs[solvid - data->start]; - if (!ap) - return 0; - for (; *ap; ap += 2) - if (data->keys[*ap].name == keyname && data->keys[*ap].type == REPOKEY_TYPE_DIRSTRARRAY) - break; - if (!*ap) - return 0; - iter = ap[1]; - } - did = *didp; - for (ap = data->attriddata + iter; *ap; ap += 2) + Id *ap; + int stop; + Solvable *s; + KeyValue kv; + + if (!data->attrs || solvid < data->start || solvid >= data->end) + return; + ap = data->attrs[solvid - data->start]; + if (!ap) + return; + for (; *ap; ap += 2) { - if (did && ap[0] != did) + Repokey *key = data->keys + *ap; + if (keyname && key->name != keyname) continue; - *didp = ap[0]; - *iterp = ap - data->attriddata + 2; - return (const char *)data->attrdata + ap[1]; + s = solvid > 0 ? data->repo->pool->solvables + solvid : 0; + kv.entry = 0; + do + { + data_fetch_uninternalized(data, key, ap[1], &kv); + stop = callback(cbdata, s, data, key, &kv); + kv.entry++; + } + while (!kv.eof && !stop); + if (keyname || stop > SEARCH_NEXT_KEY) + return; } - *iterp = 0; - return 0; } /************************************************************************ @@ -898,7 +1067,7 @@ repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int f kv->str = stringpool_id2str(&data->spool, kv->id); else kv->str = pool_id2str(pool, kv->id); - if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE) + if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE && (key->name == SOLVABLE_NAME || key->type == REPOKEY_TYPE_IDARRAY)) { const char *s; for (s = kv->str; *s >= 'a' && *s <= 'z'; s++) @@ -932,15 +1101,59 @@ repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int f } +/* this is an internal hack to pass the parent kv to repodata_search_keyskip */ struct subschema_data { - Solvable *s; void *cbdata; + Id solvid; KeyValue *parent; }; +void +repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) +{ + repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata); +} + +static int +repodata_search_array(Repodata *data, Id solvid, Id keyname, int flags, Repokey *key, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) +{ + Solvable *s = solvid > 0 ? data->repo->pool->solvables + solvid : 0; + unsigned char *dp = (unsigned char *)kv->str; + int stop; + Id schema = 0; + + if (!dp || kv->entry != -1) + return 0; + while (++kv->entry < kv->num) + { + if (kv->entry) + dp = data_skip_schema(data, dp, schema); + if (kv->entry == 0 || key->type == REPOKEY_TYPE_FLEXARRAY) + dp = data_read_id(dp, &schema); + kv->id = schema; + kv->str = (const char *)dp; + kv->eof = kv->entry == kv->num - 1 ? 1 : 0; + stop = callback(cbdata, s, data, key, kv); + if (stop && stop != SEARCH_ENTERSUB) + return stop; + if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB) + repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata); + } + if ((flags & SEARCH_ARRAYSENTINEL) != 0) + { + if (kv->entry) + dp = data_skip_schema(data, dp, schema); + kv->id = 0; + kv->str = (const char *)dp; + kv->eof = 2; + return callback(cbdata, s, data, key, kv); + } + return 0; +} + /* search a specific repodata */ void -repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) +repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) { Id schema; Repokey *key; @@ -953,14 +1166,13 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback if (!maybe_load_repodata(data, keyname)) return; - if (solvid == SOLVID_SUBSCHEMA) + if ((flags & SEARCH_SUBSCHEMA) != 0) { - struct subschema_data *subd = cbdata; - cbdata = subd->cbdata; - s = subd->s; - schema = subd->parent->id; - dp = (unsigned char *)subd->parent->str; - kv.parent = subd->parent; + flags ^= SEARCH_SUBSCHEMA; + kv.parent = (KeyValue *)keyskip; + keyskip = 0; + schema = kv.parent->id; + dp = (unsigned char *)kv.parent->str; } else { @@ -968,9 +1180,9 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback dp = solvid2data(data, solvid, &schema); if (!dp) return; - s = data->repo->pool->solvables + solvid; kv.parent = 0; } + s = solvid > 0 ? data->repo->pool->solvables + solvid : 0; keyp = data->schemadata + data->schemata[schema]; if (keyname) { @@ -990,54 +1202,30 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback { stop = 0; key = data->keys + keyid; - ddp = get_data(data, key, &dp, *keyp ? 1 : 0); + ddp = get_data(data, key, &dp, *keyp && !onekey ? 1 : 0); - if (key->type == REPOKEY_TYPE_DELETED) - continue; - if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY) + if (keyskip && (key->name >= keyskip[0] || keyskip[3 + key->name] != keyskip[1] + data->repodataid)) + { + if (onekey) + return; + continue; + } + if (key->type == REPOKEY_TYPE_DELETED && !(flags & SEARCH_KEEP_TYPE_DELETED)) { - struct subschema_data subd; - int nentries; - Id schema = 0; - - subd.cbdata = cbdata; - subd.s = s; - subd.parent = &kv; - ddp = data_read_id(ddp, &nentries); - kv.num = nentries; - kv.entry = 0; - kv.eof = 0; - while (ddp && nentries > 0) - { - if (!--nentries) - kv.eof = 1; - if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry) - ddp = data_read_id(ddp, &schema); - kv.id = schema; - kv.str = (char *)ddp; - stop = callback(cbdata, s, data, key, &kv); - if (stop > SEARCH_NEXT_KEY) - return; - if (stop && stop != SEARCH_ENTERSUB) - break; - if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB) - repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd); - ddp = data_skip_schema(data, ddp, schema); - kv.entry++; - } - if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0) - { - /* sentinel */ - kv.eof = 2; - kv.str = (char *)ddp; - stop = callback(cbdata, s, data, key, &kv); - if (stop > SEARCH_NEXT_KEY) - return; - } if (onekey) return; continue; } + if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY) + { + kv.entry = -1; + ddp = data_read_id(ddp, (Id *)&kv.num); + kv.str = (const char *)ddp; + stop = repodata_search_array(data, solvid, 0, flags, key, &kv, callback, cbdata); + if (onekey || stop > SEARCH_NEXT_KEY) + return; + continue; + } kv.entry = 0; do { @@ -1054,6 +1242,12 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback } void +repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata) +{ + repodata_search_keyskip(data, solvid, keyname, flags, 0, callback, cbdata); +} + +void repodata_setpos_kv(Repodata *data, KeyValue *kv) { Pool *pool = data->repo->pool; @@ -1244,21 +1438,6 @@ datamatcher_checkbasename(Datamatcher *ma, const char *basename) return !strcmp(match, basename); } -int -repodata_filelistfilter_matches(Repodata *data, const char *str) -{ - /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */ - /* for now hardcoded */ - if (strstr(str, "bin/")) - return 1; - if (!strncmp(str, "/etc/", 5)) - return 1; - if (!strcmp(str, "/usr/lib/sendmail")) - return 1; - return 0; -} - - enum { di_bye, @@ -1337,6 +1516,10 @@ dataiterator_init_clone(Dataiterator *di, Dataiterator *from) di->parents[i].kv.parent = &di->parents[i - 1].kv; di->kv.parent = &di->parents[di->nparents - 1].kv; } + if (di->oldkeyskip) + di->oldkeyskip = solv_memdup2(di->oldkeyskip, 3 + di->oldkeyskip[0], sizeof(Id)); + if (di->keyskip) + di->keyskip = di->oldkeyskip; } int @@ -1412,6 +1595,8 @@ dataiterator_free(Dataiterator *di) datamatcher_free(&di->matcher); if (di->dupstr) solv_free(di->dupstr); + if (di->oldkeyskip) + solv_free(di->oldkeyskip); } static unsigned char * @@ -1438,88 +1623,21 @@ dataiterator_find_keyname(Dataiterator *di, Id keyname) return dp; } -static inline int -is_filelist_extension(Repodata *data) -{ - int j; - if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST)) - return 0; - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name == SOLVABLE_FILELIST) - break; - if (j == data->nkeys) - return 0; - if (data->state != REPODATA_AVAILABLE) - return 1; - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - return 0; - return 1; -} - -static int -dataiterator_filelistcheck(Dataiterator *di) -{ - int j; - int needcomplete = 0; - Repodata *data = di->data; - - if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0) - if (!di->matcher.match - || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING - && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB) - || !repodata_filelistfilter_matches(data, di->matcher.match)) - needcomplete = 1; - if (data->state != REPODATA_AVAILABLE) - return needcomplete ? 1 : 0; - if (!needcomplete) - { - /* we don't need the complete filelist, so ignore all stubs */ - if (data->repo->nrepodata == 2) - return 1; - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - return 1; - return 0; - } - else - { - /* we need the complete filelist. check if we habe a filtered filelist and there's - * a extension with the complete filelist later on */ - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name == SOLVABLE_FILELIST) - break; - if (j == data->nkeys) - return 0; /* does not have filelist */ - for (j = 1; j < data->nkeys; j++) - if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) - break; - if (j == data->nkeys) - return 1; /* this is the externsion */ - while (data - data->repo->repodata + 1 < data->repo->nrepodata) - { - data++; - if (is_filelist_extension(data)) - return 0; - } - return 1; - } -} - int dataiterator_step(Dataiterator *di) { Id schema; - if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) { - unsigned int ddpoff = di->ddp - di->vert_ddp; - di->vert_off += ddpoff; - di->vert_len -= ddpoff; - di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len); - di->vert_storestate = di->data->storestate; - if (!di->ddp) - di->state = di_nextkey; - } + if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) + { + unsigned int ddpoff = di->ddp - di->vert_ddp; + di->vert_off += ddpoff; + di->vert_len -= ddpoff; + di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len); + di->vert_storestate = di->data->storestate; + if (!di->ddp) + di->state = di_nextkey; + } for (;;) { switch (di->state) @@ -1535,18 +1653,28 @@ dataiterator_step(Dataiterator *di) /* FALLTHROUGH */ case di_entersolvable: di_entersolvable: - if (di->repodataid) + if (!di->repodataid) + goto di_enterrepodata; /* POS case, repodata is set */ + if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames) { - di->repodataid = 1; /* reset repodata iterator */ - if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames) - { - extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1]; + extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1]; + di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0); + di->data = 0; + goto di_entersolvablekey; + } - di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0); - di->data = 0; - goto di_entersolvablekey; - } + if (di->keyname) + { + di->data = di->keyname == SOLVABLE_FILELIST ? repo_lookup_filelist_repodata(di->repo, di->solvid, &di->matcher) : repo_lookup_repodata_opt(di->repo, di->solvid, di->keyname); + if (!di->data) + goto di_nextsolvable; + di->repodataid = di->data - di->repo->repodata; + di->keyskip = 0; + goto di_enterrepodata; } + di_leavesolvablekey: + di->repodataid = 1; /* reset repodata iterator */ + di->keyskip = repo_create_keyskip(di->repo, di->solvid, &di->oldkeyskip); /* FALLTHROUGH */ case di_enterrepodata: di_enterrepodata: @@ -1556,8 +1684,6 @@ dataiterator_step(Dataiterator *di) goto di_nextsolvable; di->data = di->repo->repodata + di->repodataid; } - if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di)) - goto di_nextrepodata; if (!maybe_load_repodata(di->data, di->keyname)) goto di_nextrepodata; di->dp = solvid2data(di->data, di->solvid, &schema); @@ -1598,15 +1724,17 @@ dataiterator_step(Dataiterator *di) } else if (di->key->storage == KEY_STORAGE_INCORE) { - di->ddp = di->dp; + di->ddp = di->dp; /* start of data */ if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0)) - di->dp = data_skip_key(di->data, di->dp, di->key); + di->dp = data_skip_key(di->data, di->dp, di->key); /* advance to next key */ } else di->ddp = 0; if (!di->ddp) goto di_nextkey; - if (di->key->type == REPOKEY_TYPE_DELETED) + if (di->keyskip && (di->key->name >= di->keyskip[0] || di->keyskip[3 + di->key->name] != di->keyskip[1] + di->data->repodataid)) + goto di_nextkey; + if (di->key->type == REPOKEY_TYPE_DELETED && !(di->flags & SEARCH_KEEP_TYPE_DELETED)) goto di_nextkey; if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY) goto di_enterarray; @@ -1617,10 +1745,7 @@ dataiterator_step(Dataiterator *di) case di_nextattr: di->kv.entry++; di->ddp = data_fetch(di->ddp, &di->kv, di->key); - if (di->kv.eof) - di->state = di_nextkey; - else - di->state = di_nextattr; + di->state = di->kv.eof ? di_nextkey : di_nextattr; break; case di_nextkey: di_nextkey: @@ -1631,7 +1756,7 @@ dataiterator_step(Dataiterator *di) /* FALLTHROUGH */ case di_nextrepodata: di_nextrepodata: - if (di->repodataid && ++di->repodataid < di->repo->nrepodata) + if (!di->keyname && di->repodataid && ++di->repodataid < di->repo->nrepodata) goto di_enterrepodata; /* FALLTHROUGH */ @@ -1732,8 +1857,10 @@ dataiterator_step(Dataiterator *di) /* special solvable attr handling follows */ case di_nextsolvablekey: di_nextsolvablekey: - if (di->keyname || di->key->name == RPM_RPMDBID) - goto di_enterrepodata; + if (di->keyname) + goto di_nextsolvable; + if (di->key->name == RPM_RPMDBID) /* reached end of list? */ + goto di_leavesolvablekey; di->key++; /* FALLTHROUGH */ @@ -1767,6 +1894,7 @@ dataiterator_step(Dataiterator *di) } + /* we have a potential match */ if (di->matcher.match) { const char *str; @@ -1774,6 +1902,7 @@ dataiterator_step(Dataiterator *di) if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0) if (!datamatcher_checkbasename(&di->matcher, di->kv.str)) continue; + /* now stringify so that we can do the matching */ if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))) { if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)) @@ -1785,6 +1914,7 @@ dataiterator_step(Dataiterator *di) } else { + /* stringify filelist if requested */ if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0) repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags); } @@ -2765,22 +2895,63 @@ repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, } void -repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle) +repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id handle) { repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1); - data->attriddata[data->attriddatalen++] = ghandle; + data->attriddata[data->attriddatalen++] = handle; data->attriddata[data->attriddatalen++] = 0; } void -repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle) +repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id handle) { repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1); - data->attriddata[data->attriddatalen++] = ghandle; + data->attriddata[data->attriddatalen++] = handle; data->attriddata[data->attriddatalen++] = 0; } void +repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, KeyValue *kv) +{ + switch (keytype) + { + case REPOKEY_TYPE_ID: + repodata_set_id(data, solvid, keyname, kv->id); + break; + case REPOKEY_TYPE_CONSTANTID: + repodata_set_constantid(data, solvid, keyname, kv->id); + break; + case REPOKEY_TYPE_IDARRAY: + repodata_add_idarray(data, solvid, keyname, kv->id); + break; + case REPOKEY_TYPE_STR: + repodata_set_str(data, solvid, keyname, kv->str); + break; + case REPOKEY_TYPE_VOID: + repodata_set_void(data, solvid, keyname); + break; + case REPOKEY_TYPE_NUM: + repodata_set_num(data, solvid, keyname, SOLV_KV_NUM64(kv)); + break; + case REPOKEY_TYPE_CONSTANT: + repodata_set_constant(data, solvid, keyname, kv->num); + break; + case REPOKEY_TYPE_DIRNUMNUMARRAY: + if (kv->id) + repodata_add_dirnumnum(data, solvid, keyname, kv->id, kv->num, kv->num2); + break; + case REPOKEY_TYPE_DIRSTRARRAY: + repodata_add_dirstr(data, solvid, keyname, kv->id, kv->str); + break; + case_CHKSUM_TYPES: + repodata_set_bin_checksum(data, solvid, keyname, keytype, (const unsigned char *)kv->str); + break; + default: + break; + } +} + +void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname) { Id *pp, *ap, **app; @@ -2805,7 +2976,6 @@ repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname) *pp = 0; } -/* XXX: does not work correctly, needs fix in iterators! */ void repodata_unset(Repodata *data, Id solvid, Id keyname) { @@ -3489,7 +3659,6 @@ entrydone: data->incoredatalen = newincore.len; data->incoredatafree = 0; - solv_free(data->vincore); data->vincore = newvincore.buf; data->vincorelen = newvincore.len; @@ -3516,13 +3685,14 @@ repodata_disable_paging(Repodata *data) } } +/* call the pool's loadcallback to load a stub repodata */ static void -repodata_load_stub(Repodata *data) +repodata_stub_loader(Repodata *data) { Repo *repo = data->repo; Pool *pool = repo->pool; int r, i; - struct _Pool_tmpspace oldtmpspace; + struct s_Pool_tmpspace oldtmpspace; Datapos oldpos; if (!pool->loadcallback) @@ -3573,7 +3743,7 @@ repodata_add_stub(Repodata **datap) if (data->end > data->start) repodata_extend_block(sdata, data->start, data->end - data->start); sdata->state = REPODATA_STUB; - sdata->loadcallback = repodata_load_stub; + sdata->loadcallback = repodata_stub_loader; *datap = data; return sdata; } @@ -3616,44 +3786,21 @@ repodata_create_stubs(Repodata *data) xkeyname = 0; continue; } - switch (di.key->type) + repodata_set_kv(sdata, SOLVID_META, di.key->name, di.key->type, &di.kv); + if (di.key->name == REPOSITORY_KEYS && di.key->type == REPOKEY_TYPE_IDARRAY) { - case REPOKEY_TYPE_ID: - repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id); - break; - case REPOKEY_TYPE_CONSTANTID: - repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id); - break; - case REPOKEY_TYPE_STR: - repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str); - break; - case REPOKEY_TYPE_VOID: - repodata_set_void(sdata, SOLVID_META, di.key->name); - break; - case REPOKEY_TYPE_NUM: - repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv)); - break; - case_CHKSUM_TYPES: - repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str); - break; - case REPOKEY_TYPE_IDARRAY: - repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id); - if (di.key->name == REPOSITORY_KEYS) + if (!xkeyname) { - if (!xkeyname) - { - if (!di.kv.eof) - xkeyname = di.kv.id; - } - else - { - repodata_add_stubkey(sdata, xkeyname, di.kv.id); - xkeyname = 0; - } + if (!di.kv.eof) + xkeyname = di.kv.id; + } + else + { + repodata_add_stubkey(sdata, xkeyname, di.kv.id); + if (xkeyname == SOLVABLE_FILELIST) + repodata_set_filelisttype(sdata, REPODATA_FILELIST_EXTENSION); + xkeyname = 0; } - break; - default: - break; } } dataiterator_free(&di); @@ -3663,6 +3810,12 @@ repodata_create_stubs(Repodata *data) return data; } +void +repodata_set_filelisttype(Repodata *data, int type) +{ + data->filelisttype = type; +} + unsigned int repodata_memused(Repodata *data) { diff --git a/libsolv-0.6.15/src/repodata.h b/libsolv-0.7.2/src/repodata.h similarity index 76% rename from libsolv-0.6.15/src/repodata.h rename to libsolv-0.7.2/src/repodata.h index c18c688..f204e34 100644 --- a/libsolv-0.6.15/src/repodata.h +++ b/libsolv-0.7.2/src/repodata.h @@ -34,10 +34,10 @@ extern "C" { #define SIZEOF_SHA384 48 #define SIZEOF_SHA512 64 -struct _Repo; -struct _KeyValue; +struct s_Repo; +struct s_KeyValue; -typedef struct _Repokey { +typedef struct s_Repokey { Id name; Id type; /* REPOKEY_TYPE_xxx */ unsigned int size; @@ -53,19 +53,26 @@ typedef struct _Repokey { struct dircache; #endif -typedef struct _Repodata { - Id repodataid; /* our id */ - struct _Repo *repo; /* back pointer to repo */ - +/* repodata states */ #define REPODATA_AVAILABLE 0 #define REPODATA_STUB 1 #define REPODATA_ERROR 2 #define REPODATA_STORE 3 #define REPODATA_LOADING 4 +/* repodata filelist types */ +/* note that FILELIST_FILTERED means that the data contains a filtered + * filelist *AND* that it is authoritative for all included solvables. */ +#define REPODATA_FILELIST_FILTERED 1 +#define REPODATA_FILELIST_EXTENSION 2 + +typedef struct s_Repodata { + Id repodataid; /* our id */ + struct s_Repo *repo; /* back pointer to repo */ + int state; /* available, stub or error */ - void (*loadcallback)(struct _Repodata *); + void (*loadcallback)(struct s_Repodata *); int start; /* start of solvables this repodata is valid for */ int end; /* last solvable + 1 of this repodata */ @@ -87,6 +94,10 @@ typedef struct _Repodata { FILE *fp; /* file pointer of solv file */ int error; /* corrupt solv file */ + int filelisttype; /* type of filelist */ + Id *filelistfilter; /* filelist filter used */ + char *filelistfilterdata; /* filelist filter string space */ + unsigned int schemadatalen; /* schema storage size */ Id *schematahash; /* unification helper */ @@ -132,18 +143,18 @@ typedef struct _Repodata { #define SOLVID_META -1 #define SOLVID_POS -2 -#define SOLVID_SUBSCHEMA -3 /* internal! */ /*----- * management functions */ -void repodata_initdata(Repodata *data, struct _Repo *repo, int localpool); +void repodata_initdata(Repodata *data, struct s_Repo *repo, int localpool); void repodata_freedata(Repodata *data); void repodata_free(Repodata *data); void repodata_empty(Repodata *data, int localpool); +void repodata_load(Repodata *data); /* * key management functions @@ -196,25 +207,34 @@ repodata_has_keyname(Repodata *data, Id keyname) /* search key (all keys, if keyname == 0) for Id * Call for each match */ -void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct _KeyValue *kv), void *cbdata); +void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata); +void repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata); +void repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, struct s_KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata); /* Make sure the found KeyValue has the "str" field set. Return "str" * if valid, NULL if not possible */ -const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct _KeyValue *kv, int flags); +const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct s_KeyValue *kv, int flags); +/* filelist filter support */ +void repodata_set_filelisttype(Repodata *data, int filelisttype); int repodata_filelistfilter_matches(Repodata *data, const char *str); - +void repodata_free_filelistfilter(Repodata *data); /* lookup functions */ Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname); Id repodata_lookup_id(Repodata *data, Id solvid, Id keyname); const char *repodata_lookup_str(Repodata *data, Id solvid, Id keyname); -int repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value); +unsigned long long repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound); int repodata_lookup_void(Repodata *data, Id solvid, Id keyname); const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep); int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q); const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp); +/* internal, used in fileprovides code */ +const unsigned char *repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname); + +/* internal, fill keyskip array with data */ +Id *repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip); /*----- * data assignment functions @@ -258,19 +278,20 @@ void repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type, const char *str); void repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q); - /* directory (for package file list) */ void repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2); void repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str); void repodata_free_dircache(Repodata *data); -/* Arrays */ +/* arrays */ void repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id); void repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, const char *str); void repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle); void repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle); +/* generic */ +void repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, struct s_KeyValue *kv); void repodata_unset(Repodata *data, Id solvid, Id keyname); void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname); @@ -293,6 +314,7 @@ void repodata_disable_paging(Repodata *data); Id repodata_globalize_id(Repodata *data, Id id, int create); Id repodata_localize_id(Repodata *data, Id id, int create); Id repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create); +Id repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache); Id repodata_str2dir(Repodata *data, const char *dir, int create); const char *repodata_dir2str(Repodata *data, Id did, const char *suf); @@ -300,12 +322,35 @@ const char *repodata_chk2str(Repodata *data, Id type, const unsigned char *buf); void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file); void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file); void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg); -Id repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid); -const char *repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp); + +/* uninternalized data lookup / search */ +Repokey *repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, struct s_KeyValue *kv); +void repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata); /* stats */ unsigned int repodata_memused(Repodata *data); +static inline Id +repodata_translate_dir(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache) +{ + if (cache && dir && cache[(dir & 255) * 2] == dir) + return cache[(dir & 255) * 2 + 1]; + return repodata_translate_dir_slow(data, fromdata, dir, create, cache); +} + +static inline Id * +repodata_create_dirtranscache(Repodata *data) +{ + return (Id *)solv_calloc(256, sizeof(Id) * 2); +} + +static inline Id * +repodata_free_dirtranscache(Id *cache) +{ + return (Id *)solv_free(cache); +} + + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/repopack.h b/libsolv-0.7.2/src/repopack.h similarity index 73% rename from libsolv-0.6.15/src/repopack.h rename to libsolv-0.7.2/src/repopack.h index 3079239..e63366d 100644 --- a/libsolv-0.6.15/src/repopack.h +++ b/libsolv-0.7.2/src/repopack.h @@ -129,13 +129,6 @@ data_read_ideof(unsigned char *dp, Id *idp, int *eof) } static inline unsigned char * -data_read_u32(unsigned char *dp, unsigned int *nump) -{ - *nump = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3]; - return dp + 4; -} - -static inline unsigned char * data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key) { kv->eof = 1; @@ -144,6 +137,7 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key) switch (key->type) { case REPOKEY_TYPE_VOID: + case REPOKEY_TYPE_DELETED: return dp; case REPOKEY_TYPE_CONSTANT: kv->num2 = 0; @@ -160,9 +154,6 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key) return data_read_id(dp, &kv->id); case REPOKEY_TYPE_NUM: return data_read_num64(dp, &kv->num, &kv->num2); - case REPOKEY_TYPE_U32: - kv->num2 = 0; - return data_read_u32(dp, &kv->num); case REPOKEY_TYPE_MD5: kv->num = 0; /* not stringified yet */ kv->str = (const char *)dp; @@ -203,10 +194,17 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key) dp = data_read_id(dp, (Id *)&kv->num); return data_read_ideof(dp, (Id *)&kv->num2, &kv->eof); case REPOKEY_TYPE_FIXARRAY: - dp = data_read_id(dp, (Id *)&kv->num); - return data_read_id(dp, &kv->id); case REPOKEY_TYPE_FLEXARRAY: - return data_read_id(dp, (Id *)&kv->num); + if (!kv->entry) + { + dp = data_read_id(dp, (Id *)&kv->num); /* number of elements */ + if (!kv->num) + return 0; /* illegal */ + } + if (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY) + dp = data_read_id(dp, &kv->id); /* schema */ + kv->str = (const char *)dp; + return dp; default: return 0; } @@ -229,8 +227,6 @@ data_skip(unsigned char *dp, int type) while ((*dp & 0x80) != 0) dp++; return dp + 1; - case REPOKEY_TYPE_U32: - return dp + 4; case REPOKEY_TYPE_MD5: return dp + SIZEOF_MD5; case REPOKEY_TYPE_SHA1: @@ -290,96 +286,4 @@ data_skip(unsigned char *dp, int type) } } -static inline unsigned char * -data_skip_verify(unsigned char *dp, int type, int maxid, int maxdir) -{ - Id id; - int eof; - - switch (type) - { - case REPOKEY_TYPE_VOID: - case REPOKEY_TYPE_CONSTANT: - case REPOKEY_TYPE_CONSTANTID: - case REPOKEY_TYPE_DELETED: - return dp; - case REPOKEY_TYPE_NUM: - while ((*dp & 0x80) != 0) - dp++; - return dp + 1; - case REPOKEY_TYPE_U32: - return dp + 4; - case REPOKEY_TYPE_MD5: - return dp + SIZEOF_MD5; - case REPOKEY_TYPE_SHA1: - return dp + SIZEOF_SHA1; - case REPOKEY_TYPE_SHA224: - return dp + SIZEOF_SHA224; - case REPOKEY_TYPE_SHA256: - return dp + SIZEOF_SHA256; - case REPOKEY_TYPE_SHA384: - return dp + SIZEOF_SHA384; - case REPOKEY_TYPE_SHA512: - return dp + SIZEOF_SHA512; - case REPOKEY_TYPE_ID: - dp = data_read_id(dp, &id); - if (id >= maxid) - return 0; - return dp; - case REPOKEY_TYPE_DIR: - dp = data_read_id(dp, &id); - if (id >= maxdir) - return 0; - return dp; - case REPOKEY_TYPE_IDARRAY: - for (;;) - { - dp = data_read_ideof(dp, &id, &eof); - if (id >= maxid) - return 0; - if (eof) - return dp; - } - case REPOKEY_TYPE_STR: - while ((*dp) != 0) - dp++; - return dp + 1; - case REPOKEY_TYPE_BINARY: - { - unsigned int len; - dp = data_read_id(dp, (Id *)&len); - return dp + len; - } - case REPOKEY_TYPE_DIRSTRARRAY: - for (;;) - { - dp = data_read_ideof(dp, &id, &eof); - if (id >= maxdir) - return 0; - while ((*dp) != 0) - dp++; - dp++; - if (eof) - return dp; - } - case REPOKEY_TYPE_DIRNUMNUMARRAY: - for (;;) - { - dp = data_read_id(dp, &id); - if (id >= maxdir) - return 0; - while ((*dp & 0x80) != 0) - dp++; - dp++; - while ((*dp & 0x80) != 0) - dp++; - if (!(*dp & 0x40)) - return dp + 1; - dp++; - } - default: - return 0; - } -} - #endif /* LIBSOLV_REPOPACK */ diff --git a/libsolv-0.6.15/src/repopage.c b/libsolv-0.7.2/src/repopage.c similarity index 100% rename from libsolv-0.6.15/src/repopage.c rename to libsolv-0.7.2/src/repopage.c diff --git a/libsolv-0.6.15/src/repopage.h b/libsolv-0.7.2/src/repopage.h similarity index 96% rename from libsolv-0.6.15/src/repopage.h rename to libsolv-0.7.2/src/repopage.h index 739345e..b5f2eee 100644 --- a/libsolv-0.6.15/src/repopage.h +++ b/libsolv-0.7.2/src/repopage.h @@ -11,7 +11,7 @@ #define REPOPAGE_BLOBBITS 15 #define REPOPAGE_BLOBSIZE (1 << REPOPAGE_BLOBBITS) -typedef struct _Attrblobpage +typedef struct s_Attrblobpage { /* page_size == 0 means the page is not backed by some file storage. Otherwise it is L*2+(compressed ? 1 : 0), with L being the data @@ -20,7 +20,7 @@ typedef struct _Attrblobpage unsigned int page_size; } Attrblobpage; -typedef struct _Repopagestore { +typedef struct s_Repopagestore { int pagefd; /* file descriptor we're paging from */ long file_offset; /* pages in file start here */ diff --git a/libsolv-0.6.15/src/rules.c b/libsolv-0.7.2/src/rules.c similarity index 68% rename from libsolv-0.6.15/src/rules.c rename to libsolv-0.7.2/src/rules.c index 248b1cd..df32341 100644 --- a/libsolv-0.6.15/src/rules.c +++ b/libsolv-0.7.2/src/rules.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009, Novell Inc. + * Copyright (c) 2007-2017, SUSE Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -32,51 +32,6 @@ #define RULES_BLOCK 63 static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep); -static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded); - -/*------------------------------------------------------------------- - * Check if dependency is possible - * - * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap. - * used in solver_addpkgrulesforweak and solver_createcleandepsmap. - */ - -static inline int -dep_possible(Solver *solv, Id dep, Map *m) -{ - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags >= 8) - { - if (rd->flags == REL_COND) - return 1; - if (rd->flags == REL_AND) - { - if (!dep_possible(solv, rd->name, m)) - return 0; - return dep_possible(solv, rd->evr, m); - } - if (rd->flags == REL_OR) - { - if (dep_possible(solv, rd->name, m)) - return 1; - return dep_possible(solv, rd->evr, m); - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return solver_splitprovides(solv, rd->evr, m); - } - } - FOR_PROVIDES(p, pp, dep) - { - if (MAPTST(m, p)) - return 1; - } - return 0; -} static inline int is_otherproviders_dep(Pool *pool, Id dep) @@ -114,24 +69,27 @@ unifyrules_sortcmp(const void *ap, const void *bp, void *dp) x = a->p - b->p; if (x) - return x; /* p differs */ + return x; /* p differs */ /* identical p */ - if (a->d == 0 && b->d == 0) - return a->w2 - b->w2; /* assertion: return w2 diff */ + if (a->d == 0 && b->d == 0) /* both assertions or binary */ + return a->w2 - b->w2; - if (a->d == 0) /* a is assertion, b not */ + if (a->d == 0) /* a is assertion or binary, b not */ { x = a->w2 - pool->whatprovidesdata[b->d]; return x ? x : -1; } - if (b->d == 0) /* b is assertion, a not */ + if (b->d == 0) /* b is assertion or binary, a not */ { x = pool->whatprovidesdata[a->d] - b->w2; return x ? x : 1; } + if (a->d == b->d) + return 0; + /* compare whatprovidesdata */ ad = pool->whatprovidesdata + a->d; bd = pool->whatprovidesdata + b->d; @@ -161,22 +119,31 @@ solver_unifyrules(Solver *solv) int i, j; Rule *ir, *jr; - if (solv->nrules <= 2) /* nothing to unify */ + if (solv->nrules <= 2) /* nothing to unify */ return; + if (solv->recommendsruleq) + { + /* mis-use n2 as recommends rule marker */ + for (i = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++) + ir->n2 = 0; + for (i = 0; i < solv->recommendsruleq->count; i++) + solv->rules[solv->recommendsruleq->elements[i]].n2 = 1; + } + /* sort rules first */ solv_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool); - /* prune rules - * i = unpruned - * j = pruned - */ + /* prune rules */ jr = 0; for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++) { if (jr && !unifyrules_sortcmp(ir, jr, pool)) - continue; /* prune! */ - jr = solv->rules + j++; /* keep! */ + { + jr->n2 &= ir->n2; /* bitwise-and recommends marker */ + continue; /* prune! */ + } + jr = solv->rules + j++; /* keep! */ if (ir != jr) *jr = *ir; } @@ -185,8 +152,19 @@ solver_unifyrules(Solver *solv) POOL_DEBUG(SOLV_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j); /* adapt rule buffer */ - solv->nrules = j; - solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK); + solver_shrinkrules(solv, j); + + if (solv->recommendsruleq) + { + /* rebuild recommendsruleq */ + queue_empty(solv->recommendsruleq); + for (i = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++) + if (ir->n2) + { + ir->n2 = 0; + queue_push(solv->recommendsruleq, i); + } + } /* * debug: log rule statistics @@ -300,7 +278,7 @@ solver_addrule(Solver *solv, Id p, Id p2, Id d) * the work for unifyrules a bit easier */ if (!solv->pkgrules_end) /* we add pkg rules */ { - r = solv->rules + solv->nrules - 1; + r = solv->rules + solv->lastpkgrule; if (d) { Id *dp; @@ -335,6 +313,7 @@ solver_addrule(Solver *solv, Id p, Id p2, Id d) if (p == -p2) return 0; /* rule is self-fulfilling */ } + solv->lastpkgrule = solv->nrules; } solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK); @@ -359,6 +338,7 @@ solver_shrinkrules(Solver *solv, int nrules) { solv->nrules = nrules; solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK); + solv->lastpkgrule = 0; } /****************************************************************************** @@ -417,6 +397,19 @@ addpkgrule(Solver *solv, Id p, Id p2, Id d, int type, Id dep) #ifdef ENABLE_LINKED_PKGS +static int +addlinks_cmp(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + Id a = *(Id *)ap; + Id b = *(Id *)bp; + Solvable *sa = pool->solvables + a; + Solvable *sb = pool->solvables + b; + if (sa->name != sb->name) + return sa->name - sb->name; + return sa - sb; +} + static void addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m, Queue *workq) { @@ -424,6 +417,8 @@ addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m int i; if (!qr->count) return; + if (qp->count > 1) + solv_sort(qp->elements, qp->count, sizeof(Id), addlinks_cmp, pool); #if 0 printf("ADDLINKS %s\n -> %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req)); for (i = 0; i < qr->count; i++) @@ -439,9 +434,17 @@ addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m addpkgrule(solv, -(s - pool->solvables), 0, pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req); if (qp->count > 1) { - Id d = pool_queuetowhatprovides(pool, qp); - for (i = 0; i < qr->count; i++) - addpkgrule(solv, -qr->elements[i], 0, d, SOLVER_RULE_PKG_REQUIRES, prv); + int j; + for (i = j = 0; i < qp->count; i = j) + { + Id d = pool->solvables[qp->elements[i]].name; + for (j = i + 1; j < qp->count; j++) + if (d != pool->solvables[qp->elements[j]].name) + break; + d = pool_ids2whatprovides(pool, qp->elements + i, j - i); + for (i = 0; i < qr->count; i++) + addpkgrule(solv, -qr->elements[i], 0, d, SOLVER_RULE_PKG_REQUIRES, prv); + } } else if (qp->count) { @@ -549,13 +552,15 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w if (!dp[j]) continue; } + if (type == SOLVER_RULE_PKG_RECOMMENDS && !*dp) + continue; /* check if the rule contains both p and -p */ for (j = 0; dp[j] != 0; j++) if (dp[j] == p) break; if (dp[j]) continue; - addpkgrule(solv, -p, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep); + addpkgrule(solv, -p, 0, dp - pool->whatprovidesdata, type, dep); /* push all non-visited providers on the work queue */ if (m) for (; *dp; dp++) @@ -648,7 +653,7 @@ add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *w /*------------------------------------------------------------------- * - * add (install) rules for solvable + * add dependency rules for solvable * * s: Solvable for which to add rules * m: m[s] = 1 for solvables which have rules, prevent rule duplication @@ -674,6 +679,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) Queue workq; /* list of solvables we still have to work on */ Id workqbuf[64]; + Queue prereqq; /* list of pre-req ids to ignore */ + Id prereqbuf[16]; int i; int dontfix; /* ignore dependency errors for installed solvables */ @@ -689,6 +696,8 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf)); queue_push(&workq, s - pool->solvables); /* push solvable Id to work queue */ + queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf)); + /* loop until there's no more work left */ while (workq.count) { @@ -739,11 +748,33 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (s->requires) { + int filterpre = 0; reqp = s->repo->idarraydata + s->requires; while ((req = *reqp++) != 0) /* go through all requires */ { if (req == SOLVABLE_PREREQMARKER) /* skip the marker */ - continue; + { + if (installed && s->repo == installed) + { + if (prereqq.count) + queue_empty(&prereqq); + solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq); + filterpre = prereqq.count; + } + continue; + } + if (filterpre) + { + /* check if this id is filtered. assumes that prereqq.count is small */ + for (i = 0; i < prereqq.count; i++) + if (req == prereqq.elements[i]) + break; + if (i < prereqq.count) + { + POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req)); + continue; + } + } #ifdef ENABLE_COMPLEX_DEPS if (pool_is_complex_dep(pool, req)) @@ -809,6 +840,48 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } + if (s->recommends && solv->strongrecommends) + { + int start = solv->nrules; + solv->lastpkgrule = 0; + reqp = s->repo->idarraydata + s->recommends; + while ((req = *reqp++) != 0) /* go through all recommends */ + { +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, req)) + { + /* we have AND/COND deps, normalize */ + add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_RECOMMENDS, dontfix, &workq, m); + continue; + } +#endif + dp = pool_whatprovides_ptr(pool, req); + if (*dp == SYSTEMSOLVABLE || !*dp) /* always installed or not installable */ + continue; + for (i = 0; dp[i] != 0; i++) + if (n == dp[i]) + break; + if (dp[i]) + continue; /* provided by itself, no need to add rule */ + addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_RECOMMENDS, req); + if (m) + for (; *dp; dp++) + if (!MAPTST(m, *dp)) + queue_push(&workq, *dp); + } + if (!solv->ruleinfoq && start < solv->nrules) + { + if (!solv->recommendsruleq) + { + solv->recommendsruleq = solv_calloc(1, sizeof(Queue)); + queue_init(solv->recommendsruleq); + } + for (i = start; i < solv->nrules; i++) + queue_push(solv->recommendsruleq, i); + solv->lastpkgrule = 0; + } + } + /* that's all we check for src packages */ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) continue; @@ -958,16 +1031,17 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } - if (m && pool->implicitobsoleteusescolors && (s->arch > pool->lastarch || pool->id2arch[s->arch] != 1)) + if (m && pool->implicitobsoleteusescolors && pool_arch2score(pool, s->arch) > 1) { - int a = pool->id2arch[s->arch]; + unsigned int pa, a = pool_arch2score(pool, s->arch); /* check lock-step candidates */ FOR_PROVIDES(p, pp, s->name) { Solvable *ps = pool->solvables + p; if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p)) continue; - if (ps->arch > pool->lastarch || pool->id2arch[ps->arch] == 1 || pool->id2arch[ps->arch] >= a) + pa = pool_arch2score(pool, ps->arch); + if (!pa || pa == 1 || pa >= a) continue; queue_push(&workq, p); } @@ -985,7 +1059,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (pool_is_complex_dep(pool, rec)) { pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0); - continue; + continue; } #endif FOR_PROVIDES(p, pp, rec) @@ -1002,7 +1076,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) if (pool_is_complex_dep(pool, sug)) { pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0); - continue; + continue; } #endif FOR_PROVIDES(p, pp, sug) @@ -1011,6 +1085,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m) } } } + queue_free(&prereqq); queue_free(&workq); } @@ -1086,7 +1161,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m) /* find possible supplements */ supp = s->repo->idarraydata + s->supplements; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, m)) + if (solver_dep_possible(solv, sup, m)) break; } @@ -1095,7 +1170,7 @@ solver_addpkgrulesforweak(Solver *solv, Map *m) { supp = s->repo->idarraydata + s->enhances; while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, m)) + if (solver_dep_possible(solv, sup, m)) break; } /* if nothing found, goto next solvables */ @@ -1147,64 +1222,111 @@ solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all) *** ***/ -static Id -finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all) +static int +dup_maykeepinstalled(Solver *solv, Solvable *s) { Pool *pool = solv->pool; - int i; + Id ip, pp; - policy_findupdatepackages(solv, s, qs, allow_all ? allow_all : 2); - if (!qs->count) + if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) + return 1; + /* is installed identical to a good one? */ + FOR_PROVIDES(ip, pp, s->name) { - if (allow_all) - return 0; /* orphaned, don't create feature rule */ - /* check if this is an orphaned package */ - policy_findupdatepackages(solv, s, qs, 1); - if (!qs->count) - return 0; /* orphaned, don't create update rule */ - qs->count = 0; - return -SYSTEMSOLVABLE; /* supported but not installable */ + Solvable *is = pool->solvables + ip; + if (is->evr != s->evr) + continue; + if (solv->dupmap.size) + { + if (!MAPTST(&solv->dupmap, ip)) + continue; + } + else if (is->repo == pool->installed) + continue; + if (solvable_identical(s, is)) + return 1; } - if (allow_all) - return s - pool->solvables; - /* check if it is ok to keep the installed package */ - if (solv->dupmap.size && MAPTST(&solv->dupmap, s - pool->solvables)) - return s - pool->solvables; - for (i = 0; i < qs->count; i++) + return 0; +} + + +/* stash away the original updaters for multiversion packages. We do this so that + * we can update the package later */ +static inline void +set_specialupdaters(Solver *solv, Solvable *s, Id d) +{ + Repo *installed = solv->installed; + if (!solv->specialupdaters) + solv->specialupdaters = solv_calloc(installed->end - installed->start, sizeof(Id)); + solv->specialupdaters[s - solv->pool->solvables - installed->start] = d; +} + +#ifdef ENABLE_LINKED_PKGS +/* Check if this is a linked pseudo package. As it is linked, we do not need an update/feature rule */ +static inline int +is_linked_pseudo_package(Solver *solv, Solvable *s) +{ + Pool *pool = solv->pool; + if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) { - Solvable *ns = pool->solvables + qs->elements[i]; - if (s->evr == ns->evr && solvable_identical(s, ns)) - return s - pool->solvables; + const char *name = pool_id2str(pool, s->name); + if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) + return 1; } - /* nope, it must be some other package */ - return -SYSTEMSOLVABLE; + return 0; } +#endif -#if 0 -/* add packages from the dup repositories to the update candidates - * this isn't needed for the global dup mode as all packages are - * from dup repos in that case */ -static void -addduppackages(Solver *solv, Solvable *s, Queue *qs) +void +solver_addfeaturerule(Solver *solv, Solvable *s) { - Queue dupqs; - Id p, dupqsbuf[64]; + Pool *pool = solv->pool; int i; - int oldnoupdateprovide = solv->noupdateprovide; + Id p; + Queue qs; + Id qsbuf[64]; - queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf)); - solv->noupdateprovide = 1; - policy_findupdatepackages(solv, s, &dupqs, 2); - solv->noupdateprovide = oldnoupdateprovide; - for (i = 0; i < dupqs.count; i++) +#ifdef ENABLE_LINKED_PKGS + if (is_linked_pseudo_package(solv, s)) { - p = dupqs.elements[i]; - if (MAPTST(&solv->dupmap, p)) - queue_pushunique(qs, p); + solver_addrule(solv, 0, 0, 0); /* no feature rules for those */ + return; } - queue_free(&dupqs); -} #endif + queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + p = s - pool->solvables; + policy_findupdatepackages(solv, s, &qs, 1); + if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) + { + if (!dup_maykeepinstalled(solv, s)) + { + for (i = 0; i < qs.count; i++) + { + Solvable *ns = pool->solvables + qs.elements[i]; + if (ns->repo != pool->installed || dup_maykeepinstalled(solv, ns)) + break; + } + if (i == qs.count) + { + solver_addrule(solv, 0, 0, 0); /* this is an orphan */ + queue_free(&qs); + return; + } + } + } + if (qs.count > 1) + { + Id d = pool_queuetowhatprovides(pool, &qs); + queue_free(&qs); + solver_addrule(solv, p, 0, d); /* allow update of s */ + } + else + { + Id d = qs.count ? qs.elements[0] : 0; + queue_free(&qs); + solver_addrule(solv, p, d, 0); /* allow update of s */ + } +} /*------------------------------------------------------------------- * @@ -1215,57 +1337,43 @@ addduppackages(Solver *solv, Solvable *s, Queue *qs) */ void -solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) +solver_addupdaterule(Solver *solv, Solvable *s) { /* installed packages get a special upgrade allowed rule */ Pool *pool = solv->pool; Id p, d; Queue qs; Id qsbuf[64]; - int isorphaned = 0; + Rule *r; + int dupinvolved = 0; - queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); p = s - pool->solvables; - /* find update candidates for 's' */ - if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) - p = finddistupgradepackages(solv, s, &qs, allow_all); - else - policy_findupdatepackages(solv, s, &qs, allow_all); - -#ifdef ENABLE_LINKED_PKGS - if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start]) + /* Orphan detection. We cheat by looking at the feature rule, which + * we already calculated */ + r = solv->rules + solv->featurerules + (p - solv->installed->start); + if (!r->p) { - const char *name = pool_id2str(pool, s->name); - if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0) +#ifdef ENABLE_LINKED_PKGS + if (is_linked_pseudo_package(solv, s)) { - /* a linked pseudo package. As it is linked, we do not need an update/feature rule */ - /* nevertheless we set specialupdaters so we can update */ solver_addrule(solv, 0, 0, 0); - if (!allow_all && qs.count) - { - if (p != -SYSTEMSOLVABLE) - queue_unshift(&qs, p); - if (!solv->specialupdaters) - solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id)); - solv->specialupdaters[s - pool->solvables - solv->installed->start] = pool_queuetowhatprovides(pool, &qs); - } - queue_free(&qs); return; } - } #endif - - if (!allow_all && !p) /* !p implies qs.count == 0 */ - { + p = 0; queue_push(&solv->orphaned, s - pool->solvables); /* an orphaned package */ if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start)))) p = s - pool->solvables; /* keep this orphaned package installed */ - queue_free(&qs); solver_addrule(solv, p, 0, 0); return; } - if (!allow_all && qs.count && solv->multiversion.size) + /* find update candidates for 's' */ + queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf)); + dupinvolved = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)); + policy_findupdatepackages(solv, s, &qs, dupinvolved ? 2 : 0); + + if (qs.count && solv->multiversion.size) { int i, j; @@ -1294,41 +1402,41 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all) } qs.elements[j++] = qs.elements[i]; } + + if (j == 0 && dupinvolved && !dup_maykeepinstalled(solv, s)) + { + /* this is a multiversion orphan */ + queue_push(&solv->orphaned, p); + set_specialupdaters(solv, s, d); + if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) + { + /* we need to keep the orphan */ + queue_free(&qs); + solver_addrule(solv, p, 0, 0); + return; + } + /* we can drop it as long as we update */ + j = qs.count; + } + if (j < qs.count) /* filtered at least one package? */ { - if (j == 0 && p == -SYSTEMSOLVABLE) + if (d && (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start)))) { - /* this is a multiversion orphan */ - queue_push(&solv->orphaned, s - pool->solvables); - if (!solv->specialupdaters) - solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id)); - solv->specialupdaters[s - pool->solvables - solv->installed->start] = d; - if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start)))) - { - /* we need to keep the orphan */ - queue_free(&qs); - solver_addrule(solv, s - pool->solvables, 0, 0); - return; - } - /* we can drop it as long as we update */ - isorphaned = 1; - j = qs.count; /* force the update */ + /* non-orphan multiversion package, set special updaters if we want an update */ + set_specialupdaters(solv, s, d); } qs.count = j; } - else if (p != -SYSTEMSOLVABLE) + else { /* could fallthrough, but then we would do pool_queuetowhatprovides twice */ queue_free(&qs); - solver_addrule(solv, s - pool->solvables, 0, d); /* allow update of s */ + solver_addrule(solv, p, 0, d); /* allow update of s */ return; } } } - if (!isorphaned && p == -SYSTEMSOLVABLE && solv->dupmap.size) - p = s - pool->solvables; /* let the dup rules sort it out */ - if (qs.count && p == -SYSTEMSOLVABLE) - p = queue_shift(&qs); if (qs.count > 1) { d = pool_queuetowhatprovides(pool, &qs); @@ -1359,7 +1467,7 @@ disableupdaterule(Solver *solv, Id p) { int i, ni; ni = solv->bestrules_end - solv->bestrules; - for (i = 0; i < ni; i++) + for (i = solv->bestrules_up - solv->bestrules; i < ni; i++) if (solv->bestrules_pkg[i] == p) solver_disablerule(solv, solv->rules + solv->bestrules + i); } @@ -1402,7 +1510,7 @@ reenableupdaterule(Solver *solv, Id p) { int i, ni; ni = solv->bestrules_end - solv->bestrules; - for (i = 0; i < ni; i++) + for (i = solv->bestrules_up - solv->bestrules; i < ni; i++) if (solv->bestrules_pkg[i] == p) solver_enablerule(solv, solv->rules + solv->bestrules + i); } @@ -1424,7 +1532,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) Pool *pool = solv->pool; Repo *installed = pool->installed; int first, i, j; - Id p, pp, a, aa, bestarch; + Id p, pp, aa; + unsigned int a, bestscore; Solvable *s, *ps, *bests; Queue badq, allowedarchs; Queue lsq; @@ -1439,7 +1548,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) continue; s = pool->solvables + i; first = i; - bestarch = 0; + bestscore = 0; bests = 0; queue_empty(&allowedarchs); FOR_PROVIDES(p, pp, s->name) @@ -1451,17 +1560,17 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) first = 0; if (first) break; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + a = pool_arch2score(pool, ps->arch); if (a != 1 && installed && ps->repo == installed) { - if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) - queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */ - continue; /* ignore installed solvables when calculating the best arch */ + if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) + continue; + queue_pushunique(&allowedarchs, ps->arch); /* also ok to keep this architecture */ + continue; /* but ignore installed solvables when calculating the best arch */ } - if (a && a != 1 && (!bestarch || a < bestarch)) + if (a && a != 1 && (!bestscore || a < bestscore)) { - bestarch = a; + bestscore = a; bests = ps; } } @@ -1472,7 +1581,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch) allowedarchs.count--; /* installed arch is best */ - if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestarch) + if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore) { /* need an extra pass for lockstep checking: we only allow to keep an inferior arch * if the corresponding installed package is not lock-stepped */ @@ -1483,27 +1592,25 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) ps = pool->solvables + p; if (ps->name != s->name || ps->repo != installed || !MAPTST(addedmap, p)) continue; - if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) + if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))) continue; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; + a = pool_arch2score(pool, ps->arch); if (!a) { queue_pushunique(&allowedarchs, ps->arch); /* strange arch, allow */ continue; } - if (a == 1 || ((a ^ bestarch) & 0xffff0000) == 0) + if (a == 1 || ((a ^ bestscore) & 0xffff0000) == 0) continue; /* have installed package with inferior arch, check if lock-stepped */ FOR_PROVIDES(p2, pp2, s->name) { Solvable *s2 = pool->solvables + p2; - Id a2; + unsigned int a2; if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch) continue; - a2 = s2->arch; - a2 = (a2 <= pool->lastarch) ? pool->id2arch[a2] : 0; - if (a2 && (a2 == 1 || ((a2 ^ bestarch) & 0xffff0000) == 0)) + a2 = pool_arch2score(pool, s2->arch); + if (a2 && (a2 == 1 || ((a2 ^ bestscore) & 0xffff0000) == 0)) break; } if (!p2) @@ -1518,9 +1625,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) ps = pool->solvables + p; if (ps->name != s->name || !MAPTST(addedmap, p)) continue; - a = ps->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; - if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0) + a = pool_arch2score(pool, ps->arch); + if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0) { if (installed && ps->repo == installed) { @@ -1530,11 +1636,12 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) } for (j = 0; j < allowedarchs.count; j++) { + unsigned int aas; aa = allowedarchs.elements[j]; if (ps->arch == aa) break; - aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0; - if (aa && ((a ^ aa) & 0xffff0000) == 0) + aas = pool_arch2score(pool, aa); + if (aas && ((a ^ aas) & 0xffff0000) == 0) break; /* compatible */ } if (j == allowedarchs.count) @@ -1546,7 +1653,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) for (j = 0; j < badq.count; j++) { p = badq.elements[j]; - /* lock-step */ + /* special lock-step handling */ if (pool->implicitobsoleteusescolors) { Id p2; @@ -1557,9 +1664,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap) Solvable *s2 = pool->solvables + p2; if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch) continue; - a = s2->arch; - a = (a <= pool->lastarch) ? pool->id2arch[a] : 0; - if (a && (a == 1 || ((a ^ bestarch) & 0xffff000) == 0)) + a = pool_arch2score(pool, s2->arch); + if (a && (a == 1 || ((a ^ bestscore) & 0xffff000) == 0)) { queue_push(&lsq, p2); if (installed && s2->repo == installed) @@ -1625,7 +1731,7 @@ reenableinfarchrule(Solver *solv, Id name) ***/ static inline void -add_cleandeps_package(Solver *solv, Id p) +add_cleandeps_updatepkg(Solver *solv, Id p) { if (!solv->cleandeps_updatepkgs) { @@ -1643,6 +1749,9 @@ solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted) Repo *installed = solv->installed; Id pi, pip, obs, *obsp; + if (!solv->dupinvolvedmap.size) + map_grow(&solv->dupinvolvedmap, pool->nsolvables); + MAPSET(&solv->dupinvolvedmap, p); if (targeted) MAPSET(&solv->dupmap, p); @@ -1659,14 +1768,14 @@ solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted) if (pool->solvables[pi2].repo != installed) MAPSET(&solv->dupinvolvedmap, pi2); } - if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0) + if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all) { if (!solv->bestupdatemap.size) map_grow(&solv->bestupdatemap, installed->end - installed->start); MAPSET(&solv->bestupdatemap, pi - installed->start); } if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0) - add_cleandeps_package(solv, pi); + add_cleandeps_updatepkg(solv, pi); if (!targeted && ps->repo != installed) MAPSET(&solv->dupmap, pi); } @@ -1704,19 +1813,23 @@ solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted) if (pool->solvables[pi2].repo != installed) MAPSET(&solv->dupinvolvedmap, pi2); } - if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0) + if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all) { if (!solv->bestupdatemap.size) map_grow(&solv->bestupdatemap, installed->end - installed->start); MAPSET(&solv->bestupdatemap, pi - installed->start); } if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0) - add_cleandeps_package(solv, pi); + add_cleandeps_updatepkg(solv, pi); } } } } +/* create the two dupmaps: + * - dupmap: packages in that map are good to install/keep + * - dupinvolvedmap: packages are subject to dup mode + */ void solver_createdupmaps(Solver *solv) { @@ -1728,7 +1841,8 @@ solver_createdupmaps(Solver *solv) int i, targeted; map_init(&solv->dupmap, pool->nsolvables); - map_init(&solv->dupinvolvedmap, pool->nsolvables); + solv->dupinvolvedmap_all = 0; + map_init(&solv->dupinvolvedmap, 0); for (i = 0; i < job->count; i += 2) { how = job->elements[i]; @@ -1757,11 +1871,22 @@ solver_createdupmaps(Solver *solv) } else if (select == SOLVER_SOLVABLE_ALL) { + solv->dupinvolvedmap_all = 1; FOR_POOL_SOLVABLES(p) { - MAPSET(&solv->dupinvolvedmap, p); - if (installed && pool->solvables[p].repo != installed) - MAPSET(&solv->dupmap, p); + Solvable *s = pool->solvables + p; + if (!s->repo || s->repo == installed) + continue; + if (!pool_installable(pool, s)) + continue; + MAPSET(&solv->dupmap, p); + } + if ((how & SOLVER_FORCEBEST) != 0) + solv->bestupdatemap_all = 1; + if ((how & SOLVER_CLEANDEPS) != 0 && installed) + { + FOR_REPO_SOLVABLES(installed, p, s) + add_cleandeps_updatepkg(solv, p); } } else @@ -1793,7 +1918,23 @@ solver_createdupmaps(Solver *solv) break; } } - MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE); + if (solv->dupinvolvedmap.size) + MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE); + /* set update for all involved installed packages. We need to do + * this before creating the update rules */ + if (solv->dupinvolvedmap_all) + solv->updatemap_all = 1; + else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size) + { + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!MAPTST(&solv->dupinvolvedmap, p)) + continue; + if (!solv->updatemap.size) + map_grow(&solv->updatemap, installed->end - installed->start); + MAPSET(&solv->updatemap, p - installed->start); + } + } } void @@ -1830,13 +1971,10 @@ solver_addduprules(Solver *solv, Map *addedmap) first = 0; if (first) break; - if (!MAPTST(&solv->dupinvolvedmap, p)) + if (!solv->dupinvolvedmap_all && !MAPTST(&solv->dupinvolvedmap, p)) continue; if (installed && ps->repo == installed) { - if (!solv->updatemap.size) - map_grow(&solv->updatemap, installed->end - installed->start); - MAPSET(&solv->updatemap, p - installed->start); if (!MAPTST(&solv->dupmap, p)) { Id ip, ipp; @@ -1851,19 +1989,36 @@ solver_addduprules(Solver *solv, Map *addedmap) } if (ip) { - /* ok, found a good one. we may keep this package. */ + /* ok, identical to a good one. we may keep this package. */ MAPSET(&solv->dupmap, p); /* for best rules processing */ continue; } + /* check if it's orphaned. If yes, we may keep it */ r = solv->rules + solv->updaterules + (p - installed->start); if (!r->p) - r = solv->rules + solv->featurerules + (p - installed->start); - if (r->p && solv->specialupdaters && solv->specialupdaters[p - installed->start]) + r = solv->rules + solv->featurerules + (p - installed->start); + if (!r->p) + { + /* no update/feature rule, this is an orphan */ + MAPSET(&solv->dupmap, p); /* for best rules processing */ + continue; + } + if (solv->specialupdaters && solv->specialupdaters[p - installed->start]) { /* this is a multiversion orphan, we're good if an update is installed */ solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]); continue; } + if (r->p == p && !r->d && !r->w2) + { + r = solv->rules + solv->featurerules + (p - installed->start); + if (!r->p || (!r->d && !r->w2)) + { + /* this is an orphan */ + MAPSET(&solv->dupmap, p); /* for best rules processing */ + continue; + } + } solver_addrule(solv, -p, 0, 0); /* no match, sorry */ } } @@ -1922,137 +2077,23 @@ reenableduprule(Solver *solv, Id name) #define DISABLE_INFARCH 2 #define DISABLE_DUP 3 -/* - * add all installed packages that package p obsoletes to Queue q. - * Package p is not installed. Also, we know that if - * solv->keepexplicitobsoletes is not set, p is not in the multiversion map. - * Entries may get added multiple times. - */ static void -add_obsoletes(Solver *solv, Id p, Queue *q) +jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) { Pool *pool = solv->pool; - Repo *installed = solv->installed; - Id p2, pp2; - Solvable *s = pool->solvables + p; - Id obs, *obsp; - Id lastp2 = 0; + Id select, p, pp; + Repo *installed; + Solvable *s; + int i, j, set, qstart; + Map omap; - if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p))) + installed = solv->installed; + select = how & SOLVER_SELECTMASK; + switch (how & SOLVER_JOBMASK) { - FOR_PROVIDES(p2, pp2, s->name) - { - Solvable *ps = pool->solvables + p2; - if (ps->repo != installed) - continue; - if (!pool->implicitobsoleteusesprovides && ps->name != s->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p2); - lastp2 = p2; - } - } - if (!s->obsoletes) - return; - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - FOR_PROVIDES(p2, pp2, obs) - { - Solvable *ps = pool->solvables + p2; - if (ps->repo != installed) - continue; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - if (p2 == lastp2) - continue; - queue_push(q, p2); - lastp2 = p2; - } -} - -/* - * Call add_obsoletes and intersect the result with the - * elements in Queue q starting at qstart. - * Assumes that it's the first call if qstart == q->count. - * May use auxillary map m for the intersection process, all - * elements of q starting at qstart must have their bit cleared. - * (This is also true after the function returns.) - */ -static void -intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m) -{ - int i, j; - int qcount = q->count; - - add_obsoletes(solv, p, q); - if (qcount == qstart) - return; /* first call */ - if (qcount == q->count) - j = qstart; - else if (qcount == qstart + 1) - { - /* easy if there's just one element */ - j = qstart; - for (i = qcount; i < q->count; i++) - if (q->elements[i] == q->elements[qstart]) - { - j++; /* keep the element */ - break; - } - } - else if (!m->size && q->count - qstart <= 8) - { - /* faster than a map most of the time */ - int k; - for (i = j = qstart; i < qcount; i++) - { - Id ip = q->elements[i]; - for (k = qcount; k < q->count; k++) - if (q->elements[k] == ip) - { - q->elements[j++] = ip; - break; - } - } - } - else - { - /* for the really pathologic cases we use the map */ - Repo *installed = solv->installed; - if (!m->size) - map_init(m, installed->end - installed->start); - for (i = qcount; i < q->count; i++) - MAPSET(m, q->elements[i] - installed->start); - for (i = j = qstart; i < qcount; i++) - if (MAPTST(m, q->elements[i] - installed->start)) - { - MAPCLR(m, q->elements[i] - installed->start); - q->elements[j++] = q->elements[i]; - } - } - queue_truncate(q, j); -} - -static void -jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) -{ - Pool *pool = solv->pool; - Id select, p, pp; - Repo *installed; - Solvable *s; - int i, j, set, qstart; - Map omap; - - installed = solv->installed; - select = how & SOLVER_SELECTMASK; - switch (how & SOLVER_JOBMASK) - { - case SOLVER_INSTALL: - set = how & SOLVER_SETMASK; - if (!(set & SOLVER_NOAUTOSET)) + case SOLVER_INSTALL: + set = how & SOLVER_SETMASK; + if (!(set & SOLVER_NOAUTOSET)) { /* automatically add set bits by analysing the job */ if (select == SOLVER_SOLVABLE_NAME) @@ -2128,30 +2169,19 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) return; /* now the hard part: disable some update rules */ - /* first check if we have multiversion or installed packages in the job */ - i = j = 0; + /* first check if we have installed or multiversion packages in the job */ FOR_JOB_SELECT(p, pp, select, what) { if (pool->solvables[p].repo == installed) - j = p; - else if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes) return; - i++; - } - if (j) /* have installed packages */ - { - /* this is for dupmap_all jobs, it can go away if we create - * duprules for them */ - if (i == 1 && (set & SOLVER_SETREPO) != 0) - queue_push2(q, DISABLE_UPDATE, j); - return; + if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes) + return; } - omap.size = 0; qstart = q->count; FOR_JOB_SELECT(p, pp, select, what) { - intersect_obsoletes(solv, p, q, qstart, &omap); + solver_intersect_obsoleted(solv, p, q, qstart, &omap); if (q->count == qstart) break; } @@ -2215,8 +2245,10 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q) if (!installed) break; if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - queue_push2(q, DISABLE_UPDATE, p); + { + FOR_REPO_SOLVABLES(installed, p, s) + queue_push2(q, DISABLE_UPDATE, p); + } FOR_JOB_SELECT(p, pp, select, what) if (pool->solvables[p].repo == installed) { @@ -3222,11 +3254,6 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) int i, oldcnt; solv->bestrules = solv->nrules; - if (!installed) - { - solv->bestrules_end = solv->nrules; - return; - } queue_init(&q); queue_init(&q2); queue_init(&r2pkg); @@ -3235,39 +3262,56 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) { for (i = 0; i < solv->job.count; i += 2) { - if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST)) + Id how = solv->job.elements[i]; + if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST)) { int j; Id p2, pp2; for (j = 0; j < solv->ruletojob.count; j++) - if (solv->ruletojob.elements[j] == i) - break; - if (j == solv->ruletojob.count) - continue; - r = solv->rules + solv->jobrules + j; - queue_empty(&q); - FOR_RULELITERALS(p2, pp2, r) - if (p2 > 0) - queue_push(&q, p2); - if (!q.count) - continue; /* orphaned */ - /* select best packages, just look at prio and version */ - oldcnt = q.count; - policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND); - if (q.count == oldcnt) - continue; /* nothing filtered */ - p2 = queue_shift(&q); - if (q.count < 2) - solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); - else - solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); - queue_push(&r2pkg, -(solv->jobrules + j)); + { + if (solv->ruletojob.elements[j] != i) + continue; + r = solv->rules + solv->jobrules + j; + queue_empty(&q); + queue_empty(&q2); + FOR_RULELITERALS(p2, pp2, r) + { + if (p2 > 0) + queue_push(&q, p2); + else if (p2 < 0) + queue_push(&q2, p2); + } + if (!q.count) + continue; /* orphaned */ + /* select best packages, just look at prio and version */ + oldcnt = q.count; + policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND); + if (q.count == oldcnt) + continue; /* nothing filtered */ + if (q2.count) + queue_insertn(&q, 0, q2.count, q2.elements); + p2 = queue_shift(&q); + if (q.count < 2) + solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); + else + solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); + if ((how & SOLVER_WEAK) != 0) + queue_push(&solv->weakruleq, solv->nrules - 1); + queue_push(&r2pkg, -(solv->jobrules + j)); + } } } } + solv->bestrules_up = solv->nrules; - if (solv->bestupdatemap_all || solv->bestupdatemap.size) + if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size)) { + Map m; + + if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) + map_init(&m, pool->nsolvables); + else + map_init(&m, 0); FOR_REPO_SOLVABLES(installed, p, s) { Id d, p2, pp2; @@ -3326,6 +3370,29 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) queue_pushunique(&q, q2.elements[j]); } } + if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start))) + { + /* package is flagged both for allowuninstall and best, add negative rules */ + d = q.count == 1 ? q.elements[0] : -pool_queuetowhatprovides(pool, &q); + for (i = 0; i < q.count; i++) + MAPSET(&m, q.elements[i]); + r = solv->rules + solv->featurerules + (p - installed->start); + if (!r->p) /* identical to update rule? */ + r = solv->rules + solv->updaterules + (p - installed->start); + FOR_RULELITERALS(p2, pp2, r) + { + if (MAPTST(&m, p2)) + continue; + if (d >= 0) + solver_addrule(solv, -p2, d, 0); + else + solver_addrule(solv, -p2, 0, -d); + queue_push(&r2pkg, p); + } + for (i = 0; i < q.count; i++) + MAPCLR(&m, q.elements[i]); + continue; + } p2 = queue_shift(&q); if (q.count < 2) solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0); @@ -3333,6 +3400,7 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q)); queue_push(&r2pkg, p); } + map_free(&m); } if (r2pkg.count) solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id)); @@ -3346,6 +3414,8 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs) /* yumobs rule handling */ +/* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors + * like in policy_findupdatepackages */ static void find_obsolete_group(Solver *solv, Id obs, Queue *q) @@ -3370,7 +3440,7 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q) Id obs2, *obsp2; if (!os->obsoletes) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os)) continue; obsp2 = os->repo->idarraydata + os->obsoletes; while ((obs2 = *obsp2++) != 0) @@ -3388,7 +3458,7 @@ find_obsolete_group(Solver *solv, Id obs, Queue *q) continue; if (!os->obsoletes) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os)) continue; obsp2 = os->repo->idarraydata + os->obsoletes; while ((obs2 = *obsp2++) != 0) @@ -3473,7 +3543,6 @@ solver_addyumobsrules(Solver *solv) #if 0 printf("checking yumobs for %s\n", pool_solvable2str(pool, s)); #endif - queue_empty(&qo); for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;) { Solvable *os = pool->solvables + op; @@ -3488,7 +3557,7 @@ printf("checking yumobs for %s\n", pool_solvable2str(pool, s)); continue; if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs)) continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) + if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2)) continue; queue_pushunique(&qo, obs); break; @@ -3564,1088 +3633,6 @@ for (j = 0; j < qq.count; j++) POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now)); } -#undef CLEANDEPSDEBUG - -/* - * This functions collects all packages that are looked at - * when a dependency is checked. We need it to "pin" installed - * packages when removing a supplemented package in createcleandepsmap. - * Here's an not uncommon example: - * A contains "Supplements: packageand(B, C)" - * B contains "Requires: A" - * Now if we remove C, the supplements is no longer true, - * thus we also remove A. Without the dep_pkgcheck function, we - * would now also remove B, but this is wrong, as adding back - * C doesn't make the supplements true again. Thus we "pin" B - * when we remove A. - * There's probably a better way to do this, but I haven't come - * up with it yet ;) - */ -static inline void -dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q) -{ - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags >= 8) - { - if (rd->flags == REL_AND) - { - dep_pkgcheck(solv, rd->name, m, q); - dep_pkgcheck(solv, rd->evr, m, q); - return; - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return; - } - } - FOR_PROVIDES(p, pp, dep) - if (!m || MAPTST(m, p)) - queue_push(q, p); -} - -static int -check_xsupp(Solver *solv, Queue *depq, Id dep) -{ - Pool *pool = solv->pool; - Id p, pp; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags >= 8) - { - if (rd->flags == REL_AND) - { - if (!check_xsupp(solv, depq, rd->name)) - return 0; - return check_xsupp(solv, depq, rd->evr); - } - if (rd->flags == REL_OR) - { - if (check_xsupp(solv, depq, rd->name)) - return 1; - return check_xsupp(solv, depq, rd->evr); - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) -#if 0 - return solver_splitprovides(solv, rd->evr); -#else - return 0; -#endif - } - if (depq && rd->flags == REL_NAMESPACE) - { - int i; - for (i = 0; i < depq->count; i++) - if (depq->elements[i] == dep || depq->elements[i] == rd->name) - return 1; - } - } - FOR_PROVIDES(p, pp, dep) - if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed) - return 1; - return 0; -} - -static inline int -queue_contains(Queue *q, Id id) -{ - int i; - for (i = 0; i < q->count; i++) - if (q->elements[i] == id) - return 1; - return 0; -} - -#ifdef ENABLE_COMPLEX_DEPS -static void -complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq) -{ - int i; - Queue dq; - Id p; - - queue_init(&dq); - i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); - if (i == 0 || i == 1) - { - queue_free(&dq); - return; - } - for (i = 0; i < dq.count; i++) - { - for (; (p = dq.elements[i]) != 0; i++) - { - if (p < 0) - { - if (!MAPTST(installedm, -p)) - break; - continue; - } - if (p != SYSTEMSOLVABLE && MAPTST(im, p)) - { -#ifdef CLEANDEPSDEBUG - printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - queue_push(iq, p); - } - } - while (dq.elements[i]) - i++; - } - queue_free(&dq); -} - -static void -complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled) -{ - int i, blk; - Queue dq; - Id p; - - queue_init(&dq); - i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); - if (i == 0 || i == 1) - { - queue_free(&dq); - return; - } - for (i = 0; i < dq.count; i++) - { - blk = i; - for (; (p = dq.elements[i]) != 0; i++) - { - if (p < 0) - { - if (!MAPTST(installedm, -p)) - break; - continue; - } - if (MAPTST(im, p)) - break; - } - if (!p) - { - for (i = blk; (p = dq.elements[i]) != 0; i++) - { - if (p < 0) - continue; - if (!MAPTST(installedm, p)) - continue; - if (p == ip || MAPTST(userinstalled, p - pool->installed->start)) - continue; -#ifdef CLEANDEPSDEBUG - printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - MAPSET(im, p); - queue_push(iq, p); - } - } - while (dq.elements[i]) - i++; - } - queue_free(&dq); -} - -#endif - -/* - * Find all installed packages that are no longer - * needed regarding the current solver job. - * - * The algorithm is: - * - remove pass: remove all packages that could have - * been dragged in by the obsoleted packages. - * i.e. if package A is obsolete and contains "Requires: B", - * also remove B, as installing A will have pulled in B. - * after this pass, we have a set of still installed packages - * with broken dependencies. - * - add back pass: - * now add back all packages that the still installed packages - * require. - * - * The cleandeps packages are the packages removed in the first - * pass and not added back in the second pass. - * - * If we search for unneeded packages (unneeded is true), we - * simply remove all packages except the userinstalled ones in - * the first pass. - */ -static void -solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded) -{ - Pool *pool = solv->pool; - Repo *installed = solv->installed; - Queue *job = &solv->job; - Map userinstalled; - Map im; - Map installedm; - Rule *r; - Id rid, how, what, select; - Id p, pp, ip, jp; - Id req, *reqp, sup, *supp; - Solvable *s; - Queue iq, iqcopy, xsuppq; - int i; - - map_empty(cleandepsmap); - if (!installed || installed->end == installed->start) - return; - map_init(&userinstalled, installed->end - installed->start); - map_init(&im, pool->nsolvables); - map_init(&installedm, pool->nsolvables); - queue_init(&iq); - queue_init(&xsuppq); - - for (i = 0; i < job->count; i += 2) - { - how = job->elements[i]; - if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) - { - what = job->elements[i + 1]; - select = how & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); - FOR_JOB_SELECT(p, pp, select, what) - if (pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - } - if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES)) - { - what = job->elements[i + 1]; - if (ISRELDEP(what)) - { - Reldep *rd = GETRELDEP(pool, what); - if (rd->flags != REL_NAMESPACE) - continue; - if (rd->evr == 0) - { - queue_pushunique(&iq, rd->name); - continue; - } - FOR_PROVIDES(p, pp, what) - if (p) - break; - if (p) - continue; - queue_pushunique(&iq, what); - } - } - } - - /* have special namespace cleandeps erases */ - if (iq.count) - { - for (ip = installed->start; ip < installed->end; ip++) - { - s = pool->solvables + ip; - if (s->repo != installed) - continue; - if (!s->supplements) - continue; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup)) - { -#ifdef CLEANDEPSDEBUG - printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip)); -#endif - queue_pushunique(&xsuppq, sup); - } - } - queue_empty(&iq); - } - - /* also add visible patterns to userinstalled for openSUSE */ - if (1) - { - Dataiterator di; - dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0); - while (dataiterator_step(&di)) - { - Id *dp; - if (di.solvid <= 0) - continue; - s = pool->solvables + di.solvid; - if (!s->repo || !s->requires) - continue; - if (s->repo != installed && !pool_installable(pool, s)) - continue; - if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0) - continue; - dp = s->repo->idarraydata + s->requires; - for (dp = s->repo->idarraydata + s->requires; *dp; dp++) - FOR_PROVIDES(p, pp, *dp) - if (pool->solvables[p].repo == installed) - { - if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0) - continue; - MAPSET(&userinstalled, p - installed->start); - } - } - dataiterator_free(&di); - } - if (1) - { - /* all products and their buddies are userinstalled */ - for (p = installed->start; p < installed->end; p++) - { - Solvable *s = pool->solvables + p; - if (s->repo != installed) - continue; - if (!strncmp("product:", pool_id2str(pool, s->name), 8)) - { - MAPSET(&userinstalled, p - installed->start); -#ifdef ENABLE_LINKED_PKGS - if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1) - { - Id buddy = solv->instbuddy[p - installed->start]; - if (buddy >= installed->start && buddy < installed->end) - MAPSET(&userinstalled, buddy - installed->start); - } -#endif - } - } - } - - /* add all positive elements (e.g. locks) to "userinstalled" */ - for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) - { - r = solv->rules + rid; - if (r->d < 0) - continue; - i = solv->ruletojob.elements[rid - solv->jobrules]; - if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS) - continue; - FOR_RULELITERALS(p, jp, r) - if (p > 0 && pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - } - - /* add all cleandeps candidates to iq */ - for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) - { - r = solv->rules + rid; - if (r->d < 0) /* disabled? */ - continue; - if (r->d == 0 && r->p < 0 && r->w2 == 0) /* negative assertion (erase job)? */ - { - p = -r->p; - if (pool->solvables[p].repo != installed) - continue; - MAPCLR(&userinstalled, p - installed->start); - if (unneeded) - continue; - i = solv->ruletojob.elements[rid - solv->jobrules]; - how = job->elements[i]; - if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS)) - queue_push(&iq, p); - } - else if (r->p > 0) /* install job */ - { - if (unneeded) - continue; - i = solv->ruletojob.elements[rid - solv->jobrules]; - if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS) - { - /* check if the literals all obsolete some installed package */ - Map om; - int iqstart; - - /* just one installed literal */ - if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed) - continue; - /* multiversion is bad */ - if (solv->multiversion.size && !solv->keepexplicitobsoletes) - { - FOR_RULELITERALS(p, jp, r) - if (MAPTST(&solv->multiversion, p)) - break; - if (p) - continue; - } - - om.size = 0; - iqstart = iq.count; - FOR_RULELITERALS(p, jp, r) - { - if (p < 0) - { - queue_truncate(&iq, iqstart); /* abort */ - break; - } - if (pool->solvables[p].repo == installed) - { - if (iq.count == iqstart) - queue_push(&iq, p); - else - { - for (i = iqstart; i < iq.count; i++) - if (iq.elements[i] == p) - break; - queue_truncate(&iq, iqstart); - if (i < iq.count) - queue_push(&iq, p); - } - } - else - intersect_obsoletes(solv, p, &iq, iqstart, &om); - if (iq.count == iqstart) - break; - } - if (om.size) - map_free(&om); - } - } - } - queue_init_clone(&iqcopy, &iq); - - if (!unneeded) - { - if (solv->cleandeps_updatepkgs) - for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) - queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]); - } - - if (unneeded) - queue_empty(&iq); /* just in case... */ - - /* clear userinstalled bit for the packages we really want to delete/update */ - for (i = 0; i < iq.count; i++) - { - p = iq.elements[i]; - if (pool->solvables[p].repo != installed) - continue; - MAPCLR(&userinstalled, p - installed->start); - } - - for (p = installed->start; p < installed->end; p++) - { - if (pool->solvables[p].repo != installed) - continue; - MAPSET(&installedm, p); - if (unneeded && !MAPTST(&userinstalled, p - installed->start)) - continue; - MAPSET(&im, p); - } - MAPSET(&installedm, SYSTEMSOLVABLE); - MAPSET(&im, SYSTEMSOLVABLE); - -#ifdef CLEANDEPSDEBUG - printf("REMOVE PASS\n"); -#endif - - for (;;) - { - if (!iq.count) - { - if (unneeded) - break; - /* supplements pass */ - for (ip = installed->start; ip < installed->end; ip++) - { - if (!MAPTST(&installedm, ip)) - continue; - s = pool->solvables + ip; - if (!s->supplements) - continue; - if (!MAPTST(&im, ip)) - continue; - if (MAPTST(&userinstalled, ip - installed->start)) - continue; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &im)) - break; - if (!sup) - { - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup))) - { - /* no longer supplemented, also erase */ - int iqcount = iq.count; - /* pin packages, see comment above dep_pkgcheck */ - dep_pkgcheck(solv, sup, &im, &iq); - for (i = iqcount; i < iq.count; i++) - { - Id pqp = iq.elements[i]; - if (pool->solvables[pqp].repo == installed) - MAPSET(&userinstalled, pqp - installed->start); - } - queue_truncate(&iq, iqcount); -#ifdef CLEANDEPSDEBUG - printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup)); -#endif - queue_push(&iq, ip); - } - } - } - if (!iq.count) - break; /* no supplementing package found, we're done */ - } - ip = queue_shift(&iq); - s = pool->solvables + ip; - if (!MAPTST(&im, ip)) - continue; - if (!MAPTST(&installedm, ip)) - continue; - if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start)) - continue; - MAPCLR(&im, ip); -#ifdef CLEANDEPSDEBUG - printf("removing %s\n", pool_solvable2str(pool, s)); -#endif - if (s->requires) - { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) - { - if (req == SOLVABLE_PREREQMARKER) - continue; -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, req)) - { - complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq); - continue; - } -#endif - FOR_PROVIDES(p, pp, req) - { - if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) - { -#ifdef CLEANDEPSDEBUG - printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - queue_push(&iq, p); - } - } - } - } - if (s->recommends) - { - reqp = s->repo->idarraydata + s->recommends; - while ((req = *reqp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, req)) - { - complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq); - continue; - } -#endif - FOR_PROVIDES(p, pp, req) - { - if (p != SYSTEMSOLVABLE && MAPTST(&im, p)) - { -#ifdef CLEANDEPSDEBUG - printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - queue_push(&iq, p); - } - } - } - } - } - - /* turn userinstalled into remove set for pruning */ - map_empty(&userinstalled); - for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) - { - r = solv->rules + rid; - if (r->p >= 0 || r->d != 0 || r->w2 != 0) - continue; /* disabled or not erase */ - p = -r->p; - MAPCLR(&im, p); - if (pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - } - if (!unneeded && solv->cleandeps_updatepkgs) - { - for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) - { - p = solv->cleandeps_updatepkgs->elements[i]; - if (pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - } - } - MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */ - for (p = installed->start; p < installed->end; p++) - if (MAPTST(&im, p)) - queue_push(&iq, p); - for (rid = solv->jobrules; rid < solv->jobrules_end; rid++) - { - r = solv->rules + rid; - if (r->d < 0) - continue; - FOR_RULELITERALS(p, jp, r) - if (p > 0) - queue_push(&iq, p); - } - /* also put directly addressed packages on the install queue - * so we can mark patterns as installed */ - for (i = 0; i < job->count; i += 2) - { - how = job->elements[i]; - if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) - { - what = job->elements[i + 1]; - select = how & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed) - queue_push(&iq, what); - } - } - -#ifdef CLEANDEPSDEBUG - printf("ADDBACK PASS\n"); -#endif - for (;;) - { - if (!iq.count) - { - /* supplements pass */ - for (ip = installed->start; ip < installed->end; ip++) - { - if (!MAPTST(&installedm, ip)) - continue; - if (MAPTST(&userinstalled, ip - installed->start)) - continue; - s = pool->solvables + ip; - if (!s->supplements) - continue; - if (MAPTST(&im, ip)) - continue; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (dep_possible(solv, sup, &im)) - break; - if (sup) - { -#ifdef CLEANDEPSDEBUG - printf("%s supplemented\n", pool_solvid2str(pool, ip)); -#endif - MAPSET(&im, ip); - queue_push(&iq, ip); - } - } - if (!iq.count) - break; - } - ip = queue_shift(&iq); - s = pool->solvables + ip; -#ifdef CLEANDEPSDEBUG - printf("adding back %s\n", pool_solvable2str(pool, s)); -#endif - if (s->requires) - { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, req)) - { - complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled); - continue; - } -#endif - FOR_PROVIDES(p, pp, req) - if (MAPTST(&im, p)) - break; - if (p) - continue; - FOR_PROVIDES(p, pp, req) - { - if (MAPTST(&installedm, p)) - { - if (p == ip) - continue; - if (MAPTST(&userinstalled, p - installed->start)) - continue; -#ifdef CLEANDEPSDEBUG - printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - MAPSET(&im, p); - queue_push(&iq, p); - } - } - } - } - if (s->recommends) - { - reqp = s->repo->idarraydata + s->recommends; - while ((req = *reqp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, req)) - { - complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled); - continue; - } -#endif - FOR_PROVIDES(p, pp, req) - if (MAPTST(&im, p)) - break; - if (p) - continue; - FOR_PROVIDES(p, pp, req) - { - if (MAPTST(&installedm, p)) - { - if (p == ip) - continue; - if (MAPTST(&userinstalled, p - installed->start)) - continue; -#ifdef CLEANDEPSDEBUG - printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p)); -#endif - MAPSET(&im, p); - queue_push(&iq, p); - } - } - } - } - } - - queue_free(&iq); - /* make sure the updatepkgs and mistakes are not in the cleandeps map */ - if (solv->cleandeps_updatepkgs) - for (i = 0; i < solv->cleandeps_updatepkgs->count; i++) - MAPSET(&im, solv->cleandeps_updatepkgs->elements[i]); - if (solv->cleandeps_mistakes) - for (i = 0; i < solv->cleandeps_mistakes->count; i++) - MAPSET(&im, solv->cleandeps_mistakes->elements[i]); - /* also remove original iq packages */ - for (i = 0; i < iqcopy.count; i++) - MAPSET(&im, iqcopy.elements[i]); - queue_free(&iqcopy); - for (p = installed->start; p < installed->end; p++) - { - if (pool->solvables[p].repo != installed) - continue; - if (!MAPTST(&im, p)) - MAPSET(cleandepsmap, p - installed->start); - } - map_free(&im); - map_free(&installedm); - map_free(&userinstalled); - queue_free(&xsuppq); -#ifdef CLEANDEPSDEBUG - printf("=== final cleandeps map:\n"); - for (p = installed->start; p < installed->end; p++) - if (MAPTST(cleandepsmap, p - installed->start)) - printf(" - %s\n", pool_solvid2str(pool, p)); -#endif -} - - -struct trj_data { - Queue *edges; - Id *low; - Id idx; - Id nstack; - Id firstidx; -}; - -/* Tarjan's SCC algorithm, slightly modifed */ -static void -trj_visit(struct trj_data *trj, Id node) -{ - Id *low = trj->low; - Queue *edges = trj->edges; - Id nnode, myidx, stackstart; - int i; - - low[node] = myidx = trj->idx++; - low[(stackstart = trj->nstack++)] = node; - for (i = edges->elements[node]; (nnode = edges->elements[i]) != 0; i++) - { - Id l = low[nnode]; - if (!l) - { - if (!edges->elements[edges->elements[nnode]]) - { - trj->idx++; - low[nnode] = -1; - continue; - } - trj_visit(trj, nnode); - l = low[nnode]; - } - if (l < 0) - continue; - if (l < trj->firstidx) - { - int k; - for (k = l; low[low[k]] == l; k++) - low[low[k]] = -1; - } - else if (l < low[node]) - low[node] = l; - } - if (low[node] == myidx) - { - if (myidx != trj->firstidx) - myidx = -1; - for (i = stackstart; i < trj->nstack; i++) - low[low[i]] = myidx; - trj->nstack = stackstart; - } -} - -#ifdef ENABLE_COMPLEX_DEPS -static void -complex_unneeded(Pool *pool, Id ip, Id req, Queue *edges, Map *cleandepsmap, Queue *unneededq) -{ - int i, j; - Queue dq; - Id p; - - queue_init(&dq); - i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND); - if (i == 0 || i == 1) - { - queue_free(&dq); - return; - } - for (i = 0; i < dq.count; i++) - { - for (; (p = dq.elements[i]) != 0; i++) - { - if (p < 0) - { - if (pool->solvables[-p].repo != pool->installed) - break; - continue; - } - if (p == ip || pool->solvables[p].repo != pool->installed || !MAPTST(cleandepsmap, p - pool->installed->start)) - continue; - for (j = 0; j < unneededq->count; j++) - if (p == unneededq->elements[j]) - { - if (edges->elements[edges->count - 1] != j + 1) - queue_push(edges, j + 1); - break; - } - } - while (dq.elements[i]) - i++; - } - queue_free(&dq); -} -#endif - -void -solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered) -{ - Repo *installed = solv->installed; - int i; - Map cleandepsmap; - - queue_empty(unneededq); - if (!installed || installed->end == installed->start) - return; - - map_init(&cleandepsmap, installed->end - installed->start); - solver_createcleandepsmap(solv, &cleandepsmap, 1); - for (i = installed->start; i < installed->end; i++) - if (MAPTST(&cleandepsmap, i - installed->start)) - queue_push(unneededq, i); - - if (filtered && unneededq->count > 1) - { - Pool *pool = solv->pool; - Queue edges; - Id *nrequires; - Map installedm; - int j, pass, count = unneededq->count; - Id *low; - - map_init(&installedm, pool->nsolvables); - for (i = installed->start; i < installed->end; i++) - if (pool->solvables[i].repo == installed) - MAPSET(&installedm, i); - - nrequires = solv_calloc(count, sizeof(Id)); - queue_init(&edges); - queue_prealloc(&edges, count * 4 + 10); /* pre-size */ - - /* - * Go through the solvables in the nodes queue and create edges for - * all requires/recommends/supplements between the nodes. - * The edges are stored in the edges queue, we add 1 to the node - * index so that nodes in the edges queue are != 0 and we can - * terminate the edge list with 0. - * Thus for node element 5, the edges are stored starting at - * edges.elements[6] and are 0-terminated. - */ - /* leave first element zero to make things easier */ - /* also add trailing zero */ - queue_insertn(&edges, 0, 1 + count + 1, 0); - - /* first requires and recommends */ - for (i = 0; i < count; i++) - { - Solvable *s = pool->solvables + unneededq->elements[i]; - int oldcount = edges.count; - edges.elements[i + 1] = oldcount; - for (pass = 0; pass < 2; pass++) - { - unsigned int off = pass == 0 ? s->requires : s->recommends; - Id p, pp, dep, *dp; - if (off) - for (dp = s->repo->idarraydata + off; (dep = *dp) != 0; dp++) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, dep)) - { - complex_unneeded(pool, s - pool->solvables, dep, &edges, &cleandepsmap, unneededq); - continue; - } -#endif - FOR_PROVIDES(p, pp, dep) - { - Solvable *sp = pool->solvables + p; - if (s == sp || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start)) - continue; - for (j = 0; j < count; j++) - if (p == unneededq->elements[j]) - { - if (edges.elements[edges.count - 1] != j + 1) - queue_push(&edges, j + 1); - } - } - } - if (pass == 0) - nrequires[i] = edges.count - oldcount; - } - queue_push(&edges, 0); - } -#if 0 - printf("requires + recommends\n"); - for (i = 0; i < count; i++) - { - int j; - printf(" %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]); - for (j = edges.elements[i + 1]; edges.elements[j]; j++) - printf(" - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1])); - } -#endif - - /* then add supplements */ - for (i = 0; i < count; i++) - { - Solvable *s = pool->solvables + unneededq->elements[i]; - if (s->supplements) - { - Id *dp; - int k; - for (dp = s->repo->idarraydata + s->supplements; *dp; dp++) - if (dep_possible(solv, *dp, &installedm)) - { - Queue iq; - Id iqbuf[16]; - queue_init_buffer(&iq, iqbuf, sizeof(iqbuf)/sizeof(*iqbuf)); - dep_pkgcheck(solv, *dp, 0, &iq); - for (k = 0; k < iq.count; k++) - { - Id p = iq.elements[k]; - Solvable *sp = pool->solvables + p; - if (p == unneededq->elements[i] || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start)) - continue; - for (j = 0; j < count; j++) - if (p == unneededq->elements[j]) - break; - /* now add edge from j + 1 to i + 1 */ - queue_insert(&edges, edges.elements[j + 1] + nrequires[j], i + 1); - /* addapt following edge pointers */ - for (j = j + 2; j < count + 1; j++) - edges.elements[j]++; - } - queue_free(&iq); - } - } - } -#if 0 - /* print result */ - printf("+ supplements\n"); - for (i = 0; i < count; i++) - { - int j; - printf(" %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]); - for (j = edges.elements[i + 1]; edges.elements[j]; j++) - printf(" - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1])); - } -#endif - map_free(&installedm); - - /* now run SCC algo two times, first with requires+recommends+supplements, - * then again without the requires. We run it the second time to get rid - * of packages that got dragged in via recommends/supplements */ - /* - * low will contain the result of the SCC search. - * it must be of at least size 2 * (count + 1) and - * must be zero initialized. - * The layout is: - * 0 low low ... low stack stack ...stack 0 - * count count - */ - low = solv_calloc(count + 1, 2 * sizeof(Id)); - for (pass = 0; pass < 2; pass++) - { - struct trj_data trj; - if (pass) - { - memset(low, 0, (count + 1) * (2 * sizeof(Id))); - for (i = 0; i < count; i++) - { - edges.elements[i + 1] += nrequires[i]; - if (!unneededq->elements[i]) - low[i + 1] = -1; /* ignore this node */ - } - } - trj.edges = &edges; - trj.low = low; - trj.idx = count + 1; /* stack starts here */ - for (i = 1; i <= count; i++) - { - if (low[i]) - continue; - if (edges.elements[edges.elements[i]]) - { - trj.firstidx = trj.nstack = trj.idx; - trj_visit(&trj, i); - } - else - { - Id myidx = trj.idx++; - low[i] = myidx; - low[myidx] = i; - } - } - /* prune packages */ - for (i = 0; i < count; i++) - if (low[i + 1] <= 0) - unneededq->elements[i] = 0; - } - solv_free(low); - solv_free(nrequires); - queue_free(&edges); - - /* finally remove all pruned entries from unneededq */ - for (i = j = 0; i < count; i++) - if (unneededq->elements[i]) - unneededq->elements[j++] = unneededq->elements[i]; - queue_truncate(unneededq, j); - } - map_free(&cleandepsmap); -} - - void solver_breakorphans(Solver *solv) { diff --git a/libsolv-0.6.15/src/rules.h b/libsolv-0.7.2/src/rules.h similarity index 57% rename from libsolv-0.6.15/src/rules.h rename to libsolv-0.7.2/src/rules.h index 606819b..a3c0135 100644 --- a/libsolv-0.6.15/src/rules.h +++ b/libsolv-0.7.2/src/rules.h @@ -35,7 +35,7 @@ extern "C" { * possible. Do not add new members unless there is no other way. */ -typedef struct _Rule { +typedef struct s_Rule { Id p; /* first literal in rule */ Id d; /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */ /* in case of binary rules, d == 0, w1 == p, w2 == other literal */ @@ -58,6 +58,7 @@ typedef enum { SOLVER_RULE_PKG_OBSOLETES, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, + SOLVER_RULE_PKG_RECOMMENDS, SOLVER_RULE_UPDATE = 0x200, SOLVER_RULE_FEATURE = 0x300, SOLVER_RULE_JOB = 0x400, @@ -75,14 +76,14 @@ typedef enum { #define SOLVER_RULE_TYPEMASK 0xff00 -struct _Solver; +struct s_Solver; /*------------------------------------------------------------------- * disable rule */ static inline void -solver_disablerule(struct _Solver *solv, Rule *r) +solver_disablerule(struct s_Solver *solv, Rule *r) { if (r->d >= 0) r->d = -r->d - 1; @@ -93,63 +94,64 @@ solver_disablerule(struct _Solver *solv, Rule *r) */ static inline void -solver_enablerule(struct _Solver *solv, Rule *r) +solver_enablerule(struct s_Solver *solv, Rule *r) { if (r->d < 0) r->d = -r->d - 1; } -extern Rule *solver_addrule(struct _Solver *solv, Id p, Id p2, Id d); -extern void solver_unifyrules(struct _Solver *solv); -extern int solver_rulecmp(struct _Solver *solv, Rule *r1, Rule *r2); -extern void solver_shrinkrules(struct _Solver *solv, int nrules); +extern Rule *solver_addrule(struct s_Solver *solv, Id p, Id p2, Id d); +extern void solver_unifyrules(struct s_Solver *solv); +extern int solver_rulecmp(struct s_Solver *solv, Rule *r1, Rule *r2); +extern void solver_shrinkrules(struct s_Solver *solv, int nrules); /* pkg rules */ -extern void solver_addpkgrulesforsolvable(struct _Solver *solv, Solvable *s, Map *m); -extern void solver_addpkgrulesforweak(struct _Solver *solv, Map *m); -extern void solver_addpkgrulesforlinked(struct _Solver *solv, Map *m); -extern void solver_addpkgrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all); +extern void solver_addpkgrulesforsolvable(struct s_Solver *solv, Solvable *s, Map *m); +extern void solver_addpkgrulesforweak(struct s_Solver *solv, Map *m); +extern void solver_addpkgrulesforlinked(struct s_Solver *solv, Map *m); +extern void solver_addpkgrulesforupdaters(struct s_Solver *solv, Solvable *s, Map *m, int allow_all); /* update/feature rules */ -extern void solver_addupdaterule(struct _Solver *solv, Solvable *s, int allow_all); +extern void solver_addfeaturerule(struct s_Solver *solv, Solvable *s); +extern void solver_addupdaterule(struct s_Solver *solv, Solvable *s); /* infarch rules */ -extern void solver_addinfarchrules(struct _Solver *solv, Map *addedmap); +extern void solver_addinfarchrules(struct s_Solver *solv, Map *addedmap); /* dup rules */ -extern void solver_createdupmaps(struct _Solver *solv); -extern void solver_freedupmaps(struct _Solver *solv); -extern void solver_addduprules(struct _Solver *solv, Map *addedmap); +extern void solver_createdupmaps(struct s_Solver *solv); +extern void solver_freedupmaps(struct s_Solver *solv); +extern void solver_addduprules(struct s_Solver *solv, Map *addedmap); /* choice rules */ -extern void solver_addchoicerules(struct _Solver *solv); -extern void solver_disablechoicerules(struct _Solver *solv, Rule *r); +extern void solver_addchoicerules(struct s_Solver *solv); +extern void solver_disablechoicerules(struct s_Solver *solv, Rule *r); /* best rules */ -extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs); +extern void solver_addbestrules(struct s_Solver *solv, int havebestinstalljobs); /* yumobs rules */ -extern void solver_addyumobsrules(struct _Solver *solv); +extern void solver_addyumobsrules(struct s_Solver *solv); /* policy rule disabling/reenabling */ -extern void solver_disablepolicyrules(struct _Solver *solv); -extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx); -extern void solver_reenablepolicyrules_cleandeps(struct _Solver *solv, Id pkg); +extern void solver_disablepolicyrules(struct s_Solver *solv); +extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx); +extern void solver_reenablepolicyrules_cleandeps(struct s_Solver *solv, Id pkg); /* rule info */ -extern int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq); -extern SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp); -extern SolverRuleinfo solver_ruleclass(struct _Solver *solv, Id rid); -extern void solver_ruleliterals(struct _Solver *solv, Id rid, Queue *q); -extern int solver_rule2jobidx(struct _Solver *solv, Id rid); -extern Id solver_rule2job(struct _Solver *solv, Id rid, Id *whatp); -extern Id solver_rule2solvable(struct _Solver *solv, Id rid); -extern void solver_rule2rules(struct _Solver *solv, Id rid, Queue *q, int recursive); -extern Id solver_rule2pkgrule(struct _Solver *solv, Id rid); +extern int solver_allruleinfos(struct s_Solver *solv, Id rid, Queue *rq); +extern SolverRuleinfo solver_ruleinfo(struct s_Solver *solv, Id rid, Id *fromp, Id *top, Id *depp); +extern SolverRuleinfo solver_ruleclass(struct s_Solver *solv, Id rid); +extern void solver_ruleliterals(struct s_Solver *solv, Id rid, Queue *q); +extern int solver_rule2jobidx(struct s_Solver *solv, Id rid); +extern Id solver_rule2job(struct s_Solver *solv, Id rid, Id *whatp); +extern Id solver_rule2solvable(struct s_Solver *solv, Id rid); +extern void solver_rule2rules(struct s_Solver *solv, Id rid, Queue *q, int recursive); +extern Id solver_rule2pkgrule(struct s_Solver *solv, Id rid); /* orphan handling */ -extern void solver_breakorphans(struct _Solver *solv); -extern void solver_check_brokenorphanrules(struct _Solver *solv, Queue *dq); +extern void solver_breakorphans(struct s_Solver *solv); +extern void solver_check_brokenorphanrules(struct s_Solver *solv, Queue *dq); /* legacy */ diff --git a/libsolv-0.7.2/src/selection.c b/libsolv-0.7.2/src/selection.c new file mode 100644 index 0000000..a160122 --- /dev/null +++ b/libsolv-0.7.2/src/selection.c @@ -0,0 +1,2081 @@ +/* + * Copyright (c) 2012, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * selection.c + * + */ + +#define _GNU_SOURCE +#include +#include + +#include +#include +#include + +#include "selection.h" +#include "solver.h" +#include "evr.h" + + +static int +str2archid(Pool *pool, const char *arch) +{ + Id id; + if (!*arch) + return 0; + id = pool_str2id(pool, arch, 0); + if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) + return id; + if (pool->id2arch && pool_arch2score(pool, id) == 0) + return 0; + return id; +} + +/* remove empty jobs from the selection */ +static void +selection_prune(Pool *pool, Queue *selection) +{ + int i, j; + Id p, pp; + for (i = j = 0; i < selection->count; i += 2) + { + Id select = selection->elements[i] & SOLVER_SELECTMASK; + p = 0; + if (select == SOLVER_SOLVABLE_ALL) + p = 1; + else if (select == SOLVER_SOLVABLE_REPO) + { + Solvable *s; + Repo *repo = pool_id2repo(pool, selection->elements[i + 1]); + if (repo) + { + FOR_REPO_SOLVABLES(repo, p, s) + break; + } + } + else + { + FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1]) + break; + } + if (!p) + continue; + selection->elements[j] = selection->elements[i]; + selection->elements[j + 1] = selection->elements[i + 1]; + j += 2; + } + queue_truncate(selection, j); +} + + +static int +selection_solvables_sortcmp(const void *ap, const void *bp, void *dp) +{ + return *(const Id *)ap - *(const Id *)bp; +} + +void +selection_solvables(Pool *pool, Queue *selection, Queue *pkgs) +{ + int i, j; + Id p, pp, lastid; + queue_empty(pkgs); + for (i = 0; i < selection->count; i += 2) + { + Id select = selection->elements[i] & SOLVER_SELECTMASK; + Id id = selection->elements[i + 1]; + if (select == SOLVER_SOLVABLE_ALL) + { + FOR_POOL_SOLVABLES(p) + queue_push(pkgs, p); + } + if (select == SOLVER_SOLVABLE_REPO) + { + Solvable *s; + Repo *repo = pool_id2repo(pool, id); + if (repo) + { + FOR_REPO_SOLVABLES(repo, p, s) + queue_push(pkgs, p); + } + } + else if (select == SOLVER_SOLVABLE) + queue_push(pkgs, id); + else + { + FOR_JOB_SELECT(p, pp, select, id) + queue_push(pkgs, p); + } + } + if (pkgs->count < 2) + return; + /* sort and unify */ + solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL); + lastid = pkgs->elements[0]; + for (i = j = 1; i < pkgs->count; i++) + if (pkgs->elements[i] != lastid) + pkgs->elements[j++] = lastid = pkgs->elements[i]; + queue_truncate(pkgs, j); +} + +static void +selection_flatten(Pool *pool, Queue *selection) +{ + Queue q; + int i; + if (selection->count <= 2) + return; + for (i = 0; i < selection->count; i += 2) + if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL) + { + selection->elements[0] = selection->elements[i]; + selection->elements[1] = selection->elements[i + 1]; + queue_truncate(selection, 2); + return; + } + queue_init(&q); + selection_solvables(pool, selection, &q); + if (!q.count) + { + queue_empty(selection); + return; + } + queue_truncate(selection, 2); + if (q.count > 1) + { + selection->elements[0] = SOLVER_SOLVABLE_ONE_OF; + selection->elements[1] = pool_queuetowhatprovides(pool, &q); + } + else + { + selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + selection->elements[1] = q.elements[0]; + } +} + +/* only supports simple rels plus REL_ARCH */ +static int +match_nevr_rel(Pool *pool, Solvable *s, Id rflags, Id revr) +{ + if (rflags == REL_ARCH) + { + if (s->arch != revr) + { + if (revr != ARCH_SRC || s->arch != ARCH_NOSRC) + return 0; + } + return 1; + } + if (rflags > 7) + return 0; + return pool_intersect_evrs(pool, REL_EQ, s->evr, rflags, revr); +} + +/* only supports simple rels plus REL_ARCH */ +static void +selection_filter_rel_noprune(Pool *pool, Queue *selection, Id relflags, Id relevr) +{ + int i; + + if (!selection->count) + return; + + for (i = 0; i < selection->count; i += 2) + { + Id select = selection->elements[i] & SOLVER_SELECTMASK; + Id id = selection->elements[i + 1]; + if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF) + { + /* done by selection_addextra, currently implies SELECTION_NAME */ + Queue q; + Id p, pp; + int miss = 0; + + queue_init(&q); + FOR_JOB_SELECT(p, pp, select, id) + { + Solvable *s = pool->solvables + p; + if (match_nevr_rel(pool, s, relflags, relevr)) + queue_push(&q, p); + else + miss = 1; + } + if (miss) + { + if (q.count == 1) + { + selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + selection->elements[i + 1] = q.elements[0]; + } + else + { + selection->elements[i] = SOLVER_SOLVABLE_ONE_OF; + selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q); + } + } + queue_free(&q); + } + else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) + { + /* don't stack src reldeps */ + if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC) + id = rd->name; + } + selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1); + } + else + continue; /* actually cannot happen */ + + /* now add the setflags we gained */ + if (relflags == REL_ARCH) + selection->elements[i] |= SOLVER_SETARCH; + if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES) + { + if (pool->disttype == DISTTYPE_DEB) + selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */ + else + { + const char *rel = strrchr(pool_id2str(pool, relevr), '-'); + selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV; + } + } + } +} + +/* only supports simple rels plus REL_ARCH */ +/* prunes empty jobs */ +static void +selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr) +{ + selection_filter_rel_noprune(pool, selection, relflags, relevr); + selection_prune(pool, selection); +} + +/* limit a selection to to repository */ +/* prunes empty jobs */ +static void +selection_filter_repo(Pool *pool, Queue *selection, Repo *repo, int setflags) +{ + Queue q; + int i, j; + + if (!selection->count) + return; + if (!repo) + { + queue_empty(selection); + return; + } + queue_init(&q); + for (i = j = 0; i < selection->count; i += 2) + { + Id select = selection->elements[i] & SOLVER_SELECTMASK; + Id id = selection->elements[i + 1]; + if (select == SOLVER_SOLVABLE_ALL) + { + select = SOLVER_SOLVABLE_REPO; + id = repo->repoid; + } + else if (select == SOLVER_SOLVABLE_REPO) + { + if (id != repo->repoid) + continue; + } + else if (select == SOLVER_SOLVABLE) + { + if (pool->solvables[id].repo != repo) + continue; + } + else + { + int bad = 0; + Id p, pp; + queue_empty(&q); + FOR_JOB_SELECT(p, pp, select, id) + { + if (pool->solvables[p].repo != repo) + bad = 1; + else + queue_push(&q, p); + } + if (!q.count) + continue; + if (bad) + { + if (q.count == 1) + { + select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + id = q.elements[0]; + } + else + { + select = SOLVER_SOLVABLE_ONE_OF; + id = pool_queuetowhatprovides(pool, &q); + } + } + } + if (select == SOLVER_SOLVABLE_REPO) + { + Id p; + Solvable *s; + FOR_REPO_SOLVABLES(repo, p, s) + break; + if (!p) + continue; /* repo is empty */ + } + selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | setflags; + selection->elements[j++] = id; + } + queue_truncate(selection, j); + queue_free(&q); +} + + +static int +matchprovides(Pool *pool, Solvable *s, Id dep) +{ + Id id, *idp; + idp = s->repo->idarraydata + s->provides; + while ((id = *idp++) != 0) + if (pool_match_dep(pool, id, dep)) + return 1; + return 0; +} + +/* change a SOLVER_SOLVABLE_NAME/PROVIDES selection to something that also includes + * extra packages. + * extra packages are: src, badarch, disabled + */ +static void +selection_addextra(Pool *pool, Queue *selection, int flags) +{ + Queue q; + Id p, pp, dep; + int i, isextra, haveextra, doprovides; + + if ((flags & SELECTION_INSTALLED_ONLY) != 0) + flags &= ~SELECTION_WITH_SOURCE; + + if (!(flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH))) + return; /* nothing to add */ + + queue_init(&q); + for (i = 0; i < selection->count; i += 2) + { + if (selection->elements[i] == SOLVER_SOLVABLE_NAME) + doprovides = 0; + else if (selection->elements[i] == SOLVER_SOLVABLE_PROVIDES) + doprovides = 1; + else + continue; + dep = selection->elements[i + 1]; + haveextra = 0; + queue_empty(&q); + if (doprovides) + { + /* first put all non-extra packages on the queue */ + FOR_PROVIDES(p, pp, dep) + { + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && pool->solvables[p].repo != pool->installed) + continue; + queue_push(&q, p); + } + } + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (!doprovides && !pool_match_nevr(pool, s, dep)) + continue; + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + isextra = 0; + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) + { + if (!(flags & SELECTION_WITH_SOURCE) && !(flags & SELECTION_SOURCE_ONLY)) + continue; + if (!(flags & SELECTION_SOURCE_ONLY)) + isextra = 1; + if (pool_disabled_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_DISABLED)) + continue; + isextra = 1; + } + } + else + { + if ((flags & SELECTION_SOURCE_ONLY) != 0) + continue; + if (s->repo != pool->installed) + { + if (pool_disabled_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_DISABLED)) + continue; + isextra = 1; + } + if (pool_badarch_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_BADARCH)) + continue; + isextra = 1; + } + } + } + if (doprovides) + { + if (!isextra) + continue; /* already done above in FOR_PROVIDES */ + if (!s->provides || !matchprovides(pool, s, dep)) + continue; + } + haveextra |= isextra; + queue_push(&q, p); + } + if (!haveextra || !q.count) + continue; + if (q.count == 1) + { + selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + selection->elements[i + 1] = q.elements[0]; + } + else + { + if (doprovides) + solv_sort(q.elements, q.count, sizeof(Id), selection_solvables_sortcmp, NULL); + selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF; + selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q); + } + } + queue_free(&q); +} + +static inline const char * +skipkind(const char *n) +{ + const char *s; + for (s = n; *s >= 'a' && *s <= 'z'; s++) + ; + if (*s == ':' && s != n) + return s + 1; + return n; +} + +static inline void +queue_pushunique2(Queue *q, Id id1, Id id2) +{ + int i; + for (i = 0; i < q->count; i += 2) + if (q->elements[i] == id1 && q->elements[i + 1] == id2) + return; + queue_push2(q, id1, id2); +} + + +/***** provides matching *****/ + +static int +selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int flags) +{ + Id p, id, *idp; + int match = 0; + int doglob, nocase, globflags; + + if ((flags & SELECTION_INSTALLED_ONLY) != 0) + return 0; /* neither disabled nor badarch nor src */ + + nocase = flags & SELECTION_NOCASE; + doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0; + globflags = doglob && nocase ? FNM_CASEFOLD : 0; + + FOR_POOL_SOLVABLES(p) + { + const char *n; + Solvable *s = pool->solvables + p; + if (!s->provides) + continue; + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) /* no provides */ + continue; + if (s->repo == pool->installed) + continue; + if (pool_disabled_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_DISABLED)) + continue; + if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s)) + continue; + } + else if (pool_badarch_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_BADARCH)) + continue; + } + else + continue; + /* here is an extra solvable we need to consider */ + idp = s->repo->idarraydata + s->provides; + while ((id = *idp++) != 0) + { + while (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + id = rd->name; + } + if (pool->whatprovides[id] > 1) + continue; /* we already did that one in the normal code path */ + n = pool_id2str(pool, id); + if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0) + { + queue_pushunique2(selection, SOLVER_SOLVABLE_PROVIDES, id); + match = 1; + } + } + } + return match; +} + +/* this is the fast path of selection_provides: the id for the name + * is known and thus we can use the whatprovides data to quickly + * check the existance of a package with that provides */ +static int +selection_provides_id(Pool *pool, Queue *selection, Id id, int flags) +{ + Id p, pp; + + FOR_PROVIDES(p, pp, id) + { + Solvable *s = pool->solvables + p; + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); + return SELECTION_PROVIDES; + } + + if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0) + { + /* misuse selection_addextra to test if there is an extra package + * that provides the id */ + queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); + selection_addextra(pool, selection, flags); + if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES) + queue_empty(selection); /* no extra package found */ + else + { + selection->elements[0] = SOLVER_SOLVABLE_PROVIDES; + selection->elements[1] = id; + } + return selection->count ? SELECTION_PROVIDES : 0; + } + + return 0; +} + +/* match the provides of a package */ +/* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs + * so that the selection can be modified later. */ +static int +selection_provides(Pool *pool, Queue *selection, const char *name, int flags) +{ + Id id, p, pp; + int match; + int doglob; + int nocase; + int globflags; + const char *n; + + if ((flags & SELECTION_SOURCE_ONLY) != 0) + return 0; /* sources do not have provides */ + + nocase = flags & SELECTION_NOCASE; + if (!nocase) + { + /* try the fast path first */ + id = pool_str2id(pool, name, 0); + if (id) + { + /* the id is known, do the fast id matching */ + int ret = selection_provides_id(pool, selection, id, flags); + if (ret) + return ret; + } + } + + doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0; + if (!nocase && !doglob) + { + /* all done above in selection_provides_id */ + return 0; + } + + /* looks like a glob or nocase match. really hard work. */ + match = 0; + globflags = doglob && nocase ? FNM_CASEFOLD : 0; + for (id = 1; id < pool->ss.nstrings; id++) + { + /* do we habe packages providing this id? */ + if ((!pool->whatprovides[id] && pool->addedfileprovides == 2) || pool->whatprovides[id] == 1) + continue; + n = pool_id2str(pool, id); + if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0) + { + if ((flags & SELECTION_INSTALLED_ONLY) != 0) + { + FOR_PROVIDES(p, pp, id) + if (pool->solvables[p].repo == pool->installed) + break; + if (!p) + continue; + } + else if (!pool->whatprovides[id]) + { + FOR_PROVIDES(p, pp, id) + break; + if (!p) + continue; + } + queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id); + match = 1; + } + } + + if (flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) + match |= selection_addextra_provides(pool, selection, name, flags); + + return match ? SELECTION_PROVIDES : 0; +} + +/***** name matching *****/ + +/* this is the fast path of selection_name: the id for the name + * is known and thus we can quickly check the existance of a + * package with that name */ +static int +selection_name_id(Pool *pool, Queue *selection, Id id, int flags) +{ + Id p, pp, matchid; + + matchid = id; + if ((flags & SELECTION_SOURCE_ONLY) != 0) + { + /* sources cannot be installed */ + if ((flags & SELECTION_INSTALLED_ONLY) != 0) + return 0; + /* add ARCH_SRC to match only sources */ + matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); + flags &= ~SELECTION_WITH_SOURCE; + } + + FOR_PROVIDES(p, pp, matchid) + { + Solvable *s = pool->solvables + p; + if (s->name != id) + continue; + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + /* one match is all we need */ + queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid); + /* add the requested extra packages */ + if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0) + selection_addextra(pool, selection, flags); + return SELECTION_NAME; + } + + if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0) + { + queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid); + selection_addextra(pool, selection, flags); + if (selection->elements[0] == SOLVER_SOLVABLE_NAME) + queue_empty(selection); + return selection->count ? SELECTION_NAME : 0; + } + + if ((flags & SELECTION_WITH_SOURCE) != 0 && (flags & SELECTION_INSTALLED_ONLY) == 0) + { + /* WITH_SOURCE case, but we had no match. try SOURCE_ONLY instead */ + matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); + FOR_PROVIDES(p, pp, matchid) + { + Solvable *s = pool->solvables + p; + if (s->name != id) + continue; + queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid); + return SELECTION_NAME; + } + } + return 0; +} + +/* does not check SELECTION_INSTALLED_ONLY, as it is normally done + * by other means */ +static inline int +solvable_matches_selection_flags(Pool *pool, Solvable *s, int flags) +{ + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) + { + if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE)) + return 0; + /* source package are never installed and never have a bad arch */ + if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s)) + return 0; + } + else + { + if ((flags & SELECTION_SOURCE_ONLY) != 0) + return 0; + if (s->repo != pool->installed) + { + if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s)) + return 0; + if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s)) + return 0; + } + } + return 1; +} + +/* match the name of a package */ +/* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */ +static int +selection_name(Pool *pool, Queue *selection, const char *name, int flags) +{ + Id id, p; + int match; + int doglob, nocase; + int globflags; + const char *n; + + if ((flags & SELECTION_SOURCE_ONLY) != 0) + flags &= ~SELECTION_WITH_SOURCE; + + nocase = flags & SELECTION_NOCASE; + if (!nocase && !(flags & SELECTION_SKIP_KIND)) + { + /* try the fast path first */ + id = pool_str2id(pool, name, 0); + if (id) + { + int ret = selection_name_id(pool, selection, id, flags); + if (ret) + return ret; + } + } + + doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0; + if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob) + return 0; /* all done above in selection_name_id */ + + /* do a name match over all packages. hard work. */ + match = 0; + globflags = doglob && nocase ? FNM_CASEFOLD : 0; + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + if (!solvable_matches_selection_flags(pool, s, flags)) + continue; + id = s->name; + n = pool_id2str(pool, id); + if (flags & SELECTION_SKIP_KIND) + n = skipkind(n); + if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0) + { + if ((flags & SELECTION_SOURCE_ONLY) != 0) + { + if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + continue; + id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1); + } + queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id); + match = 1; + } + } + if (match) + { + /* if there was a match widen the selector to include all extra packages */ + if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0) + selection_addextra(pool, selection, flags); + return SELECTION_NAME; + } + return 0; +} + + +/***** SELECTION_DOTARCH and SELECTION_REL handling *****/ + +/* like selection_name, but check for a .arch suffix if the match did + not work and SELECTION_DOTARCH is used */ +static int +selection_name_arch(Pool *pool, Queue *selection, const char *name, int flags, int doprovides, int noprune) +{ + int ret; + const char *r; + Id archid; + + if (doprovides) + ret = selection_provides(pool, selection, name, flags); + else + ret = selection_name(pool, selection, name, flags); + if (ret) + return ret; + if (!(flags & SELECTION_DOTARCH)) + return 0; + /* check if there is an .arch suffix */ + if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) + { + char *rname = solv_strdup(name); + rname[r - name] = 0; + if (archid == ARCH_SRC || archid == ARCH_NOSRC) + flags |= SELECTION_SOURCE_ONLY; + if (doprovides) + ret = selection_provides(pool, selection, rname, flags); + else + ret = selection_name(pool, selection, rname, flags); + if (ret) + { + selection_filter_rel_noprune(pool, selection, REL_ARCH, archid); + if (!noprune) + selection_prune(pool, selection); + } + solv_free(rname); + return ret && selection->count ? ret | SELECTION_DOTARCH : 0; + } + return 0; +} + +static char * +splitrel(char *rname, char *r, int *rflagsp) +{ + int nend = r - rname; + int rflags = 0; + if (nend && *r == '=' && r[-1] == '!') + { + nend--; + r++; + rflags = REL_LT|REL_GT; + } + for (; *r; r++) + { + if (*r == '<') + rflags |= REL_LT; + else if (*r == '=') + rflags |= REL_EQ; + else if (*r == '>') + rflags |= REL_GT; + else + break; + } + while (*r && (*r == ' ' || *r == '\t')) + r++; + while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t')) + nend--; + if (nend <= 0 || !*r || !rflags) + return 0; + *rflagsp = rflags; + rname[nend] = 0; + return r; +} + +/* match name/provides, support DOTARCH and REL modifiers + */ +static int +selection_name_arch_rel(Pool *pool, Queue *selection, const char *name, int flags, int doprovides) +{ + int ret, rflags = 0, noprune; + char *r = 0, *rname = 0; + + /* try to split off an relation part */ + if ((flags & SELECTION_REL) != 0) + { + if ((r = strpbrk(name, "<=>")) != 0) + { + rname = solv_strdup(name); + r = rname + (r - name); + if ((r = splitrel(rname, r, &rflags)) == 0) + rname = solv_free(rname); + } + } + + /* check if we need to call selection_addextra */ + noprune = doprovides && (flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)); + + if (!r) + { + /* could not split off relation */ + ret = selection_name_arch(pool, selection, name, flags, doprovides, noprune); + if (ret && noprune) + { + selection_addextra(pool, selection, flags); + selection_prune(pool, selection); + } + return ret && selection->count ? ret : 0; + } + + /* we could split of a relation. prune name and then filter rel */ + ret = selection_name_arch(pool, selection, rname, flags, doprovides, noprune); + if (ret) + { + selection_filter_rel_noprune(pool, selection, rflags, pool_str2id(pool, r, 1)); + if (noprune) + selection_addextra(pool, selection, flags); + selection_prune(pool, selection); + } + solv_free(rname); + return ret && selection->count ? ret | SELECTION_REL : 0; +} + +/***** filelist matching *****/ + +static int +selection_filelist_sortcmp(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + const Id *a = ap, *b = bp; + if (a[0] != b[0]) + return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0])); + return a[1] - b[1]; +} + +static int +selection_filelist(Pool *pool, Queue *selection, const char *name, int flags) +{ + Dataiterator di; + Queue q; + Id id; + int type; + int i, j, lastid; + + /* all files in the file list start with a '/' */ + if (*name != '/') + { + if (!(flags & SELECTION_GLOB)) + return 0; + if (*name != '*' && *name != '[' && *name != '?') + return 0; + } + type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB; + if ((flags & SELECTION_NOCASE) != 0) + type |= SEARCH_NOCASE; + queue_init(&q); + dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES); + while (dataiterator_step(&di)) + { + Solvable *s = pool->solvables + di.solvid; + if (!s->repo) + continue; + if (!solvable_matches_selection_flags(pool, s, flags)) + continue; + if ((flags & SELECTION_FLAT) != 0) + { + /* don't bother with the complex stuff */ + queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, di.solvid); + dataiterator_skip_solvable(&di); + continue; + } + id = pool_str2id(pool, di.kv.str, 1); + queue_push2(&q, id, di.solvid); + } + dataiterator_free(&di); + if ((flags & SELECTION_FLAT) != 0) + { + queue_free(&q); + return selection->count ? SELECTION_FILELIST : 0; + } + if (!q.count) + { + queue_free(&q); + return 0; + } + solv_sort(q.elements, q.count / 2, 2 * sizeof(Id), selection_filelist_sortcmp, pool); + lastid = 0; + queue_push2(&q, 0, 0); + for (i = j = 0; i < q.count; i += 2) + { + if (q.elements[i] != lastid) + { + if (j == 1) + queue_pushunique2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]); + else if (j > 1) + { + int k; + Id *idp; + /* check if we already have it */ + for (k = 0; k < selection->count; k += 2) + { + if (selection->elements[k] != SOLVER_SOLVABLE_ONE_OF) + continue; + idp = pool->whatprovidesdata + selection->elements[k + 1]; + if (!memcmp(idp, q.elements, j * sizeof(Id)) && !idp[j]) + break; + } + if (k == selection->count) + queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_ids2whatprovides(pool, q.elements, j)); + } + lastid = q.elements[i]; + j = 0; + } + if (!j || q.elements[j - 1] != q.elements[i]) + q.elements[j++] = q.elements[i + 1]; + } + queue_free(&q); + return SELECTION_FILELIST; +} + + +/***** canon name matching *****/ + +#if defined(MULTI_SEMANTICS) +# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE) +#elif defined(DEBIAN) +# define EVRCMP_DEPCMP EVRCMP_COMPARE +#else +# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE +#endif + +/* magic epoch promotion code, works only for SELECTION_NAME selections */ +static void +selection_filter_evr(Pool *pool, Queue *selection, const char *evr) +{ + int i, j; + Queue q; + Id qbuf[10]; + const char *sp; + + /* do we already have an epoch? */ + for (sp = evr; *sp >= '0' && *sp <= '9'; sp++) + ; + if (*sp == ':' && sp != evr) + { + /* yes, just add the rel filter */ + selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, evr, 1)); + return; + } + + queue_init(&q); + queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf)); + for (i = j = 0; i < selection->count; i += 2) + { + Id select = selection->elements[i] & SOLVER_SELECTMASK; + Id id = selection->elements[i + 1]; + Id p, pp; + const char *lastepoch = 0; + int lastepochlen = 0; + + queue_empty(&q); + FOR_JOB_SELECT(p, pp, select, id) + { + Solvable *s = pool->solvables + p; + const char *sevr = pool_id2str(pool, s->evr); + for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++) + ; + if (*sp != ':') + sp = sevr; + /* compare vr part */ + if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0) + { + int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP); + if (r == -1 || r == 1) + continue; /* solvable does not match vr */ + } + queue_push(&q, p); + if (sp > sevr) + { + while (sevr < sp && *sevr == '0') /* normalize epoch */ + sevr++; + } + if (!lastepoch) + { + lastepoch = sevr; + lastepochlen = sp - sevr; + } + else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0) + lastepochlen = -1; /* multiple different epochs */ + } + if (!lastepoch || lastepochlen == 0) + id = pool_str2id(pool, evr, 1); /* no match at all or zero epoch */ + else if (lastepochlen >= 0) + { + /* found exactly one epoch, simply prepend */ + char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2); + strncpy(evrx, lastepoch, lastepochlen + 1); + strcpy(evrx + lastepochlen + 1, evr); + id = pool_str2id(pool, evrx, 1); + solv_free(evrx); + } + else + { + /* multiple epochs in multiple solvables, convert to list of solvables */ + selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF; + selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q); + j += 2; + continue; + } + queue_empty(&q); + queue_push2(&q, selection->elements[i], selection->elements[i + 1]); + selection_filter_rel(pool, &q, REL_EQ, id); + if (!q.count) + continue; /* oops, no match */ + selection->elements[j] = q.elements[0]; + selection->elements[j + 1] = q.elements[1]; + j += 2; + } + queue_truncate(selection, j); + queue_free(&q); +} + +/* match the "canonical" name of the package */ +static int +selection_canon(Pool *pool, Queue *selection, const char *name, int flags) +{ + char *rname, *r, *r2; + Id archid = 0; + int ret; + + /* + * nameglob-version + * nameglob-version.arch + * nameglob-version-release + * nameglob-version-release.arch + */ + flags |= SELECTION_NAME; + flags &= ~SELECTION_PROVIDES; + + if (pool->disttype == DISTTYPE_DEB) + { + if ((r = strchr(name, '_')) == 0) + return 0; + rname = solv_strdup(name); /* so we can modify it */ + r = rname + (r - name); + *r++ = 0; + if ((ret = selection_name(pool, selection, rname, flags)) == 0) + { + solv_free(rname); + return 0; + } + /* is there a vaild arch? */ + if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) + { + *r2 = 0; /* split off */ + selection_filter_rel(pool, selection, REL_ARCH, archid); + } + selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1)); + solv_free(rname); + return selection->count ? ret | SELECTION_CANON : 0; + } + + if (pool->disttype == DISTTYPE_HAIKU) + { + if ((r = strchr(name, '-')) == 0) + return 0; + rname = solv_strdup(name); /* so we can modify it */ + r = rname + (r - name); + *r++ = 0; + if ((ret = selection_name(pool, selection, rname, flags)) == 0) + { + solv_free(rname); + return 0; + } + /* is there a vaild arch? */ + if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) + { + *r2 = 0; /* split off */ + selection_filter_rel(pool, selection, REL_ARCH, archid); + } + selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1)); + solv_free(rname); + return selection->count ? ret | SELECTION_CANON : 0; + } + + if ((r = strrchr(name, '-')) == 0) + return 0; + rname = solv_strdup(name); /* so we can modify it */ + r = rname + (r - name); + *r = 0; + + /* split off potential arch part from version */ + if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0) + *r2 = 0; /* found valid arch, split it off */ + if (archid == ARCH_SRC || archid == ARCH_NOSRC) + flags |= SELECTION_SOURCE_ONLY; + + /* try with just the version */ + if ((ret = selection_name(pool, selection, rname, flags)) == 0) + { + /* no luck, try with version-release */ + if ((r2 = strrchr(rname, '-')) == 0) + { + solv_free(rname); + return 0; + } + *r = '-'; + *r2 = 0; + r = r2; + if ((ret = selection_name(pool, selection, rname, flags)) == 0) + { + solv_free(rname); + return 0; + } + } + if (archid) + selection_filter_rel(pool, selection, REL_ARCH, archid); + selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */ + solv_free(rname); + return selection->count ? ret | SELECTION_CANON : 0; +} + +/* return the needed withbits to match the provided selection */ +static int +selection_extrabits(Pool *pool, Queue *selection, int flags) +{ + int i, needflags, isextra; + int allflags; + Id p; + Solvable *s; + Queue qlimit; + + allflags = flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH); + if (!selection->count) + return allflags; + if (selection->count == 2 && selection->elements[0] == SOLVER_SOLVABLE_ALL) + return allflags; /* don't bother */ + queue_init(&qlimit); + selection_solvables(pool, selection, &qlimit); + needflags = 0; + for (i = 0; i < qlimit.count; i++) + { + p = qlimit.elements[i]; + s = pool->solvables + p; + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed) + continue; + isextra = 0; + if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) + { + if (!(flags & SELECTION_WITH_SOURCE)) + continue; + isextra |= SELECTION_WITH_SOURCE; + if (pool_disabled_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_DISABLED)) + continue; + isextra |= SELECTION_WITH_DISABLED; + } + } + else + { + if ((flags & SELECTION_SOURCE_ONLY) != 0) + continue; + if (s->repo != pool->installed) + { + if (pool_disabled_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_DISABLED)) + continue; + isextra |= SELECTION_WITH_DISABLED; + } + if (pool_badarch_solvable(pool, s)) + { + if (!(flags & SELECTION_WITH_BADARCH)) + continue; + isextra |= SELECTION_WITH_BADARCH; + } + } + } + if (isextra) + { + needflags |= isextra; + if (needflags == allflags) + break; + } + } + queue_free(&qlimit); + return needflags; +} + +static int +selection_combine(Pool *pool, Queue *sel1, Queue *sel2, int flags, int ret) +{ + if ((flags & SELECTION_MODEBITS) == SELECTION_ADD) + selection_add(pool, sel1, sel2); + else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT) + selection_subtract(pool, sel1, sel2); + else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER) + { + if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY)) + { + if ((flags & SELECTION_FILTER_SWAPPED) != 0) + { + selection_filter(pool, sel2, sel1); + queue_free(sel1); + queue_init_clone(sel1, sel2); + } + else + selection_filter(pool, sel1, sel2); + } + } + else /* SELECTION_REPLACE */ + { + queue_free(sel1); + queue_init_clone(sel1, sel2); + } + queue_free(sel2); + return ret; +} + +int +selection_make(Pool *pool, Queue *selection, const char *name, int flags) +{ + int ret = 0; + if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE) + { + Queue q; + + if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER) + { + if (!selection->count) + return 0; + if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0) + { + /* try to drop expensive extra bits */ + flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags); + } + } + queue_init(&q); + ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS); + return selection_combine(pool, selection, &q, flags, ret); + } + queue_empty(selection); + if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed) + return 0; + + /* here come our four selection modes */ + if ((flags & SELECTION_FILELIST) != 0) + ret = selection_filelist(pool, selection, name, flags); + if (!ret && (flags & SELECTION_NAME) != 0) + ret = selection_name_arch_rel(pool, selection, name, flags, 0); + if (!ret && (flags & SELECTION_PROVIDES) != 0) + ret = selection_name_arch_rel(pool, selection, name, flags, 1); + if (!ret && (flags & SELECTION_CANON) != 0) + ret = selection_canon(pool, selection, name, flags); + + /* now do result filtering */ + if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0) + selection_filter_repo(pool, selection, pool->installed, SOLVER_SETREPO); + + /* flatten if requested */ + if (ret && (flags & SELECTION_FLAT) != 0) + selection_flatten(pool, selection); + return selection->count ? ret : 0; +} + +static int +matchdep_str(const char *pattern, const char *string, int flags) +{ + if (!pattern || !string) + return 0; + if (flags & SELECTION_GLOB) + { + int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0; + return fnmatch(pattern, string, globflags) == 0 ? 1 : 0; + } + if (flags & SELECTION_NOCASE) + return strcasecmp(pattern, string) == 0 ? 1 : 0; + return strcmp(pattern, string) == 0 ? 1 : 0; +} + +/* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */ +static int +matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags) +{ + if (ISRELDEP(id)) + { + Reldep *rd = GETRELDEP(pool, id); + if (rd->flags > 7) + { + if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS) + { + if (matchdep(pool, rd->name, rname, rflags, revr, flags)) + return 1; + if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr)) + { + rd = GETRELDEP(pool, rd->evr); + if (rd->flags != REL_ELSE) + return 0; + } + if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags)) + return 1; + return 0; + } + if (rd->flags == REL_ARCH) + return matchdep(pool, rd->name, rname, rflags, revr, flags); + } + if (!matchdep(pool, rd->name, rname, rflags, revr, flags)) + return 0; + if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr)) + return 0; + return 1; + } + return matchdep_str(rname, pool_id2str(pool, id), flags); +} + +struct limiter { + int start; /* either 2 or repofilter->start */ + int end; /* either nsolvables or repofilter->end */ + Repo *repofilter; + Id *mapper; + Queue qlimit; +}; + + +static int +selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq, Id solvid, int flags, int keyname, int marker, struct limiter *limiter) +{ + Map m, missc; + int reloff; + int li, i, j; + Id p; + Queue q; + + if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE) + { + int ret; + Queue q; + queue_init(&q); + ret = selection_make_matchsolvable_common(pool, &q, solvidq, solvid, flags & ~SELECTION_MODEBITS, keyname, marker, limiter); + return selection_combine(pool, selection, &q, flags, ret); + } + + queue_empty(selection); + if (!limiter->end) + return 0; + if (!solvidq && !solvid) + return 0; + if (solvidq && solvid) + return 0; + + if (solvidq) + { + map_init(&m, pool->nsolvables); + for (i = 0; i < solvidq->count; i++) + MAPSET(&m, solvidq->elements[i]); + } + queue_init(&q); + reloff = pool->ss.nstrings; + map_init(&missc, reloff + pool->nrels); + for (li = limiter->start; li < limiter->end; li++) + { + Solvable *s; + p = limiter->mapper ? limiter->mapper[li] : li; + if (solvidq && MAPTST(&m, p)) + continue; + if (!solvidq && p == solvid) + continue; + s = pool->solvables + p; + if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter)) + continue; + if (!solvable_matches_selection_flags(pool, s, flags)) + continue; + if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff)) + queue_push(selection, p); + } + queue_free(&q); + map_free(&missc); + if (solvidq) + map_free(&m); + + /* convert package list to selection */ + if (!selection->count) + return 0; + j = selection->count; + queue_insertn(selection, 0, selection->count, 0); + for (i = 0; i < selection->count; i += 2) + { + selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + selection->elements[i + 1] = selection->elements[j++]; + } + if ((flags & SELECTION_FLAT) != 0) + selection_flatten(pool, selection); + return SELECTION_PROVIDES; +} + +static int +selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter) +{ + int li, i, j; + int ret = 0; + char *rname = 0, *r = 0; + int rflags = 0; + Id revr = 0; + Id p; + Queue q; + + if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE) + { + Queue q; + queue_init(&q); + ret = selection_make_matchdeps_common(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, limiter); + return selection_combine(pool, selection, &q, flags, ret); + } + + queue_empty(selection); + if (!limiter->end) + return 0; + if (!name && !dep) + return 0; + if (name && dep) + return 0; + + if ((flags & SELECTION_MATCH_DEPSTR) != 0) + flags &= ~SELECTION_REL; + + if (name) + { + rname = solv_strdup(name); + if ((flags & SELECTION_REL) != 0) + { + if ((r = strpbrk(rname, "<=>")) != 0) + { + if ((r = splitrel(rname, r, &rflags)) == 0) + { + solv_free(rname); + return 0; + } + } + revr = pool_str2id(pool, r, 1); + ret |= SELECTION_REL; + } + if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0) + flags &= ~SELECTION_GLOB; + + if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0) + { + /* we can use the faster selection_make_matchdepid */ + dep = pool_str2id(pool, rname, 1); + if (rflags) + dep = pool_rel2id(pool, dep, revr, rflags, 1); + rname = solv_free(rname); + name = 0; + } + } + if (dep) + { + if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0) + { + Reldep *rd; + if (!ISRELDEP(dep)) + return 0; + rd = GETRELDEP(pool, dep); + if (!rd->name || rd->flags != REL_EQ) + return 0; + dep = rd->name; + rflags = rd->flags; + revr = rd->evr; + } + } + + queue_init(&q); + for (li = limiter->start; li < limiter->end; li++) + { + Solvable *s; + p = limiter->mapper ? limiter->mapper[li] : li; + s = pool->solvables + p; + if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter)) + continue; + if (!solvable_matches_selection_flags(pool, s, flags)) + continue; + if (keyname == SOLVABLE_NAME) /* nevr match hack */ + { + if (dep) + { + if ((flags & SELECTION_MATCH_DEPSTR) != 0) + { + if (s->name != dep || s->evr != revr) + continue; + } + else + { + if (!pool_match_nevr(pool, s, dep)) + continue; + } + } + else + { + if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */ + { + char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr)); + if (!matchdep_str(rname, tmp, flags)) + continue; + } + else + { + if (!matchdep(pool, s->name, rname, rflags, revr, flags)) + continue; + if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr)) + continue; + } + } + queue_push(selection, p); + continue; + } + if (q.count) + queue_empty(&q); + repo_lookup_deparray(s->repo, p, keyname, &q, marker); + if (!q.count) + continue; + if (dep) + { + if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */ + { + for (i = 0; i < q.count; i++) + if (q.elements[i] == dep) + break; + } + else + { + for (i = 0; i < q.count; i++) + if (pool_match_dep(pool, q.elements[i], dep)) + break; + } + } + else + { + if ((flags & SELECTION_MATCH_DEPSTR) != 0) + { + for (i = 0; i < q.count; i++) + if (matchdep_str(rname, pool_dep2str(pool, q.elements[i]), flags)) + break; + } + else + { + for (i = 0; i < q.count; i++) + if (matchdep(pool, q.elements[i], rname, rflags, revr, flags)) + break; + } + } + if (i < q.count) + queue_push(selection, p); + } + queue_free(&q); + solv_free(rname); + + /* convert package list to selection */ + if (!selection->count) + return 0; + j = selection->count; + queue_insertn(selection, 0, selection->count, 0); + for (i = 0; i < selection->count; i += 2) + { + selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET; + selection->elements[i + 1] = selection->elements[j++]; + } + + if ((flags & SELECTION_FLAT) != 0) + selection_flatten(pool, selection); + return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES); +} + +static void +setup_limiter(Pool *pool, Queue *selection, int flags, struct limiter *limiter) +{ + limiter->start = 2; + limiter->end = pool->nsolvables; + limiter->mapper = 0; + limiter->repofilter = 0; + if ((flags & SELECTION_INSTALLED_ONLY) != 0) + { + Repo *repo = pool->installed; + limiter->repofilter = repo; + limiter->start = repo ? repo->start : 0; + limiter->end = repo ? repo->end : 0; + } + if ((flags & SELECTION_MODEBITS) != SELECTION_SUBTRACT && (flags & SELECTION_MODEBITS) != SELECTION_FILTER) + return; + /* the result will be limited to the first selection */ + if (!selection->count) + limiter->start = limiter->end = 0; + if (!limiter->end) + return; + /* check for special cases where we do not need to call selection_solvables() */ + if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL) + return; + if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO) + { + Repo *repo = pool_id2repo(pool, selection->elements[1]); + if (limiter->repofilter && repo != limiter->repofilter) + repo = 0; + limiter->repofilter = repo; + limiter->start = repo ? repo->start : 0; + limiter->end = repo ? repo->end : 0; + return; + } + /* convert selection into a package list and use it in the limiter */ + queue_init(&limiter->qlimit); + selection_solvables(pool, selection, &limiter->qlimit); + limiter->start = 0; + limiter->end = limiter->qlimit.count; + if (!limiter->qlimit.count) + queue_free(&limiter->qlimit); + else + limiter->mapper = limiter->qlimit.elements; +} + +static void +free_limiter(struct limiter *limiter) +{ + if (limiter->mapper) + queue_free(&limiter->qlimit); +} + +/* + * select against the dependencies in keyname + * like SELECTION_PROVIDES, but with the deps in keyname instead of provides. + * supported match modifiers: + * SELECTION_REL + * SELECTION_GLOB + * SELECTION_NOCASE + */ +int +selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker) +{ + struct limiter limiter; + int ret; + setup_limiter(pool, selection, flags, &limiter); + ret = selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker, &limiter); + free_limiter(&limiter); + return ret; +} + +/* + * select against the dependency id in keyname + */ +int +selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker) +{ + struct limiter limiter; + int ret; + setup_limiter(pool, selection, flags, &limiter); + ret = selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker, &limiter); + free_limiter(&limiter); + return ret; +} + +int +selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker) +{ + struct limiter limiter; + int ret; + setup_limiter(pool, selection, flags, &limiter); + ret = selection_make_matchsolvable_common(pool, selection, 0, solvid, flags, keyname, marker, &limiter); + free_limiter(&limiter); + return ret; +} + +int +selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker) +{ + struct limiter limiter; + int ret; + setup_limiter(pool, selection, flags, &limiter); + ret = selection_make_matchsolvable_common(pool, selection, solvidq, 0, flags, keyname, marker, &limiter); + free_limiter(&limiter); + return ret; +} + +static inline int +pool_is_kind(Pool *pool, Id name, Id kind) +{ + const char *n; + if (!kind) + return 1; + n = pool_id2str(pool, name); + if (kind != 1) + { + const char *kn = pool_id2str(pool, kind); + int knl = strlen(kn); + return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0; + } + else + { + if (*n == ':') + return 1; + while(*n >= 'a' && *n <= 'z') + n++; + return *n == ':' ? 0 : 1; + } +} + +static void +selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags) +{ + int i, j, miss; + Queue q; + Id p, pp; + + queue_init(&q); + for (i = j = 0; i < sel->count; i += 2) + { + Id select = sel->elements[i] & SOLVER_SELECTMASK; + Id id = sel->elements[i + 1]; + if (q.count) + queue_empty(&q); + miss = 0; + if (select == SOLVER_SOLVABLE_ALL) + { + FOR_POOL_SOLVABLES(p) + { + if (map_tst(m, p)) + queue_push(&q, p); + else + miss = 1; + } + } + else if (select == SOLVER_SOLVABLE_REPO) + { + Solvable *s; + Repo *repo = pool_id2repo(pool, id); + if (repo) + { + FOR_REPO_SOLVABLES(repo, p, s) + { + if (map_tst(m, p)) + queue_push(&q, p); + else + miss = 1; + } + } + } + else if (select == SOLVER_SOLVABLE) + { + if (!map_tst(m, id)) + continue; + sel->elements[j] = sel->elements[i] | setflags; + sel->elements[j + 1] = id; + j += 2; + continue; + } + else + { + FOR_JOB_SELECT(p, pp, select, id) + { + if (map_tst(m, p)) + queue_pushunique(&q, p); + else + miss = 1; + } + } + if (!q.count) + continue; + if (!miss) + { + sel->elements[j] = sel->elements[i] | setflags; + sel->elements[j + 1] = id; + } + else if (q.count > 1) + { + sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags; + sel->elements[j + 1] = pool_queuetowhatprovides(pool, &q); + } + else + { + sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags; + sel->elements[j + 1] = q.elements[0]; + } + j += 2; + } + queue_truncate(sel, j); + queue_free(&q); +} + +static void +selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert) +{ + int i, j; + Id p, pp, q1filled = 0; + Queue q1; + Map m2; + Id setflags = 0; + + /* handle special cases */ + if (!sel1->count || !sel2->count) + { + if (invert && !sel2->count) + return; + queue_empty(sel1); + return; + } + if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert) + { + /* XXX: not 100% correct, but very useful */ + setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK); /* job & jobflags */ + queue_free(sel1); + queue_init_clone(sel1, sel2); + for (i = 0; i < sel1->count; i += 2) + sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | setflags; + return; + } + if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert) + { + Repo *repo = pool_id2repo(pool, sel1->elements[1]); + setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_NOAUTOSET); /* job, jobflags, setflags */ + queue_free(sel1); + queue_init_clone(sel1, sel2); + for (i = 0; i < sel1->count; i += 2) + sel1->elements[i] &= SOLVER_SELECTMASK | SOLVER_SETMASK; /* remove job and jobflags */ + selection_filter_repo(pool, sel1, repo, setflags); + return; + } + if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL) + { + if (invert) + queue_empty(sel1); + return; + } + if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert) + { + Repo *repo = pool_id2repo(pool, sel2->elements[1]); + setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET); + selection_filter_repo(pool, sel1, repo, setflags); + return; + } + + /* convert sel2 into a map */ + queue_init(&q1); + map_init(&m2, pool->nsolvables); + for (i = 0; i < sel2->count; i += 2) + { + Id select = sel2->elements[i] & SOLVER_SELECTMASK; + if (select == SOLVER_SOLVABLE_ALL) + { + queue_free(&q1); + map_free(&m2); + if (invert) + queue_empty(sel1); + return; + } + if (select == SOLVER_SOLVABLE_REPO) + { + Solvable *s; + Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]); + if (repo) + { + FOR_REPO_SOLVABLES(repo, p, s) + map_set(&m2, p); + } + } + else + { + if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1])) + { + Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]); + if (rd->flags == REL_ARCH && rd->name == 0) + { + /* special arch filter */ + if (!q1filled++) + selection_solvables(pool, sel1, &q1); + for (j = 0; j < q1.count; j++) + { + Id p = q1.elements[j]; + Solvable *s = pool->solvables + p; + if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC)) + map_set(&m2, p); + } + continue; + } + else if (rd->flags == REL_KIND && rd->name == 0) + { + /* special kind filter */ + if (!q1filled++) + selection_solvables(pool, sel1, &q1); + for (j = 0; j < q1.count; j++) + { + Id p = q1.elements[j]; + Solvable *s = pool->solvables + p; + if (pool_is_kind(pool, s->name, rd->evr)) + map_set(&m2, p); + } + continue; + } + } + FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1]) + map_set(&m2, p); + } + } + queue_free(&q1); + + /* now filter sel1 with the map */ + if (invert) + map_invertall(&m2); + if (sel2->count == 2) + setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET); + selection_filter_map(pool, sel1, &m2, setflags); + map_free(&m2); +} + +void +selection_filter(Pool *pool, Queue *sel1, Queue *sel2) +{ + selection_filter_int(pool, sel1, sel2, 0); +} + +void +selection_add(Pool *pool, Queue *sel1, Queue *sel2) +{ + if (sel2->count) + queue_insertn(sel1, sel1->count, sel2->count, sel2->elements); +} + +void +selection_subtract(Pool *pool, Queue *sel1, Queue *sel2) +{ + selection_filter_int(pool, sel1, sel2, 1); +} + +const char * +pool_selection2str(Pool *pool, Queue *selection, Id flagmask) +{ + char *s; + const char *s2; + int i; + s = pool_tmpjoin(pool, 0, 0, 0); + for (i = 0; i < selection->count; i += 2) + { + Id how = selection->elements[i]; + if (*s) + s = pool_tmpappend(pool, s, " + ", 0); + s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]); + s = pool_tmpappend(pool, s, s2, 0); + pool_freetmpspace(pool, s2); + how &= flagmask & SOLVER_SETMASK; + if (how) + { + int o = strlen(s); + s = pool_tmpappend(pool, s, " ", 0); + if (how & SOLVER_SETEV) + s = pool_tmpappend(pool, s, ",setev", 0); + if (how & SOLVER_SETEVR) + s = pool_tmpappend(pool, s, ",setevr", 0); + if (how & SOLVER_SETARCH) + s = pool_tmpappend(pool, s, ",setarch", 0); + if (how & SOLVER_SETVENDOR) + s = pool_tmpappend(pool, s, ",setvendor", 0); + if (how & SOLVER_SETREPO) + s = pool_tmpappend(pool, s, ",setrepo", 0); + if (how & SOLVER_NOAUTOSET) + s = pool_tmpappend(pool, s, ",noautoset", 0); + if (s[o + 1] != ',') + s = pool_tmpappend(pool, s, ",?", 0); + s[o + 1] = '['; + s = pool_tmpappend(pool, s, "]", 0); + } + } + return s; +} + diff --git a/libsolv-0.7.2/src/selection.h b/libsolv-0.7.2/src/selection.h new file mode 100644 index 0000000..8e60a27 --- /dev/null +++ b/libsolv-0.7.2/src/selection.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * selection.h + * + */ + +#ifndef LIBSOLV_SELECTION_H +#define LIBSOLV_SELECTION_H + +#include "pool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* what to match */ +#define SELECTION_NAME (1 << 0) +#define SELECTION_PROVIDES (1 << 1) +#define SELECTION_FILELIST (1 << 2) +#define SELECTION_CANON (1 << 3) + +/* match extensions */ +#define SELECTION_DOTARCH (1 << 4) /* allow ".arch" suffix */ +#define SELECTION_REL (1 << 5) /* allow "<=> rel" suffix */ + +/* string comparison modifiers */ +#define SELECTION_GLOB (1 << 9) +#define SELECTION_NOCASE (1 << 11) + +/* extra flags */ +#define SELECTION_FLAT (1 << 10) /* flatten the resulting selection */ +#define SELECTION_SKIP_KIND (1 << 14) /* remove kind: name prefix in SELECTION_NAME matches */ +#define SELECTION_MATCH_DEPSTR (1 << 15) /* match dep2str result */ + +/* package selection */ +#define SELECTION_INSTALLED_ONLY (1 << 8) +#define SELECTION_SOURCE_ONLY (1 << 12) +#define SELECTION_WITH_SOURCE (1 << 13) +#define SELECTION_WITH_DISABLED (1 << 16) +#define SELECTION_WITH_BADARCH (1 << 17) +#define SELECTION_WITH_ALL (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH) + +/* result operator */ +#define SELECTION_REPLACE (0 << 28) +#define SELECTION_ADD (1 << 28) +#define SELECTION_SUBTRACT (2 << 28) +#define SELECTION_FILTER (3 << 28) + + +/* extra SELECTION_FILTER bits */ +#define SELECTION_FILTER_KEEP_IFEMPTY (1 << 30) +#define SELECTION_FILTER_SWAPPED (1 << 31) + +/* internal */ +#define SELECTION_MODEBITS (3 << 28) + +extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags); +extern int selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker); +extern int selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker); +extern int selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker); +extern int selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker); + +extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2); +extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2); +extern void selection_subtract(Pool *pool, Queue *sel1, Queue *sel2); + +extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs); + +extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libsolv-0.6.15/src/sha1.c b/libsolv-0.7.2/src/sha1.c similarity index 100% rename from libsolv-0.6.15/src/sha1.c rename to libsolv-0.7.2/src/sha1.c diff --git a/libsolv-0.6.15/src/sha1.h b/libsolv-0.7.2/src/sha1.h similarity index 100% rename from libsolv-0.6.15/src/sha1.h rename to libsolv-0.7.2/src/sha1.h diff --git a/libsolv-0.6.15/src/sha2.c b/libsolv-0.7.2/src/sha2.c similarity index 100% rename from libsolv-0.6.15/src/sha2.c rename to libsolv-0.7.2/src/sha2.c diff --git a/libsolv-0.6.15/src/sha2.h b/libsolv-0.7.2/src/sha2.h similarity index 98% rename from libsolv-0.6.15/src/sha2.h rename to libsolv-0.7.2/src/sha2.h index 220af32..5377360 100644 --- a/libsolv-0.6.15/src/sha2.h +++ b/libsolv-0.7.2/src/sha2.h @@ -51,12 +51,12 @@ * uintXX_t (from inttypes.h), you may need to define things by hand * for your system: */ -typedef struct _SHA256_CTX { +typedef struct s_SHA256_CTX { uint32_t state[8]; uint64_t bitcount; uint32_t buffer[SHA256_BLOCK_LENGTH/4]; } SHA256_CTX; -typedef struct _SHA512_CTX { +typedef struct s_SHA512_CTX { uint64_t state[8]; uint64_t bitcount[2]; uint64_t buffer[SHA512_BLOCK_LENGTH/8]; diff --git a/libsolv-0.6.15/src/solvable.c b/libsolv-0.7.2/src/solvable.c similarity index 65% rename from libsolv-0.6.15/src/solvable.c rename to libsolv-0.7.2/src/solvable.c index cccc89d..331f290 100644 --- a/libsolv-0.6.15/src/solvable.c +++ b/libsolv-0.7.2/src/solvable.c @@ -257,14 +257,14 @@ solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound) return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound); } -unsigned int -solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound) +unsigned long long +solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound) { unsigned long long size; if (!s->repo) return notfound; - size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10); - return (unsigned int)((size + 1023) >> 10); + size = solvable_lookup_num(s, keyname, (unsigned long long)-1); + return size == (unsigned long long)-1 ? notfound : ((size + 1023) >> 10); } int @@ -409,305 +409,12 @@ solvable_lookup_sourcepkg(Solvable *s) /*****************************************************************************/ -static inline Id dep2name(Pool *pool, Id dep) -{ - while (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - dep = rd->name; - } - return dep; -} - -static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) -{ - Id p, pp; - Solvable *sn = pool->solvables + n; - - FOR_PROVIDES(p, pp, sn->name) - { - Solvable *s = pool->solvables + p; - if (s->name != sn->name || s->arch != sn->arch) - continue; - if (!MAPTST(installed, p)) - continue; - if (pool_match_nevr(pool, pool->solvables + p, con)) - continue; - return 1; /* found installed package that doesn't conflict */ - } - return 0; -} - -static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap) -{ - Id p, pp; - FOR_PROVIDES(p, pp, dep) - { - if (p == SYSTEMSOLVABLE) - return -1; - if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) - continue; - if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep)) - if (providedbyinstalled_multiversion(pool, installed, p, dep)) - continue; - if (MAPTST(installed, p)) - return 1; - } - return 0; -} - -/* - * solvable_trivial_installable_map - anwers is a solvable is installable - * without any other installs/deinstalls. - * The packages considered to be installed are provided via the - * installedmap bitmap. A additional "conflictsmap" bitmap providing - * information about the conflicts of the installed packages can be - * used for extra speed up. Provide a NULL pointer if you do not - * have this information. - * Both maps can be created with pool_create_state_maps() or - * solver_create_state_maps(). - * - * returns: - * 1: solvable is installable without any other package changes - * 0: solvable is not installable - * -1: solvable is installable, but doesn't constrain any installed packages - */ -int -solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap) -{ - Pool *pool = s->repo->pool; - Solvable *s2; - Id p, *dp; - Id *reqp, req; - Id *conp, con; - int r, interesting = 0; - - if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables)) - return 0; - if (s->requires) - { - reqp = s->repo->idarraydata + s->requires; - while ((req = *reqp++) != 0) - { - if (req == SOLVABLE_PREREQMARKER) - continue; - r = providedbyinstalled(pool, installedmap, req, 0, 0); - if (!r) - return 0; - if (r > 0) - interesting = 1; - } - } - if (s->conflicts) - { - int ispatch = 0; - - if (!strncmp("patch:", pool_id2str(pool, s->name), 6)) - ispatch = 1; - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap)) - { - if (ispatch && solvable_is_irrelevant_patch(s, installedmap)) - return -1; - return 0; - } - if (!interesting && ISRELDEP(con)) - { - con = dep2name(pool, con); - if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap)) - interesting = 1; - } - } - if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap)) - interesting = 0; - } -#if 0 - if (s->repo) - { - Id *obsp, obs; - Repo *installed = 0; - if (s->obsoletes && s->repo != installed) - { - obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - if (providedbyinstalled(pool, installedmap, obs, 0, 0)) - return 0; - } - } - if (s->repo != installed) - { - Id pp; - FOR_PROVIDES(p, pp, s->name) - { - s2 = pool->solvables + p; - if (s2->repo == installed && s2->name == s->name) - return 0; - } - } - } -#endif - if (!conflictsmap) - { - int i; - - p = s - pool->solvables; - for (i = 1; i < pool->nsolvables; i++) - { - if (!MAPTST(installedmap, i)) - continue; - s2 = pool->solvables + i; - if (!s2->conflicts) - continue; - conp = s2->repo->idarraydata + s2->conflicts; - while ((con = *conp++) != 0) - { - dp = pool_whatprovides_ptr(pool, con); - for (; *dp; dp++) - if (*dp == p) - return 0; - } - } - } - return interesting ? 1 : -1; -} - -/* - * different interface for solvable_trivial_installable_map, where - * the information about the installed packages is provided - * by a queue. - */ -int -solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap) -{ - Pool *pool = s->repo->pool; - int i; - Id p; - Map installedmap; - int r; - - map_init(&installedmap, pool->nsolvables); - for (i = 0; i < installed->count; i++) - { - p = installed->elements[i]; - if (p > 0) /* makes it work with decisionq */ - MAPSET(&installedmap, p); - } - r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap); - map_free(&installedmap); - return r; -} - -/* - * different interface for solvable_trivial_installable_map, where - * the information about the installed packages is provided - * by a repo containing the installed solvables. - */ -int -solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap) -{ - Pool *pool = s->repo->pool; - Id p; - Solvable *s2; - Map installedmap; - int r; - - map_init(&installedmap, pool->nsolvables); - FOR_REPO_SOLVABLES(installed, p, s2) - MAPSET(&installedmap, p); - r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap); - map_free(&installedmap); - return r; -} - -/* FIXME: this mirrors policy_illegal_vendorchange */ -static int -pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2) -{ - Id v1, v2; - Id vendormask1, vendormask2; - - if (pool->custom_vendorcheck) - return pool->custom_vendorcheck(pool, s1, s2); - /* treat a missing vendor as empty string */ - v1 = s1->vendor ? s1->vendor : ID_EMPTY; - v2 = s2->vendor ? s2->vendor : ID_EMPTY; - if (v1 == v2) - return 0; - vendormask1 = pool_vendor2mask(pool, v1); - if (!vendormask1) - return 1; /* can't match */ - vendormask2 = pool_vendor2mask(pool, v2); - if ((vendormask1 & vendormask2) != 0) - return 0; - return 1; /* no class matches */ -} - -/* check if this patch is relevant according to the vendor. To bad that patches - * don't have a vendor, so we need to do some careful repo testing. */ -int -solvable_is_irrelevant_patch(Solvable *s, Map *installedmap) -{ - Pool *pool = s->repo->pool; - Id con, *conp; - int hadpatchpackage = 0; - - if (!s->conflicts) - return 0; - conp = s->repo->idarraydata + s->conflicts; - while ((con = *conp++) != 0) - { - Reldep *rd; - Id p, pp, p2, pp2; - if (!ISRELDEP(con)) - continue; - rd = GETRELDEP(pool, con); - if (rd->flags != REL_LT) - continue; - FOR_PROVIDES(p, pp, con) - { - Solvable *si; - if (!MAPTST(installedmap, p)) - continue; - si = pool->solvables + p; - if (!pool_match_nevr(pool, si, con)) - continue; - FOR_PROVIDES(p2, pp2, rd->name) - { - Solvable *s2 = pool->solvables + p2; - if (!pool_match_nevr(pool, s2, rd->name)) - continue; - if (pool_match_nevr(pool, s2, con)) - continue; /* does not fulfill patch */ - if (s2->repo == s->repo) - { - hadpatchpackage = 1; - /* ok, we have a package from the patch repo that solves the conflict. check vendor */ - if (si->vendor == s2->vendor) - return 0; - if (!pool_illegal_vendorchange(pool, si, s2)) - return 0; - /* vendor change was illegal, ignore conflict */ - } - } - } - } - /* if we didn't find a patchpackage don't claim that the patch is irrelevant */ - if (!hadpatchpackage) - return 0; - return 1; -} - -/*****************************************************************************/ - /* * Create maps containing the state of each solvable. Input is a "installed" queue, * it contains all solvable ids that are considered to be installed. * - * The created maps can be used for solvable_trivial_installable_map(), - * pool_calc_duchanges(), pool_calc_installsizechange(). + * The created maps can be used for * pool_calc_duchanges() and + * pool_calc_installsizechange(). * */ void @@ -894,6 +601,9 @@ solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker) int i; Pool *pool = s->repo->pool; Queue q; + + if (keyname == SOLVABLE_NAME) + return pool_match_nevr(pool, s, dep) ? 1 : 0; /* nevr match hack */ queue_init(&q); solvable_lookup_deparray(s, keyname, &q, marker); for (i = 0; i < q.count; i++) @@ -903,3 +613,67 @@ solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker) queue_free(&q); return i; } + +int +solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff) +{ + Pool *pool = s->repo->pool; + int i, boff; + Id *wp; + + if (depq->count) + queue_empty(depq); + solvable_lookup_deparray(s, keyname, depq, marker); + for (i = 0; i < depq->count; i++) + { + Id dep = depq->elements[i]; + boff = ISRELDEP(dep) ? reloff + GETRELID(dep) : dep; + if (MAPTST(missc, boff)) + continue; + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (!ISRELDEP(rd->name) && rd->flags < 8) + { + /* do pre-filtering on the base */ + if (MAPTST(missc, rd->name)) + continue; + wp = pool_whatprovides_ptr(pool, rd->name); + if (solvidmap) + { + for (; *wp; wp++) + if (MAPTST(solvidmap, *wp)) + break; + } + else + { + for (; *wp; wp++) + if (*wp == solvid) + break; + } + if (!*wp) + { + /* the base does not include solvid, no need to check the complete dep */ + MAPSET(missc, rd->name); + MAPSET(missc, boff); + continue; + } + } + } + wp = pool_whatprovides_ptr(pool, dep); + if (solvidmap) + { + for (; *wp; wp++) + if (MAPTST(solvidmap, *wp)) + return 1; + } + else + { + for (; *wp; wp++) + if (*wp == solvid) + return 1; + } + MAPSET(missc, boff); + } + return 0; +} diff --git a/libsolv-0.6.15/src/solvable.h b/libsolv-0.7.2/src/solvable.h similarity index 78% rename from libsolv-0.6.15/src/solvable.h rename to libsolv-0.7.2/src/solvable.h index 85d20c4..bf92a00 100644 --- a/libsolv-0.6.15/src/solvable.h +++ b/libsolv-0.7.2/src/solvable.h @@ -17,20 +17,21 @@ #include "pooltypes.h" #include "queue.h" +#include "bitmap.h" #ifdef __cplusplus extern "C" { #endif -struct _Repo; +struct s_Repo; -typedef struct _Solvable { +typedef struct s_Solvable { Id name; Id arch; Id evr; /* epoch:version-release */ Id vendor; - struct _Repo *repo; /* repo we belong to */ + struct s_Repo *repo; /* repo we belong to */ /* dependencies are offsets into repo->idarraydata */ Offset provides; /* terminated with Id 0 */ @@ -50,7 +51,7 @@ typedef struct _Solvable { Id solvable_lookup_type(Solvable *s, Id keyname); Id solvable_lookup_id(Solvable *s, Id keyname); unsigned long long solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound); -unsigned int solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound); +unsigned long long solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound); const char *solvable_lookup_str(Solvable *s, Id keyname); const char *solvable_lookup_str_poollang(Solvable *s, Id keyname); const char *solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase); @@ -78,8 +79,19 @@ void solvable_unset(Solvable *s, Id keyname); int solvable_identical(Solvable *s1, Solvable *s2); Id solvable_selfprovidedep(Solvable *s); + int solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker); +/* internal */ +int solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff); + + +/* weird suse stuff */ +int solvable_is_irrelevant_patch(Solvable *s, Map *installedmap); +int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap); +int solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap); +int solvable_trivial_installable_repo(Solvable *s, struct s_Repo *installed, Map *multiversionmap); + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/solver.c b/libsolv-0.7.2/src/solver.c similarity index 68% rename from libsolv-0.6.15/src/solver.c rename to libsolv-0.7.2/src/solver.c index 2e28b7d..57fa3e4 100644 --- a/libsolv-0.6.15/src/solver.c +++ b/libsolv-0.7.2/src/solver.c @@ -31,243 +31,6 @@ #define RULES_BLOCK 63 -/******************************************************************** - * - * dependency check helpers - * - */ - -/*------------------------------------------------------------------- - * handle split provides - * - * a splitprovides dep looks like - * namespace:splitprovides(pkg REL_WITH path) - * and is only true if pkg is installed and contains the specified path. - * we also make sure that pkg is selected for an update, otherwise the - * update would always be forced onto the user. - * Map m is the map used when called from dep_possible. - */ - -static int -solver_is_updating(Solver *solv, Id p) -{ - /* check if the update rule is true */ - Pool *pool = solv->pool; - Rule *r; - Id l, pp; - if (solv->decisionmap[p] >= 0) - return 0; /* old package stayed */ - r = solv->rules + solv->updaterules + (p - solv->installed->start); - FOR_RULELITERALS(l, pp, r) - if (l > 0 && l != p && solv->decisionmap[l] > 0) - return 1; - return 0; -} - -int -solver_splitprovides(Solver *solv, Id dep, Map *m) -{ - Pool *pool = solv->pool; - Id p, pp; - Reldep *rd; - Solvable *s; - - if (!solv->dosplitprovides || !solv->installed) - return 0; - if (!ISRELDEP(dep)) - return 0; - rd = GETRELDEP(pool, dep); - if (rd->flags != REL_WITH) - return 0; - /* - * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in - * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete - * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag - * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but - * we filter the package name further down anyway). - */ - if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr]) - pp = pool_searchlazywhatprovidesq(pool, rd->evr); - else - pp = pool_whatprovides(pool, dep); - while ((p = pool->whatprovidesdata[pp++]) != 0) - { - /* here we have packages that provide the correct name and contain the path, - * now do extra filtering */ - s = pool->solvables + p; - if (s->repo != solv->installed || s->name != rd->name) - continue; - /* check if the package is updated. if m is set, we're called from dep_possible */ - if (m || solver_is_updating(solv, p)) - return 1; - } - return 0; -} - - -/* mirrors solver_dep_fulfilled, but returns 2 if a new package - * was involved */ -static int -solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep) -{ - Pool *pool = solv->pool; - Id p, pp; - int r; - - if (ISRELDEP(dep)) - { - Reldep *rd = GETRELDEP(pool, dep); - if (rd->flags == REL_COND) - { - int r1, r2; - if (ISRELDEP(rd->evr)) - { - Reldep *rd2 = GETRELDEP(pool, rd->evr); - if (rd2->flags == REL_ELSE) - { - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name); - if (r1) - { - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - return r2 && r1 == 2 ? 2 : r2; - } - return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr); - } - } - r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r1 && !r2) - return 0; - return r1 == 2 ? 2 : 1; - } - if (rd->flags == REL_AND) - { - int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - if (!r1) - return 0; - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r2) - return 0; - return r1 == 2 || r2 == 2 ? 2 : 1; - } - if (rd->flags == REL_OR) - { - int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name); - r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr); - if (!r1 && !r2) - return 0; - return r1 == 2 || r2 == 2 ? 2 : 1; - } - if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) - return solver_splitprovides(solv, rd->evr, 0); - if (rd->flags == REL_NAMESPACE && solv->installsuppdepq) - { - Queue *q = solv->installsuppdepq; - int i; - for (i = 0; i < q->count; i++) - if (q->elements[i] == dep || q->elements[i] == rd->name) - return 2; - } - } - r = 0; - FOR_PROVIDES(p, pp, dep) - if (solv->decisionmap[p] > 0) - { - Solvable *s = pool->solvables + p; - if (s->repo && s->repo != solv->installed) - return 2; - r = 1; - } - return r; -} - -static int -solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s) -{ - Id sup, *supp; - supp = s->repo->idarraydata + s->supplements; - while ((sup = *supp++) != 0) - if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2) - return 1; - return 0; -} - -static Id -autouninstall(Solver *solv, Id *problem) -{ - Pool *pool = solv->pool; - int i; - int lastfeature = 0, lastupdate = 0; - Id v; - Id extraflags = -1; - Map *m = 0; - - if (!solv->allowuninstall && !solv->allowuninstall_all) - { - if (!solv->allowuninstallmap.size) - return 0; /* why did we get called? */ - m = &solv->allowuninstallmap; - } - for (i = 0; (v = problem[i]) != 0; i++) - { - if (v < 0) - extraflags &= solv->job.elements[-v - 1]; - if (v >= solv->updaterules && v < solv->updaterules_end) - { - Rule *r; - if (m && !MAPTST(m, v - solv->updaterules)) - continue; - /* check if identical to feature rule, we don't like that (except for orphans) */ - r = solv->rules + solv->featurerules + (v - solv->updaterules); - if (!r->p) - { - /* update rule == feature rule */ - if (v > lastfeature) - lastfeature = v; - /* prefer orphaned packages in dup mode */ - if (solv->keep_orphans) - { - r = solv->rules + v; - if (!r->d && r->p == (solv->installed->start + (v - solv->updaterules))) - { - lastfeature = v; - lastupdate = 0; - break; - } - } - continue; - } - if (v > lastupdate) - lastupdate = v; - } - } - if (!lastupdate && !lastfeature) - return 0; - v = lastupdate ? lastupdate : lastfeature; - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling "); - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v); - solver_disableproblem(solv, v); - if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size) - { - /* add the package to the updatepkgs list, this will automatically turn - * on cleandeps mode */ - Id p = solv->rules[v].p; - if (!solv->cleandeps_updatepkgs) - { - solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue)); - queue_init(solv->cleandeps_updatepkgs); - } - if (p > 0) - { - int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count; - queue_pushunique(solv->cleandeps_updatepkgs, p); - if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt) - solver_disablepolicyrules(solv); - } - } - return v; -} - /************************************************************************/ /* @@ -325,22 +88,24 @@ enabledisablelearntrules(Solver *solv) * If we find a conflict, disable rules and add them to problem queue. */ -static void -makeruledecisions(Solver *solv) +static int +makeruledecisions(Solver *solv, int disablerules) { Pool *pool = solv->pool; - int i, ri, ii; + int i, ri, ii, ori; Rule *r, *rr; Id v, vv; int decisionstart; int record_proof = 1; int oldproblemcount; int havedisabled = 0; + int doautouninstall; /* The system solvable is always installed first */ assert(solv->decisionq.count == 0); queue_push(&solv->decisionq, SYSTEMSOLVABLE); queue_push(&solv->decisionq_why, 0); + queue_push2(&solv->decisionq_reason, 0, 0); solv->decisionmap[SYSTEMSOLVABLE] = 1; /* installed at level '1' */ decisionstart = solv->decisionq.count; @@ -382,7 +147,7 @@ makeruledecisions(Solver *solv) if (!solv->decisionmap[vv]) /* if not yet decided */ { queue_push(&solv->decisionq, v); - queue_push(&solv->decisionq_why, r - solv->rules); + queue_push(&solv->decisionq_why, ri); solv->decisionmap[vv] = v > 0 ? 1 : -1; IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) { @@ -414,11 +179,14 @@ makeruledecisions(Solver *solv) /* conflict with a learnt rule */ /* can happen when packages cannot be installed for multiple reasons. */ /* we disable the learnt rule in this case */ - /* (XXX: we should really call analyze_unsolvable_rule here!) */ + /* (XXX: we should really do something like analyze_unsolvable_rule here!) */ solver_disablerule(solv, r); continue; } + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n"); + assert(ri >= solv->pkgrules_end); /* must not have a conflict in the pkg rules! */ + /* * find the decision which is the "opposite" of the rule */ @@ -426,134 +194,94 @@ makeruledecisions(Solver *solv) if (solv->decisionq.elements[i] == -v) break; assert(i < solv->decisionq.count); /* assert that we found it */ - oldproblemcount = solv->problems.count; - - /* - * conflict with system solvable ? - */ if (v == -SYSTEMSOLVABLE) + ori = 0; + else { - if (record_proof) - { - queue_push(&solv->problems, solv->learnt_pool.count); - queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, 0); - } - else - queue_push(&solv->problems, 0); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri); - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - queue_push(&solv->problems, v); - queue_push(&solv->problems, 0); - if (v >= solv->featurerules && v < solv->updaterules_end) - { - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } - } - solver_disableproblem(solv, v); - havedisabled = 1; - break; /* start over */ + ori = solv->decisionq_why.elements[i]; /* the conflicting rule */ + assert(ori > 0); } - assert(solv->decisionq_why.elements[i] > 0); - /* - * conflict with a pkg rule ? - */ - if (solv->decisionq_why.elements[i] < solv->pkgrules_end) + * record the problem + */ + doautouninstall = 0; + oldproblemcount = solv->problems.count; + queue_push(&solv->problems, 0); /* start problem */ + if (ori < solv->pkgrules_end) { - if (record_proof) + /* easy: conflict with system solvable or pkg rule */ + assert(v > 0 || v == -SYSTEMSOLVABLE); + IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE) { - queue_push(&solv->problems, solv->learnt_pool.count); - queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); - queue_push(&solv->learnt_pool, 0); + if (ori) + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri); + else + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri); + if (ori) + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ori); } - else - queue_push(&solv->problems, 0); - assert(v > 0 || v == -SYSTEMSOLVABLE); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri); - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - queue_push(&solv->problems, v); - queue_push(&solv->problems, 0); - if (v >= solv->featurerules && v < solv->updaterules_end) + solver_recordproblem(solv, ri); + if (ri >= solv->featurerules && ri < solv->updaterules_end) + doautouninstall = 1; + } + else + { + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv); + /* + * push all of our rules (can only be feature or job rules) + * asserting this literal on the problem stack + */ + for (i = solv->pkgrules_end, rr = solv->rules + i; i < solv->learntrules; i++, rr++) { - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } + if (rr->d < 0 /* disabled */ + || rr->w2) /* or no assertion */ + continue; + if (rr->p != vv /* not affecting the literal */ + && rr->p != -vv) + continue; + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ + continue; + + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i); + solver_recordproblem(solv, i); + if (i >= solv->featurerules && i < solv->updaterules_end) + doautouninstall = 1; } - solver_disableproblem(solv, v); - havedisabled = 1; - break; /* start over */ } + queue_push(&solv->problems, 0); /* finish problem */ - /* - * conflict with another job or update/feature rule - */ + /* try autouninstall if requested */ + if (doautouninstall) + { + if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) + if (solver_autouninstall(solv, oldproblemcount) != 0) + { + solv->problems.count = oldproblemcount; + havedisabled = 1; + break; /* start over */ + } + } - /* record proof */ + /* record the proof if requested */ if (record_proof) { - queue_push(&solv->problems, solv->learnt_pool.count); + solv->problems.elements[oldproblemcount] = solv->learnt_pool.count; queue_push(&solv->learnt_pool, ri); - queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]); + if (ori) + queue_push(&solv->learnt_pool, ori); queue_push(&solv->learnt_pool, 0); } - else - queue_push(&solv->problems, 0); - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv); - - /* - * push all of our rules (can only be feature or job rules) - * asserting this literal on the problem stack - */ - for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++) + if (!disablerules) { - if (rr->d < 0 /* disabled */ - || rr->w2) /* or no assertion */ - continue; - if (rr->p != vv /* not affecting the literal */ - && rr->p != -vv) - continue; - if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */ - continue; - - POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i); - solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i); - - v = i; - if (i >= solv->jobrules && i < solv->jobrules_end) - v = -(solv->ruletojob.elements[i - solv->jobrules] + 1); - queue_push(&solv->problems, v); + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n"); + return -1; } - queue_push(&solv->problems, 0); - - if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) - { - solv->problems.count = oldproblemcount; - havedisabled = 1; - break; /* start over */ - } - - for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) - solver_disableproblem(solv, solv->problems.elements[i]); + /* disable all problem rules */ + solver_disableproblemset(solv, oldproblemcount); havedisabled = 1; break; /* start over */ } @@ -598,21 +326,15 @@ makeruledecisions(Solver *solv) continue; POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling "); - solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r); - - if (ri >= solv->jobrules && ri < solv->jobrules_end) - v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1); - else - v = ri; - solver_disableproblem(solv, v); - if (v < 0) - solver_reenablepolicyrules(solv, -v); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r); + solver_fixproblem(solv, ri); havedisabled = 1; break; /* start over */ } if (ii == solv->ruleassertions.count) break; /* finished! */ } + return 1; /* the new level */ } @@ -907,18 +629,7 @@ revert(Solver *solv, int level) solv->branches.count -= solv->branches.elements[solv->branches.count - 2]; if (solv->recommends_index > solv->decisionq.count) solv->recommends_index = -1; /* rebuild recommends/suggests maps */ - if (solv->decisionq.count < solv->decisioncnt_jobs) - solv->decisioncnt_jobs = 0; - if (solv->decisionq.count < solv->decisioncnt_update) - solv->decisioncnt_update = 0; - if (solv->decisionq.count < solv->decisioncnt_keep) - solv->decisioncnt_keep = 0; - if (solv->decisionq.count < solv->decisioncnt_resolve) - solv->decisioncnt_resolve = 0; - if (solv->decisionq.count < solv->decisioncnt_weak) - solv->decisioncnt_weak= 0; - if (solv->decisionq.count < solv->decisioncnt_orphan) - solv->decisioncnt_orphan = 0; + solv->decisionq_reason.count = level + 1; } /*------------------------------------------------------------------- @@ -1111,15 +822,44 @@ solver_reset(Solver *solv) } queue_empty(&solv->decisionq_why); queue_empty(&solv->decisionq); + queue_empty(&solv->decisionq_reason); solv->recommends_index = -1; solv->propagate_index = 0; - solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; queue_empty(&solv->branches); /* adapt learnt rule status to new set of enabled/disabled rules */ enabledisablelearntrules(solv); } +static inline int +queue_contains(Queue *q, Id id) +{ + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == id) + return 1; + return 0; +} + +static void +disable_recommendsrules(Solver *solv, Queue *weakq) +{ + Pool *pool = solv->pool; + int i; + for (i = 0; i < weakq->count; i++) + { + Rule *r; + if (!queue_contains(solv->recommendsruleq, weakq->elements[i])) + continue; + r = solv->rules + weakq->elements[i]; + if (r->d >= 0) + { + POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling "); + solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r); + solver_disablerule(solv, r); + } + } +} /*------------------------------------------------------------------- * @@ -1129,7 +869,7 @@ solver_reset(Solver *solv) */ static void -analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) +analyze_unsolvable_rule(Solver *solv, Rule *r, Queue *weakq, Map *rseen) { Pool *pool = solv->pool; int i; @@ -1144,42 +884,14 @@ analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen) MAPSET(rseen, why - solv->learntrules); for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++) if (solv->learnt_pool.elements[i] > 0) - analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen); + analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], weakq, rseen); return; } - if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why)) - if (!*lastweakp || why > *lastweakp) - *lastweakp = why; - /* do not add pkg rules to problem */ - if (why < solv->pkgrules_end) - return; - /* turn rule into problem */ - if (why >= solv->jobrules && why < solv->jobrules_end) - why = -(solv->ruletojob.elements[why - solv->jobrules] + 1); - /* normalize dup/infarch rules */ - if (why > solv->infarchrules && why < solv->infarchrules_end) - { - Id name = pool->solvables[-solv->rules[why].p].name; - while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name) - why--; - } - if (why > solv->duprules && why < solv->duprules_end) - { - Id name = pool->solvables[-solv->rules[why].p].name; - while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name) - why--; - } - - /* return if problem already countains our rule */ - if (solv->problems.count) - { - for (i = solv->problems.count - 1; i >= 0; i--) - if (solv->problems.elements[i] == 0) /* end of last problem reached? */ - break; - else if (solv->problems.elements[i] == why) - return; - } - queue_push(&solv->problems, why); + if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why) && weakq) + queue_push(weakq, why); + /* add non-pkg rules to problem and disable */ + if (why >= solv->pkgrules_end) + solver_recordproblem(solv, why); } @@ -1210,12 +922,12 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) Rule *r; Map involved; /* global to speed things up? */ Map rseen; + Queue weakq; Id pp, v, vv, why; int i, idx; Id *decisionmap = solv->decisionmap; int oldproblemcount; int oldlearntpoolcount; - Id lastweak; int record_proof = 1; POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n"); @@ -1231,10 +943,10 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) r = cr; map_init(&involved, pool->nsolvables); map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0); + queue_init(&weakq); if (record_proof) queue_push(&solv->learnt_pool, r - solv->rules); - lastweak = 0; - analyze_unsolvable_rule(solv, r, &lastweak, &rseen); + analyze_unsolvable_rule(solv, r, &weakq, &rseen); FOR_RULELITERALS(v, pp, r) { if (DECISIONMAP_TRUE(v)) /* the one true literal */ @@ -1254,7 +966,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) if (record_proof) queue_push(&solv->learnt_pool, why); r = solv->rules + why; - analyze_unsolvable_rule(solv, r, &lastweak, &rseen); + analyze_unsolvable_rule(solv, r, &weakq, &rseen); FOR_RULELITERALS(v, pp, r) { if (DECISIONMAP_TRUE(v)) /* the one true literal */ @@ -1267,28 +979,37 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) map_free(&rseen); queue_push(&solv->problems, 0); /* mark end of this problem */ - if (lastweak) + if (weakq.count) { - /* disable last weak rule */ + Id lastweak; + /* revert problems */ solv->problems.count = oldproblemcount; solv->learnt_pool.count = oldlearntpoolcount; - if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end) - v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1); - else - v = lastweak; + /* find last weak */ + lastweak = 0; + for (i = 0; i < weakq.count; i++) + if (weakq.elements[i] > lastweak) + lastweak = weakq.elements[i]; + if (lastweak < solv->pkgrules_end && solv->strongrecommends && solv->recommendsruleq && queue_contains(solv->recommendsruleq, lastweak)) + { + disable_recommendsrules(solv, &weakq); + queue_free(&weakq); + solver_reset(solv); + return 0; + } + queue_free(&weakq); POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling "); solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak); if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end) solver_disablechoicerules(solv, solv->rules + lastweak); - solver_disableproblem(solv, v); - if (v < 0) - solver_reenablepolicyrules(solv, -v); + solver_fixproblem(solv, lastweak); solver_reset(solv); return 0; } + queue_free(&weakq); if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size) - if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0) + if (solver_autouninstall(solv, oldproblemcount) != 0) { solv->problems.count = oldproblemcount; solv->learnt_pool.count = oldlearntpoolcount; @@ -1306,8 +1027,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) /* + 2: index + trailing zero */ if (disablerules && oldproblemcount + 2 < solv->problems.count) { - for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++) - solver_disableproblem(solv, solv->problems.elements[i]); + solver_disableproblemset(solv, oldproblemcount); /* XXX: might want to enable all weak rules again */ solver_reset(solv); return 0; @@ -1334,7 +1054,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules) */ static int -setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid) +setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Rule *r, *lr; @@ -1348,6 +1068,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul solv->decisionmap[-decision] = -level; queue_push(&solv->decisionq, decision); queue_push(&solv->decisionq_why, -ruleid); /* <= 0 -> free decision */ + queue_push(&solv->decisionq_reason, reason); } assert(ruleid >= 0 && level > 0); for (;;) @@ -1376,7 +1097,7 @@ setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id rul } static void -reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq) +reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq) { Pool *pool = solv->pool; int i, j, haveone = 0, dqcount = dq->count; @@ -1432,6 +1153,8 @@ reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq) solv->recommends_index = -1; queue_truncate(&solv->decisionq, decisionqcount); } + /* but obey favored maps */ + policy_prefer_favored(solv, dq); } /*------------------------------------------------------------------- @@ -1462,7 +1185,7 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) { Pool *pool = solv->pool; int level; - Id p, why; + Id p, why, reason; #if 0 { int i; @@ -1482,7 +1205,8 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) /* hack: revert simply sets the count, so we can still access the reverted elements */ why = -solv->decisionq_why.elements[solv->decisionq_why.count]; assert(why >= 0); - return setpropagatelearn(solv, level, p, disablerules, why); + reason = solv->decisionq_reason.elements[level + 1]; + return setpropagatelearn(solv, level, p, disablerules, why, reason); } /*------------------------------------------------------------------- @@ -1497,23 +1221,23 @@ takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules) */ static int -selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid) +selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid, Id reason) { Pool *pool = solv->pool; Id p; if (dq->count > 1) policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); - /* if we're resolving job rules and didn't resolve the installed packages yet, + /* if we're resolving rules and didn't resolve the installed packages yet, * do some special supplements ordering */ - if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed) - reorder_dq_for_jobrules(solv, level, dq); + if (dq->count > 1 && solv->do_extra_reordering) + reorder_dq_for_future_installed(solv, level, dq); /* if we have multiple candidates we open a branch */ if (dq->count > 1) createbranch(solv, level, dq, 0, ruleid); p = dq->elements[0]; POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p)); - return setpropagatelearn(solv, level, p, disablerules, ruleid); + return setpropagatelearn(solv, level, p, disablerules, ruleid, reason); } @@ -1554,6 +1278,7 @@ solver_create(Pool *pool) queue_init(&solv->ruletojob); queue_init(&solv->decisionq); queue_init(&solv->decisionq_why); + queue_init(&solv->decisionq_reason); queue_init(&solv->problems); queue_init(&solv->orphaned); queue_init(&solv->learnt_why); @@ -1579,80 +1304,6 @@ solver_create(Pool *pool) } -static int -resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) -{ - Pool *pool = solv->pool; - int oldlevel = level; - int i, olevel; - Rule *r; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); - if (!solv->decisioncnt_jobs) - solv->decisioncnt_jobs = solv->decisionq.count; - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) - { - Id l, pp; - if (r->d < 0) /* ignore disabled rules */ - continue; - queue_empty(dq); - FOR_RULELITERALS(l, pp, r) - { - if (l < 0) - { - if (solv->decisionmap[-l] <= 0) - break; - } - else - { - if (solv->decisionmap[l] > 0) - break; - if (solv->decisionmap[l] == 0) - queue_push(dq, l); - } - } - if (l || !dq->count) - continue; - /* prune to installed if not updating */ - if (dq->count > 1 && solv->installed && !solv->updatemap_all && - !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) - { - int j, k; - for (j = k = 0; j < dq->count; j++) - { - Solvable *s = pool->solvables + dq->elements[j]; - if (s->repo == solv->installed) - { - dq->elements[k++] = dq->elements[j]; - if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) - { - k = 0; /* package wants to be updated, do not prune */ - break; - } - } - } - if (k) - dq->count = k; - } - olevel = level; - level = selectandinstall(solv, level, dq, disablerules, i); - if (level <= olevel) - { - if (level == olevel) - { - i--; - r--; - continue; /* try something else */ - } - if (level < oldlevel) - return level; - /* redo from start of jobrules */ - i = solv->jobrules - 1; - r = solv->rules + i; - } - } - return level; -} /*------------------------------------------------------------------- * @@ -1685,6 +1336,7 @@ solver_free(Solver *solv) queue_free(&solv->ruletojob); queue_free(&solv->decisionq); queue_free(&solv->decisionq_why); + queue_free(&solv->decisionq_reason); queue_free(&solv->learnt_why); queue_free(&solv->learnt_pool); queue_free(&solv->problems); @@ -1701,6 +1353,8 @@ solver_free(Solver *solv) queuep_free(&solv->recommendscplxq); queuep_free(&solv->suggestscplxq); queuep_free(&solv->brokenorphanrules); + queuep_free(&solv->favorq); + queuep_free(&solv->recommendsruleq); map_free(&solv->recommendsmap); map_free(&solv->suggestsmap); @@ -1716,6 +1370,8 @@ solver_free(Solver *solv) map_free(&solv->droporphanedmap); map_free(&solv->cleandepsmap); map_free(&solv->allowuninstallmap); + map_free(&solv->favormap); + map_free(&solv->isdisfavormap); solv_free(solv->decisionmap); solv_free(solv->rules); @@ -1775,10 +1431,20 @@ solver_get_flag(Solver *solv, int flag) return solv->break_orphans; case SOLVER_FLAG_FOCUS_INSTALLED: return solv->focus_installed; + case SOLVER_FLAG_FOCUS_BEST: + return solv->focus_best; case SOLVER_FLAG_YUM_OBSOLETES: return solv->do_yum_obsoletes; case SOLVER_FLAG_NEED_UPDATEPROVIDE: return solv->needupdateprovide; + case SOLVER_FLAG_URPM_REORDER: + return solv->urpmreorder; + case SOLVER_FLAG_STRONG_RECOMMENDS: + return solv->strongrecommends; + case SOLVER_FLAG_INSTALL_ALSO_UPDATES: + return solv->install_also_updates; + case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED: + return solv->only_namespace_recommended; default: break; } @@ -1851,12 +1517,27 @@ solver_set_flag(Solver *solv, int flag, int value) case SOLVER_FLAG_FOCUS_INSTALLED: solv->focus_installed = value; break; + case SOLVER_FLAG_FOCUS_BEST: + solv->focus_best = value; + break; case SOLVER_FLAG_YUM_OBSOLETES: solv->do_yum_obsoletes = value; break; case SOLVER_FLAG_NEED_UPDATEPROVIDE: solv->needupdateprovide = value; break; + case SOLVER_FLAG_URPM_REORDER: + solv->urpmreorder = value; + break; + case SOLVER_FLAG_STRONG_RECOMMENDS: + solv->strongrecommends = value; + break; + case SOLVER_FLAG_INSTALL_ALSO_UPDATES: + solv->install_also_updates = value; + break; + case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED: + solv->only_namespace_recommended = value; + break; default: break; } @@ -1864,53 +1545,78 @@ solver_set_flag(Solver *solv, int flag, int value) } static int -cleandeps_check_mistakes(Solver *solv) +resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq) { Pool *pool = solv->pool; + int oldlevel = level; + int i, olevel; Rule *r; - Id p, pp; - int i; - int mademistake = 0; - if (!solv->cleandepsmap.size) - return 0; - /* check for mistakes */ - for (i = solv->installed->start; i < solv->installed->end; i++) + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n"); + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) { - if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start)) - continue; - r = solv->rules + solv->featurerules + (i - solv->installed->start); - /* a mistake is when the featurerule is true but the updaterule is false */ - if (!r->p) + Id l, pp; + if (r->d < 0) /* ignore disabled rules */ continue; - FOR_RULELITERALS(p, pp, r) - if (p > 0 && solv->decisionmap[p] > 0) - break; - if (!p) - continue; /* feature rule is not true */ - r = solv->rules + solv->updaterules + (i - solv->installed->start); - if (!r->p) + queue_empty(dq); + FOR_RULELITERALS(l, pp, r) + { + if (l < 0) + { + if (solv->decisionmap[-l] <= 0) + break; + } + else + { + if (solv->decisionmap[l] > 0) + break; + if (solv->decisionmap[l] == 0) + queue_push(dq, l); + } + } + if (l || !dq->count) continue; - FOR_RULELITERALS(p, pp, r) - if (p > 0 && solv->decisionmap[p] > 0) - break; - if (p) - continue; /* update rule is true */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: "); - solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r); - POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: "); - solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start)); - if (!solv->cleandeps_mistakes) + /* prune to installed if not updating */ + if (dq->count > 1 && solv->installed && !solv->updatemap_all && + !solv->install_also_updates && + !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE)) { - solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue)); - queue_init(solv->cleandeps_mistakes); + int j = dq->count, k; + if (solv->updatemap.size) + { + /* do not prune if an installed package wants to be updated */ + for (j = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == solv->installed + && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start)) + break; + } + if (j == dq->count) + { + for (j = k = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == solv->installed) + dq->elements[k++] = dq->elements[j]; + if (k) + dq->count = k; + } + } + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB); + if (level <= olevel) + { + if (level == olevel) + { + i--; + r--; + continue; /* try something else */ + } + if (level < oldlevel) + return level; + /* redo from start of jobrules */ + i = solv->jobrules - 1; + r = solv->rules + i; } - queue_push(solv->cleandeps_mistakes, i); - MAPCLR(&solv->cleandepsmap, i - solv->installed->start); - solver_reenablepolicyrules_cleandeps(solv, i); - mademistake = 1; } - return mademistake; + return level; } static void @@ -1931,6 +1637,291 @@ prune_to_update_targets(Solver *solv, Id *cp, Queue *q) queue_truncate(q, j); } +static int +resolve_installed(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int i, n, pass; + int installedpos = solv->installedpos; + Solvable *s; + Id p, pp; + int olevel, origlevel = level; + + POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); + if (!installedpos) + installedpos = installed->start; + /* we use two passes if we need to update packages + * to create a better user experience */ + for (pass = solv->updatemap.size ? 0 : 1; pass < 2; ) + { + int passlevel = level; + Id *specialupdaters = solv->specialupdaters; + /* start with installedpos, the position that gave us problems the last time */ + for (i = installedpos, n = installed->start; n < installed->end; i++, n++) + { + Rule *r, *rr; + Id d; + + if (i == installed->end) + i = installed->start; + s = pool->solvables + i; + if (s->repo != installed) + continue; + + if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) + continue; /* already decided */ + if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) + continue; /* updates first */ + r = solv->rules + solv->updaterules + (i - installed->start); + rr = r; + if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ + rr -= solv->installed->end - solv->installed->start; + if (!rr->p) /* identical to update rule? */ + rr = r; + if (!rr->p) + continue; /* orpaned package or pseudo package */ + + /* check if we should update this package to the latest version + * noupdate is set for erase jobs, in that case we want to deinstall + * the installed package and not replace it with a newer version + * rr->p != i is for dup jobs where the installed package cannot be kept */ + if (dq->count) + queue_empty(dq); + if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) + { + if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) + { + /* special multiversion handling, make sure best version is chosen */ + if (rr->p == i && solv->decisionmap[i] >= 0) + queue_push(dq, i); + while ((p = pool->whatprovidesdata[d++]) != 0) + if (solv->decisionmap[p] >= 0) + queue_push(dq, p); + if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start]) + prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq); + if (dq->count) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + p = dq->elements[0]; + if (p != i && solv->decisionmap[p] == 0) + { + rr = solv->rules + solv->featurerules + (i - solv->installed->start); + if (!rr->p) /* update rule == feature rule? */ + rr = rr - solv->featurerules + solv->updaterules; + dq->count = 1; + } + else + dq->count = 0; + } + } + else + { + /* update to best package of the update rule */ + FOR_RULELITERALS(p, pp, rr) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; /* already fulfilled */ + break; + } + if (!solv->decisionmap[p]) + queue_push(dq, p); + } + } + } + if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start]) + prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq); + /* install best version */ + if (dq->count) + { + olevel = level; + level = selectandinstall(solv, level, dq, disablerules, rr - solv->rules, SOLVER_REASON_UPDATE_INSTALLED); + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; + } + } + /* if still undecided keep package */ + if (solv->decisionmap[i] == 0) + { + olevel = level; + if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) + { +#if 0 + POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, -i, disablerules, 0, SOLVER_REASON_CLEANDEPS_ERASE); +#else + continue; +#endif + } + else + { + POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); + level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules, SOLVER_REASON_KEEP_INSTALLED); + } + if (level <= olevel) + { + if (level < passlevel) + break; /* trouble */ + if (level < olevel) + n = installed->start; /* redo all */ + i--; + n--; + continue; /* retry with learnt rule */ + } + } + } + if (n < installed->end) + { + installedpos = i; /* retry problem solvable next time */ + if (level < origlevel) + break; /* ran into trouble */ + /* re-run all passes */ + pass = solv->updatemap.size ? 0 : 1; + continue; + } + /* reset installedpos, advance to next pass */ + installedpos = installed->start; + pass++; + } + solv->installedpos = installedpos; + return level; +} + +static int +resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq) +{ + Pool *pool = solv->pool; + int i, j, n; + int postponed; + Rule *r; + int origlevel = level; + Id p, *dp; + + /* + * decide + */ + POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); + postponed = 0; + for (i = 1, n = 1; ; i++, n++) + { + if (n >= solv->nrules) + { + if (postponed <= 0) + break; + i = postponed; + postponed = -1; + n = 1; + } + if (i == solv->nrules) + i = 1; + r = solv->rules + i; + if (r->d < 0) /* ignore disabled rules */ + continue; + if (r->p < 0) /* most common cases first */ + { + if (r->d == 0 || solv->decisionmap[-r->p] <= 0) + continue; + } + if (dq->count) + queue_empty(dq); + if (r->d == 0) + { + /* binary or unary rule */ + /* need two positive undecided literals, r->p already checked above */ + if (r->w2 <= 0) + continue; + if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) + continue; + queue_push(dq, r->p); + queue_push(dq, r->w2); + } + else + { + /* make sure that + * all negative literals are installed + * no positive literal is installed + * i.e. the rule is not fulfilled and we + * just need to decide on the positive literals + * (decisionmap[-r->p] for the r->p < 0 case is already checked above) + */ + if (r->p >= 0) + { + if (solv->decisionmap[r->p] > 0) + continue; + if (solv->decisionmap[r->p] == 0) + queue_push(dq, r->p); + } + dp = pool->whatprovidesdata + r->d; + while ((p = *dp++) != 0) + { + if (p < 0) + { + if (solv->decisionmap[-p] <= 0) + break; + } + else + { + if (solv->decisionmap[p] > 0) + break; + if (solv->decisionmap[p] == 0) + queue_push(dq, p); + } + } + if (p) + continue; + } + IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) + { + POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); + solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); + } + /* dq->count < 2 cannot happen as this means that + * the rule is unit */ + assert(dq->count > 1); + + /* prune to cleandeps packages */ + if (solv->cleandepsmap.size && solv->installed) + { + Repo *installed = solv->installed; + for (j = 0; j < dq->count; j++) + if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start)) + break; + if (j < dq->count) + { + dq->elements[0] = dq->elements[j]; + queue_truncate(dq, 1); + } + } + + if (dq->count > 1 && postponed >= 0) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE_NOREORDER); + if (dq->count > 1) + { + if (!postponed) + postponed = i; + continue; + } + } + + level = selectandinstall(solv, level, dq, disablerules, r - solv->rules, SOLVER_REASON_RESOLVE); + if (level < origlevel) + break; /* trouble */ + /* something changed, so look at all rules again */ + n = 0; + } + return level; +} + + #ifdef ENABLE_COMPLEX_DEPS static void @@ -1974,7 +1965,7 @@ add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap) { if (solv->decisionmap[p] < 0) continue; - if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) + if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) continue; } queue_push(dq, p); @@ -2055,14 +2046,420 @@ do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected) if (p > 0) MAPSET(m, p); } - while (dq.elements[i]) - i++; + while (dq.elements[i]) + i++; + } + queue_free(&dq); +} + +#endif + +static void +prune_disfavored(Solver *solv, Queue *plist) +{ + int i, j; + if (!solv->isdisfavormap.size) + return; + for (i = j = 0; i < plist->count; i++) + { + Id p = plist->elements[i]; + if (!MAPTST(&solv->isdisfavormap, p)) + plist->elements[j++] = p; + } + if (i != j) + queue_truncate(plist, j); +} + +static int +resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp) +{ + Pool *pool = solv->pool; + int i, j, qcount; + int olevel; + Solvable *s; + Map dqmap; + int decisioncount; + Id p; + + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); + if (dq->count) + queue_empty(dq); /* recommended packages */ + if (dqs->count) + queue_empty(dqs); /* supplemented packages */ + for (i = 1; i < pool->nsolvables; i++) + { + if (solv->decisionmap[i] < 0) + continue; + s = pool->solvables + i; + if (solv->decisionmap[i] > 0) + { + /* installed, check for recommends */ + Id *recp, rec, pp, p; + if (!solv->addalreadyrecommended && s->repo == solv->installed) + continue; + if (s->recommends) + { + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + /* cheat: we just look if there is REL_NAMESPACE in the dep */ + if (solv->only_namespace_recommended && !solver_is_namespace_dep(solv, rec)) + continue; +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + { + add_complex_recommends(solv, rec, dq, 0); + continue; + } +#endif + qcount = dq->count; + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = qcount; + break; + } + else if (solv->decisionmap[p] == 0) + { + if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) + continue; + queue_pushunique(dq, p); + } + } + } + } + } + else + { + /* not yet installed, check if supplemented */ + if (!s->supplements) + continue; + if (!pool_installable(pool, s)) + continue; + if (!solver_is_supplementing(solv, s)) + continue; + if (solv->process_orphans && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start)))) + continue; + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i)) + continue; /* disfavored supplements, do not install */ + queue_push(dqs, i); + } + } + + /* filter out disfavored recommended packages */ + if (dq->count && solv->isdisfavormap.size) + prune_disfavored(solv, dq); + + /* filter out all packages obsoleted by installed packages */ + /* this is no longer needed if we have (and trust) reverse obsoletes */ + if ((dqs->count || dq->count) && solv->installed) + { + Map obsmap; + Id obs, *obsp, po, ppo; + + map_init(&obsmap, pool->nsolvables); + for (p = solv->installed->start; p < solv->installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != solv->installed || !s->obsoletes) + continue; + if (solv->decisionmap[p] <= 0) + continue; + if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) + continue; + obsp = s->repo->idarraydata + s->obsoletes; + /* foreach obsoletes */ + while ((obs = *obsp++) != 0) + FOR_PROVIDES(po, ppo, obs) + { + Solvable *pos = pool->solvables + po; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) + continue; + MAPSET(&obsmap, po); + } + } + for (i = j = 0; i < dqs->count; i++) + if (!MAPTST(&obsmap, dqs->elements[i])) + dqs->elements[j++] = dqs->elements[i]; + dqs->count = j; + for (i = j = 0; i < dq->count; i++) + if (!MAPTST(&obsmap, dq->elements[i])) + dq->elements[j++] = dq->elements[i]; + dq->count = j; + map_free(&obsmap); + } + + /* filter out all already supplemented packages if requested */ + if ((!solv->addalreadyrecommended || solv->only_namespace_recommended) && dqs->count) + { + /* filter out old supplements */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + s = pool->solvables + p; + if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* multiversion doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different version (see bnc#501088) */ + if (dqs->count && solv->multiversion.size) + { + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&solv->multiversion, p)) + { + Id p2, pp2; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) + break; + if (p2) + continue; /* ignore this package */ + } + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* implicitobsoleteusescolors doesn't mix well with supplements. + * filter supplemented packages where we already decided + * to install a different architecture */ + if (dqs->count && pool->implicitobsoleteusescolors) + { + for (i = j = 0; i < dqs->count; i++) + { + Id p2, pp2; + p = dqs->elements[i]; + s = pool->solvables + p; + FOR_PROVIDES(p2, pp2, s->name) + if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch) + break; + if (p2) + continue; /* ignore this package */ + dqs->elements[j++] = p; + } + dqs->count = j; + } + + /* make dq contain both recommended and supplemented pkgs */ + if (dqs->count) + { + for (i = 0; i < dqs->count; i++) + queue_pushunique(dq, dqs->elements[i]); + } + + if (!dq->count) + return level; + *rerunp = 1; + + if (dq->count == 1) + { + /* simple case, just one package. no need to choose to best version */ + p = dq->elements[0]; + if (dqs->count) + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + else + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + return setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + } + + /* filter packages, this gives us the best versions */ + policy_filter_unwanted(solv, dq, POLICY_MODE_RECOMMEND); + + /* create map of result */ + map_init(&dqmap, pool->nsolvables); + for (i = 0; i < dq->count; i++) + MAPSET(&dqmap, dq->elements[i]); + + /* prune dqs so that it only contains the best versions */ + for (i = j = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (MAPTST(&dqmap, p)) + dqs->elements[j++] = p; + } + dqs->count = j; + + /* install all supplemented packages, but order first */ + if (dqs->count > 1) + policy_filter_unwanted(solv, dqs, POLICY_MODE_SUPPLEMENT); + decisioncount = solv->decisionq.count; + for (i = 0; i < dqs->count; i++) + { + p = dqs->elements[i]; + if (solv->decisionmap[p]) + continue; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel) + break; + } + if (i < dqs->count || solv->decisionq.count < decisioncount) + { + map_free(&dqmap); + return level; + } + + /* install all recommended packages */ + /* more work as we want to created branches if multiple + * choices are valid */ + for (i = 0; i < decisioncount; i++) + { + Id rec, *recp, pp; + p = solv->decisionq.elements[i]; + if (p < 0) + continue; + s = pool->solvables + p; + if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) + continue; + if (!s->recommends) + continue; + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + queue_empty(dq); +#ifdef ENABLE_COMPLEX_DEPS + if (pool_is_complex_dep(pool, rec)) + add_complex_recommends(solv, rec, dq, &dqmap); + else +#endif + FOR_PROVIDES(p, pp, rec) + { + if (solv->decisionmap[p] > 0) + { + dq->count = 0; + break; + } + else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) + queue_push(dq, p); + } + if (!dq->count) + continue; + if (dq->count > 1) + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + /* if we have multiple candidates we open a branch */ + if (dq->count > 1) + createbranch(solv, level, dq, s - pool->solvables, rec); + p = dq->elements[0]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP); + if (level <= olevel || solv->decisionq.count < decisioncount) + break; /* we had to revert some decisions */ + } + if (rec) + break; /* had a problem above, quit loop */ + } + map_free(&dqmap); + return level; +} + +static int +resolve_cleandeps(Solver *solv, int level, int disablerules, int *rerunp) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + int olevel; + Id p; + Solvable *s; + + if (!installed || !solv->cleandepsmap.size) + return level; + POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding cleandeps packages\n"); + for (p = installed->start; p < installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != installed) + continue; + if (solv->decisionmap[p] != 0 || !MAPTST(&solv->cleandepsmap, p - installed->start)) + continue; + POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE); + if (level < olevel) + break; + } + if (p < installed->end) + *rerunp = 1; + return level; +} + +static int +resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp) +{ + Pool *pool = solv->pool; + int i; + Id p; + int installedone = 0; + int olevel; + + /* let's see if we can install some unsupported package */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + if (solv->droporphanedmap_all) + continue; + if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) + continue; + POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + installedone = 1; + if (level < olevel) + break; + } + if (installedone || i < solv->orphaned.count) + { + *rerunp = 1; + return level; + } + for (i = 0; i < solv->orphaned.count; i++) + { + p = solv->orphaned.elements[i]; + if (solv->decisionmap[p]) + continue; /* already decided */ + POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + { + *rerunp = 1; + return level; + } + } + if (solv->brokenorphanrules) + { + solver_check_brokenorphanrules(solv, dq); + if (dq->count) + { + policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE); + for (i = 0; i < dq->count; i++) + { + p = dq->elements[i]; + POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); + olevel = level; + level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN); + if (level < olevel) + break; + } + *rerunp = 1; + } } - queue_free(&dq); + return level; } -#endif - /*------------------------------------------------------------------- * * solver_run_sat @@ -2079,12 +2476,11 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) int systemlevel; int level, olevel; Rule *r; - int i, j, n; + int i; Solvable *s; Pool *pool = solv->pool; - Id p, pp, *dp, postponed; + Id p; int minimizationsteps; - int installedpos = solv->installed ? solv->installed->start : 0; IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION) { @@ -2100,6 +2496,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) queue_init(&dq); queue_init(&dqs); + solv->installedpos = 0; + solv->do_extra_reordering = 0; /* * here's the main loop: @@ -2123,13 +2521,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) { if (level < 0) break; - makeruledecisions(solv); - level = 1; - if (!disablerules && solv->problems.count) - { - level = -1; - break; - } + level = makeruledecisions(solv, disablerules); + if (level < 0) + break; POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count); if ((r = propagate(solv, level)) != 0) { @@ -2144,181 +2538,41 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) */ if (level < systemlevel && !solv->focus_installed) { + if (solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + solv->do_extra_reordering = 1; olevel = level; level = resolve_jobrules(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; if (level < olevel) continue; systemlevel = level + 1; } + /* resolve job dependencies in the focus_best case */ + if (level < systemlevel && solv->focus_best && !solv->focus_installed && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) + { + solv->do_extra_reordering = 1; + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + solv->do_extra_reordering = 0; + if (level < olevel) + continue; /* start over */ + systemlevel = level + 1; + } /* * installed packages */ - if (!solv->decisioncnt_update) - solv->decisioncnt_update = solv->decisionq.count; if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled) { - Repo *installed = solv->installed; - int pass; - - POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n"); - /* we use two passes if we need to update packages - * to create a better user experience */ - for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++) - { - int passlevel = level; - Id *specialupdaters = solv->specialupdaters; - if (pass == 1 && !solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; - /* start with installedpos, the position that gave us problems the last time */ - for (i = installedpos, n = installed->start; n < installed->end; i++, n++) - { - Rule *rr; - Id d; - - if (i == installed->end) - i = installed->start; - s = pool->solvables + i; - if (s->repo != installed) - continue; - - if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start])) - continue; /* already decided */ - if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start)) - continue; /* updates first */ - r = solv->rules + solv->updaterules + (i - installed->start); - rr = r; - if (!rr->p || rr->d < 0) /* disabled -> look at feature rule */ - rr -= solv->installed->end - solv->installed->start; - if (!rr->p) /* identical to update rule? */ - rr = r; - if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start])) - continue; /* orpaned package */ - - /* check if we should update this package to the latest version - * noupdate is set for erase jobs, in that case we want to deinstall - * the installed package and not replace it with a newer version - * rr->p != i is for dup jobs where the installed package cannot be kept */ - queue_empty(&dq); - if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i))) - { - if (!rr->p) - { - /* specialupdater with no update/feature rule */ - for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; ) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0) - { - /* special multiversion handling, make sure best version is chosen */ - if (rr->p == i && solv->decisionmap[i] >= 0) - queue_push(&dq, i); - while ((p = pool->whatprovidesdata[d++]) != 0) - if (solv->decisionmap[p] >= 0) - queue_push(&dq, p); - if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); - if (dq.count) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - p = dq.elements[0]; - if (p != i && solv->decisionmap[p] == 0) - { - rr = solv->rules + solv->featurerules + (i - solv->installed->start); - if (!rr->p) /* update rule == feature rule? */ - rr = rr - solv->featurerules + solv->updaterules; - dq.count = 1; - } - else - dq.count = 0; - } - } - else - { - /* update to best package of the update rule */ - FOR_RULELITERALS(p, pp, rr) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; /* already fulfilled */ - break; - } - if (!solv->decisionmap[p]) - queue_push(&dq, p); - } - } - } - if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start]) - prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq); - /* install best version */ - if (dq.count) - { - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules); - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; - } - } - /* if still undecided keep package */ - if (solv->decisionmap[i] == 0) - { - olevel = level; - if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start)) - { -#if 0 - POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, -i, disablerules, 0); -#else - continue; -#endif - } - else - { - POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i)); - level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules); - } - if (level <= olevel) - { - if (level < passlevel) - break; /* trouble */ - if (level < olevel) - n = installed->start; /* redo all */ - i--; - n--; - continue; /* retry with learnt rule */ - } - } - } - if (n < installed->end) - { - installedpos = i; /* retry problem solvable next time */ - break; /* ran into trouble */ - } - installedpos = installed->start; /* reset installedpos */ - } + olevel = level; + level = resolve_installed(solv, level, disablerules, &dq); + if (level < olevel) + continue; systemlevel = level + 1; - if (pass < 2) - continue; /* had trouble, retry */ } - if (!solv->decisioncnt_keep) - solv->decisioncnt_keep = solv->decisionq.count; + /* resolve jobs in focus_installed case */ if (level < systemlevel && solv->focus_installed) { olevel = level; @@ -2331,457 +2585,39 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) if (level < systemlevel) systemlevel = level; - /* - * decide - */ - if (!solv->decisioncnt_resolve) - solv->decisioncnt_resolve = solv->decisionq.count; - POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n"); - postponed = 0; - for (i = 1, n = 1; ; i++, n++) - { - if (n >= solv->nrules) - { - if (postponed <= 0) - break; - i = postponed; - postponed = -1; - n = 1; - } - if (i == solv->nrules) - i = 1; - r = solv->rules + i; - if (r->d < 0) /* ignore disabled rules */ - continue; - if (r->p < 0) /* most common cases first */ - { - if (r->d == 0 || solv->decisionmap[-r->p] <= 0) - continue; - } - if (dq.count) - queue_empty(&dq); - if (r->d == 0) - { - /* binary or unary rule */ - /* need two positive undecided literals, r->p already checked above */ - if (r->w2 <= 0) - continue; - if (solv->decisionmap[r->p] || solv->decisionmap[r->w2]) - continue; - queue_push(&dq, r->p); - queue_push(&dq, r->w2); - } - else - { - /* make sure that - * all negative literals are installed - * no positive literal is installed - * i.e. the rule is not fulfilled and we - * just need to decide on the positive literals - * (decisionmap[-r->p] for the r->p < 0 case is already checked above) - */ - if (r->p >= 0) - { - if (solv->decisionmap[r->p] > 0) - continue; - if (solv->decisionmap[r->p] == 0) - queue_push(&dq, r->p); - } - dp = pool->whatprovidesdata + r->d; - while ((p = *dp++) != 0) - { - if (p < 0) - { - if (solv->decisionmap[-p] <= 0) - break; - } - else - { - if (solv->decisionmap[p] > 0) - break; - if (solv->decisionmap[p] == 0) - queue_push(&dq, p); - } - } - if (p) - continue; - } - IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE) - { - POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled "); - solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r); - } - /* dq.count < 2 cannot happen as this means that - * the rule is unit */ - assert(dq.count > 1); - - /* prune to cleandeps packages */ - if (solv->cleandepsmap.size && solv->installed) - { - Repo *installed = solv->installed; - for (j = 0; j < dq.count; j++) - if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start)) - break; - if (j < dq.count) - { - dq.elements[0] = dq.elements[j]; - queue_truncate(&dq, 1); - } - } - - if (dq.count > 1 && postponed >= 0) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER); - if (dq.count > 1) - { - if (!postponed) - postponed = i; - continue; - } - } - - olevel = level; - level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules); - if (level < systemlevel) - break; /* trouble */ - /* something changed, so look at all rules again */ - n = 0; - } - - if (n < solv->nrules) /* ran into trouble? */ + /* resolve all dependencies */ + olevel = level; + level = resolve_dependencies(solv, level, disablerules, &dq); + if (level < olevel) continue; /* start over */ /* decide leftover cleandeps packages */ if (solv->cleandepsmap.size && solv->installed) { - for (p = solv->installed->start; p < solv->installed->end; p++) - { - s = pool->solvables + p; - if (s->repo != solv->installed) - continue; - if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start)) - { - POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); - if (level < olevel) - break; - } - } - if (p < solv->installed->end) + int rerun = 0; + level = resolve_cleandeps(solv, level, disablerules, &rerun); + if (rerun) continue; } /* at this point we have a consistent system. now do the extras... */ - if (!solv->decisioncnt_weak) - solv->decisioncnt_weak = solv->decisionq.count; if (doweak) { - int qcount; - - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n"); - queue_empty(&dq); /* recommended packages */ - queue_empty(&dqs); /* supplemented packages */ - for (i = 1; i < pool->nsolvables; i++) - { - if (solv->decisionmap[i] < 0) - continue; - if (solv->decisionmap[i] > 0) - { - /* installed, check for recommends */ - Id *recp, rec, pp, p; - s = pool->solvables + i; - if (!solv->addalreadyrecommended && s->repo == solv->installed) - continue; - /* XXX need to special case AND ? */ - if (s->recommends) - { - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - { - add_complex_recommends(solv, rec, &dq, 0); - continue; - } -#endif - qcount = dq.count; - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = qcount; - break; - } - else if (solv->decisionmap[p] == 0) - { - if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)))) - continue; - queue_pushunique(&dq, p); - } - } - } - } - } - else - { - s = pool->solvables + i; - if (!s->supplements) - continue; - if (!pool_installable(pool, s)) - continue; - if (!solver_is_supplementing(solv, s)) - continue; - if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start)))) - continue; - queue_push(&dqs, i); - } - } - - /* filter out all packages obsoleted by installed packages */ - /* this is no longer needed if we have reverse obsoletes */ - if ((dqs.count || dq.count) && solv->installed) - { - Map obsmap; - Id obs, *obsp, po, ppo; - - map_init(&obsmap, pool->nsolvables); - for (p = solv->installed->start; p < solv->installed->end; p++) - { - s = pool->solvables + p; - if (s->repo != solv->installed || !s->obsoletes) - continue; - if (solv->decisionmap[p] <= 0) - continue; - if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p)) - continue; - obsp = s->repo->idarraydata + s->obsoletes; - /* foreach obsoletes */ - while ((obs = *obsp++) != 0) - FOR_PROVIDES(po, ppo, obs) - { - Solvable *pos = pool->solvables + po; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos)) - continue; - MAPSET(&obsmap, po); - } - } - for (i = j = 0; i < dqs.count; i++) - if (!MAPTST(&obsmap, dqs.elements[i])) - dqs.elements[j++] = dqs.elements[i]; - dqs.count = j; - for (i = j = 0; i < dq.count; i++) - if (!MAPTST(&obsmap, dq.elements[i])) - dq.elements[j++] = dq.elements[i]; - dq.count = j; - map_free(&obsmap); - } - - /* filter out all already supplemented packages if requested */ - if (!solv->addalreadyrecommended && dqs.count) - { - /* filter out old supplements */ - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - s = pool->solvables + p; - if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s)) - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* multiversion doesn't mix well with supplements. - * filter supplemented packages where we already decided - * to install a different version (see bnc#501088) */ - if (dqs.count && solv->multiversion.size) - { - for (i = j = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (MAPTST(&solv->multiversion, p)) - { - Id p2, pp2; - s = pool->solvables + p; - FOR_PROVIDES(p2, pp2, s->name) - if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name) - break; - if (p2) - continue; /* ignore this package */ - } - dqs.elements[j++] = p; - } - dqs.count = j; - } - - /* make dq contain both recommended and supplemented pkgs */ - if (dqs.count) - { - for (i = 0; i < dqs.count; i++) - queue_pushunique(&dq, dqs.elements[i]); - } - - if (dq.count) - { - Map dqmap; - int decisioncount = solv->decisionq.count; - - if (dq.count == 1) - { - /* simple case, just one package. no need to choose to best version */ - p = dq.elements[0]; - if (dqs.count) - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - else - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - level = setpropagatelearn(solv, level, p, 0, 0); - continue; /* back to main loop */ - } - - /* filter packages, this gives us the best versions */ - policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND); - - /* create map of result */ - map_init(&dqmap, pool->nsolvables); - for (i = 0; i < dq.count; i++) - MAPSET(&dqmap, dq.elements[i]); - - /* install all supplemented packages */ - for (i = 0; i < dqs.count; i++) - { - p = dqs.elements[i]; - if (solv->decisionmap[p] || !MAPTST(&dqmap, p)) - continue; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel) - break; - } - if (i < dqs.count || solv->decisionq.count < decisioncount) - { - map_free(&dqmap); - continue; - } - - /* install all recommended packages */ - /* more work as we want to created branches if multiple - * choices are valid */ - for (i = 0; i < decisioncount; i++) - { - Id rec, *recp, pp; - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed)) - continue; - if (!s->recommends) - continue; - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { - queue_empty(&dq); -#ifdef ENABLE_COMPLEX_DEPS - if (pool_is_complex_dep(pool, rec)) - add_complex_recommends(solv, rec, &dq, &dqmap); - else -#endif - FOR_PROVIDES(p, pp, rec) - { - if (solv->decisionmap[p] > 0) - { - dq.count = 0; - break; - } - else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p)) - queue_push(&dq, p); - } - if (!dq.count) - continue; - if (dq.count > 1) - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - /* if we have multiple candidates we open a branch */ - if (dq.count > 1) - createbranch(solv, level, &dq, s - pool->solvables, rec); - p = dq.elements[0]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level <= olevel || solv->decisionq.count < decisioncount) - break; /* we had to revert some decisions */ - } - if (rec) - break; /* had a problem above, quit loop */ - } - map_free(&dqmap); - continue; /* back to main loop so that all deps are checked */ - } + int rerun = 0; + level = resolve_weak(solv, level, disablerules, &dq, &dqs, &rerun); + if (rerun) + continue; } - if (!solv->decisioncnt_orphan) - solv->decisioncnt_orphan = solv->decisionq.count; if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules)) { - int installedone = 0; - - /* let's see if we can install some unsupported package */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n"); - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - if (solv->droporphanedmap_all) - continue; - if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start)) - continue; - POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - installedone = 1; - if (level < olevel) - break; - } - if (installedone || i < solv->orphaned.count) - continue; /* back to main loop */ - for (i = 0; i < solv->orphaned.count; i++) - { - p = solv->orphaned.elements[i]; - if (solv->decisionmap[p]) - continue; /* already decided */ - POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); - if (level < olevel) - break; - } - if (i < solv->orphaned.count) - continue; /* back to main loop */ - if (solv->brokenorphanrules) - { - solver_check_brokenorphanrules(solv, &dq); - if (dq.count) - { - policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE); - for (i = 0; i < dq.count; i++) - { - p = dq.elements[i]; - POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p)); - olevel = level; - level = setpropagatelearn(solv, level, p, 0, 0); - if (level < olevel) - break; - } - continue; - } - } + int rerun = 0; + level = resolve_orphaned(solv, level, disablerules, &dq, &rerun); + if (rerun) + continue; } - + /* one final pass to make sure we decided all installed packages */ if (solv->installed) { @@ -2794,7 +2630,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p)); olevel = level; - level = setpropagatelearn(solv, level, -p, 0, 0); + level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE); if (level < olevel) break; } @@ -2802,7 +2638,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) continue; /* back to main loop */ } - if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv)) + if (solv->installed && solv->cleandepsmap.size && solver_check_cleandeps_mistakes(solv)) { solver_reset(solv); level = 0; /* restart from scratch */ @@ -2864,6 +2700,8 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) lastsi = -1; break; } + if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)) + continue; if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p))) lastsi = i; } @@ -2876,6 +2714,9 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) p = -solv->branches.elements[i]; if (p <= 0 || solv->decisionmap[p] != l + 1) continue; + if (solv->favormap.size && MAPTST(&solv->favormap, p)) + if (!(solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))) + continue; /* current selection is favored */ if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p))) { lasti = lastsi; @@ -2896,22 +2737,13 @@ solver_run_sat(Solver *solv, int disablerules, int doweak) /* no minimization found, we're finally finished! */ break; } + assert(level == -1 || level + 1 == solv->decisionq_reason.count); POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps); POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n"); queue_free(&dq); queue_free(&dqs); - if (level < 0) - { - /* unsolvable */ - solv->decisioncnt_jobs = solv->decisionq.count; - solv->decisioncnt_update = solv->decisionq.count; - solv->decisioncnt_keep = solv->decisionq.count; - solv->decisioncnt_resolve = solv->decisionq.count; - solv->decisioncnt_weak = solv->decisionq.count; - solv->decisioncnt_orphan = solv->decisionq.count; - } #if 0 solver_printdecisionq(solv, SOLV_DEBUG_RESULT); #endif @@ -3087,8 +2919,10 @@ solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap) Solvable *s; Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - MAPSET(multiversionmap, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + MAPSET(multiversionmap, p); + } } FOR_JOB_SELECT(p, pp, select, what) MAPSET(multiversionmap, p); @@ -3114,7 +2948,7 @@ solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak) } static inline void -add_cleandeps_package(Solver *solv, Id p) +add_cleandeps_updatepkg(Solver *solv, Id p) { if (!solv->cleandeps_updatepkgs) { @@ -3130,7 +2964,9 @@ add_update_target(Solver *solv, Id p, Id how) Pool *pool = solv->pool; Solvable *s = pool->solvables + p; Repo *installed = solv->installed; - Id pi, pip; + Id pi, pip, identicalp; + int startcnt, endcnt; + if (!solv->update_targets) { solv->update_targets = solv_calloc(1, sizeof(Queue)); @@ -3141,6 +2977,8 @@ add_update_target(Solver *solv, Id p, Id how) queue_push2(solv->update_targets, p, p); return; } + identicalp = 0; + startcnt = solv->update_targets->count; FOR_PROVIDES(pi, pip, s->name) { Solvable *si = pool->solvables + pi; @@ -3153,11 +2991,11 @@ add_update_target(Solver *solv, Id p, Id how) MAPSET(&solv->bestupdatemap, pi - installed->start); } if (how & SOLVER_CLEANDEPS) - add_cleandeps_package(solv, pi); + add_cleandeps_updatepkg(solv, pi); queue_push2(solv->update_targets, pi, p); - /* check if it's ok to keep the installed package */ + /* remember an installed package that is identical to p */ if (s->evr == si->evr && solvable_identical(s, si)) - queue_push2(solv->update_targets, pi, pi); + identicalp = pi; } if (s->obsoletes) { @@ -3182,11 +3020,17 @@ add_update_target(Solver *solv, Id p, Id how) MAPSET(&solv->bestupdatemap, pi - installed->start); } if (how & SOLVER_CLEANDEPS) - add_cleandeps_package(solv, pi); + add_cleandeps_updatepkg(solv, pi); queue_push2(solv->update_targets, pi, p); } } } + /* also allow upgrading to an identical installed package */ + if (identicalp) + { + for (endcnt = solv->update_targets->count; startcnt < endcnt; startcnt += 2) + queue_push2(solv->update_targets, solv->update_targets->elements[startcnt], identicalp); + } } static int @@ -3341,6 +3185,42 @@ add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak) } #endif +/* sort by package id, last entry wins */ +static int +setup_favormaps_cmp(const void *ap, const void *bp, void *dp) +{ + const Id *a = ap, *b = bp; + if ((*a - *b) != 0) + return *a - *b; + return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]); +} + +static void +setup_favormaps(Solver *solv) +{ + Queue *q = solv->favorq; + Pool *pool = solv->pool; + int i; + Id oldp = 0; + if (q->count > 2) + solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormaps_cmp, solv); + map_grow(&solv->favormap, pool->nsolvables); + for (i = 0; i < q->count; i += 2) + { + Id p = q->elements[i]; + if (p == oldp) + continue; + oldp = p; + MAPSET(&solv->favormap, p); + if (q->elements[i + 1] < 0) + { + if (!solv->isdisfavormap.size) + map_grow(&solv->isdisfavormap, pool->nsolvables); + MAPSET(&solv->isdisfavormap, p); + } + } +} + /* * * solve job queue @@ -3358,7 +3238,7 @@ solver_solve(Solver *solv, Queue *job) Map installcandidatemap; Id how, what, select, name, weak, p, pp, d; Queue q; - Solvable *s; + Solvable *s, *name_s; Rule *r; int now, solve_start; int needduprules = 0; @@ -3372,7 +3252,7 @@ solver_solve(Solver *solv, Queue *job) POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange); POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts); POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors); - POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended); + POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d onlynamespacerecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended, solv->only_namespace_recommended); /* create whatprovides if not already there */ if (!pool->whatprovides) @@ -3389,7 +3269,7 @@ solver_solve(Solver *solv, Queue *job) queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements); job = &solv->job; - /* free old stuff in jase we re-run a solver */ + /* free old stuff in case we re-run a solver */ queuep_free(&solv->update_targets); queuep_free(&solv->cleandeps_updatepkgs); queue_empty(&solv->ruleassertions); @@ -3405,15 +3285,17 @@ solver_solve(Solver *solv, Queue *job) map_zerosize(&solv->bestupdatemap); solv->fixmap_all = 0; map_zerosize(&solv->fixmap); - solv->dupmap_all = 0; map_zerosize(&solv->dupmap); map_zerosize(&solv->dupinvolvedmap); + solv->process_orphans = 0; solv->droporphanedmap_all = 0; map_zerosize(&solv->droporphanedmap); solv->allowuninstall_all = 0; map_zerosize(&solv->allowuninstallmap); map_zerosize(&solv->cleandepsmap); map_zerosize(&solv->weakrulemap); + map_zerosize(&solv->favormap); + map_zerosize(&solv->isdisfavormap); queue_empty(&solv->weakruleq); solv->watches = solv_free(solv->watches); queue_empty(&solv->ruletojob); @@ -3421,7 +3303,7 @@ solver_solve(Solver *solv, Queue *job) memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id)); queue_empty(&solv->decisionq); queue_empty(&solv->decisionq_why); - solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0; + queue_empty(&solv->decisionq_reason); queue_empty(&solv->learnt_why); queue_empty(&solv->learnt_pool); queue_empty(&solv->branches); @@ -3467,7 +3349,7 @@ solver_solve(Solver *solv, Queue *job) deduceq2addedmap(solv, &addedmap); if (solv->nrules != initialnrules) solver_shrinkrules(solv, initialnrules); - solv->nrules = initialnrules; + solv->lastpkgrule = 0; solv->pkgrules_end = 0; if (installed) @@ -3503,7 +3385,7 @@ solver_solve(Solver *solv, Queue *job) if (how & SOLVER_CLEANDEPS) { FOR_REPO_SOLVABLES(installed, p, s) - add_cleandeps_package(solv, p); + add_cleandeps_updatepkg(solv, p); } } else if (select == SOLVER_SOLVABLE_REPO) @@ -3519,7 +3401,7 @@ solver_solve(Solver *solv, Queue *job) if (how & SOLVER_CLEANDEPS) { FOR_REPO_SOLVABLES(installed, p, s) - add_cleandeps_package(solv, p); + add_cleandeps_updatepkg(solv, p); } break; } @@ -3549,7 +3431,7 @@ solver_solve(Solver *solv, Queue *job) MAPSET(&solv->bestupdatemap, p - installed->start); } if (how & SOLVER_CLEANDEPS) - add_cleandeps_package(solv, p); + add_cleandeps_updatepkg(solv, p); targeted = 0; } if (!targeted || solv->noautotarget) @@ -3560,7 +3442,7 @@ solver_solve(Solver *solv, Queue *job) } break; case SOLVER_DROP_ORPHANED: - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid)) solv->droporphanedmap_all = 1; FOR_JOB_SELECT(p, pp, select, what) { @@ -3625,17 +3507,9 @@ solver_solve(Solver *solv, Queue *job) } break; case SOLVER_DISTUPGRADE: + needduprules = 1; if (select == SOLVER_SOLVABLE_ALL) - { - solv->dupmap_all = 1; - solv->updatemap_all = 1; - if (how & SOLVER_FORCEBEST) - solv->bestupdatemap_all = 1; - } - if ((how & SOLVER_TARGETED) != 0) - needduprules = 1; - if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size || solv->keep_orphans) - needduprules = 1; + solv->process_orphans = 1; break; default: break; @@ -3681,6 +3555,7 @@ solver_solve(Solver *solv, Queue *job) if (solv->nrules > initialnrules) solver_unifyrules(solv); /* remove duplicate pkg rules */ solv->pkgrules_end = solv->nrules; /* mark end of pkg rules */ + solv->lastpkgrule = 0; if (solv->nrules > initialnrules) addedmap2deduceq(solv, &addedmap); /* so that we can recreate the addedmap */ @@ -3716,7 +3591,7 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 1); /* allow s to be updated */ + solver_addfeaturerule(solv, s); } /* make sure we accounted for all rules */ assert(solv->nrules - solv->featurerules == installed->end - installed->start); @@ -3744,7 +3619,7 @@ solver_solve(Solver *solv, Queue *job) solver_addrule(solv, 0, 0, 0); /* create dummy rule */ continue; } - solver_addupdaterule(solv, s, 0); /* allowall = 0: downgrades not allowed */ + solver_addupdaterule(solv, s); /* * check for and remove duplicate */ @@ -3757,11 +3632,12 @@ solver_solve(Solver *solv, Queue *job) continue; } /* it's also orphaned if the feature rule consists just of the installed package */ - if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2) + if (!solv->process_orphans && sr->p == i && !sr->d && !sr->w2) queue_push(&solv->orphaned, i); + if (!solver_rulecmp(solv, r, sr)) memset(sr, 0, sizeof(*sr)); /* delete unneeded feature rule */ - else + else if (sr->p) solver_disablerule(solv, sr); /* disable feature rule for now */ } /* consistency check: we added a rule for _every_ installed solvable */ @@ -3845,6 +3721,7 @@ solver_solve(Solver *solv, Queue *job) map_grow(&solv->cleandepsmap, installed->end - installed->start); /* specific solvable: by id or by nevra */ name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1; + name_s = 0; if (select == SOLVER_SOLVABLE_ALL) /* hmmm ;) */ { FOR_POOL_SOLVABLES(p) @@ -3854,8 +3731,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, -p, 0, 0, i, weak); + } } #ifdef ENABLE_COMPLEX_DEPS else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what)) @@ -3869,7 +3748,10 @@ solver_solve(Solver *solv, Queue *job) { s = pool->solvables + p; if (installed && s->repo == installed) - name = !name ? s->name : -1; + { + name = !name ? s->name : -1; + name_s = s; + } solver_addjobrule(solv, -p, 0, 0, i, weak); } /* special case for "erase a specific solvable": we also @@ -3893,6 +3775,8 @@ solver_solve(Solver *solv, Queue *job) /* keep installcandidates of other jobs */ if (MAPTST(&installcandidatemap, p)) continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, name_s, s)) + continue; /* don't add the same rule twice */ for (j = oldnrules; j < k; j++) if (solv->rules[j].p == -p) @@ -3930,8 +3814,10 @@ solver_solve(Solver *solv, Queue *job) { Repo *repo = pool_id2repo(pool, what); if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + { + FOR_REPO_SOLVABLES(repo, p, s) + solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); + } } FOR_JOB_SELECT(p, pp, select, what) solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak); @@ -3948,6 +3834,21 @@ solver_solve(Solver *solv, Queue *job) case SOLVER_ALLOWUNINSTALL: POOL_DEBUG(SOLV_DEBUG_JOB, "job: allowuninstall %s\n", solver_select2str(pool, select, what)); break; + case SOLVER_FAVOR: + case SOLVER_DISFAVOR: + POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what)); + FOR_JOB_SELECT(p, pp, select, what) + { + int j; + if (!solv->favorq) + { + solv->favorq = solv_calloc(1, sizeof(Queue)); + queue_init(solv->favorq); + } + j = solv->favorq->count + 1; + queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j); + } + break; default: POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n"); break; @@ -3968,32 +3869,30 @@ solver_solve(Solver *solv, Queue *job) assert(solv->ruletojob.count == solv->nrules - solv->jobrules); solv->jobrules_end = solv->nrules; + /* transform favorq into two maps */ + if (solv->favorq) + setup_favormaps(solv); + /* now create infarch and dup rules */ if (!solv->noinfarchcheck) - { - solver_addinfarchrules(solv, &addedmap); -#if 0 - if (pool->implicitobsoleteusescolors) - { - /* currently doesn't work well with infarch rules, so make - * them weak */ - for (i = solv->infarchrules; i < solv->infarchrules_end; i++) - queue_push(&solv->weakruleq, i); - } -#endif - } + solver_addinfarchrules(solv, &addedmap); else solv->infarchrules = solv->infarchrules_end = solv->nrules; - if (needduprules) + if (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size) solver_addduprules(solv, &addedmap); else solv->duprules = solv->duprules_end = solv->nrules; +#ifdef ENABLE_LINKED_PKGS + if (solv->instbuddy && solv->updatemap.size) + extend_updatemap_to_buddies(solv); +#endif + if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob) solver_addbestrules(solv, hasbestinstalljob); else - solv->bestrules = solv->bestrules_end = solv->nrules; + solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules; if (needduprules) solver_freedupmaps(solv); /* no longer needed */ @@ -4023,11 +3922,11 @@ solver_solve(Solver *solv, Queue *job) map_free(&installcandidatemap); queue_free(&q); - POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules); + POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules); POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024); /* create weak map */ - if (solv->weakruleq.count) + if (solv->weakruleq.count || solv->recommendsruleq) { map_grow(&solv->weakrulemap, solv->nrules); for (i = 0; i < solv->weakruleq.count; i++) @@ -4035,6 +3934,14 @@ solver_solve(Solver *solv, Queue *job) p = solv->weakruleq.elements[i]; MAPSET(&solv->weakrulemap, p); } + if (solv->recommendsruleq) + { + for (i = 0; i < solv->recommendsruleq->count; i++) + { + p = solv->recommendsruleq->elements[i]; + MAPSET(&solv->weakrulemap, p); + } + } } /* enable cleandepsmap creation if we have updatepkgs */ @@ -4063,7 +3970,7 @@ solver_solve(Solver *solv, Queue *job) solver_disablepolicyrules(solv); /* break orphans if requested */ - if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans) + if (solv->process_orphans && solv->orphaned.count && solv->break_orphans) solver_breakorphans(solv); /* @@ -4100,6 +4007,35 @@ void solver_get_orphaned(Solver *solv, Queue *orphanedq) queue_init_clone(orphanedq, &solv->orphaned); } +void solver_get_cleandeps(Solver *solv, Queue *cleandepsq) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Solvable *s; + Rule *r; + Id p, pp, pr; + + queue_empty(cleandepsq); + if (!installed || !solv->cleandepsmap.size) + return; + FOR_REPO_SOLVABLES(installed, p, s) + { + if (!MAPTST(&solv->cleandepsmap, p - installed->start) || solv->decisionmap[p] >= 0) + continue; + /* now check the update rule */ + r = solv->rules + solv->updaterules + (p - solv->installed->start); + if (r->p) + { + FOR_RULELITERALS(pr, pp, r) + if (solv->decisionmap[pr] > 0) + break; + if (pr) + continue; + } + queue_push(cleandepsq, p); + } +} + void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected) { Pool *pool = solv->pool; @@ -4167,20 +4103,12 @@ void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *su MAPZERO(&solv->recommendsmap); /* put all packages the solver already chose in the map */ - if (solv->decisioncnt_weak) - { - for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++) - { - Id why; - why = solv->decisionq_why.elements[i]; - if (why) - continue; /* forced by unit rule or dep resolving */ - p = solv->decisionq.elements[i]; - if (p < 0) - continue; + for (i = 1; i < solv->decisionq.count; i++) + if ((p = solv->decisionq.elements[i]) > 0 && solv->decisionq_why.elements[i] == 0) + { + if (solv->decisionq_reason.elements[solv->decisionmap[p]] == SOLVER_REASON_WEAKDEP) MAPSET(&solv->recommendsmap, p); - } - } + } for (i = 0; i < solv->decisionq.count; i++) { @@ -4368,24 +4296,6 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap) pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap); } -void -solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res) -{ - Pool *pool = solv->pool; - Map installedmap; - int i; - pool_create_state_maps(pool, &solv->decisionq, &installedmap, 0); - pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0); - for (i = 0; i < res->count; i++) - if (res->elements[i] != -1) - { - Solvable *s = pool->solvables + pkgs->elements[i]; - if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap)) - res->elements[i] = -1; - } - map_free(&installedmap); -} - /*------------------------------------------------------------------- * * decision introspection @@ -4466,31 +4376,8 @@ solver_describe_decision(Solver *solv, Id p, Id *infop) *infop = why > 0 ? why : -why; if (why > 0) return SOLVER_REASON_UNIT_RULE; - why = -why; - if (i == 0) - return SOLVER_REASON_KEEP_INSTALLED; /* the systemsolvable */ - if (i < solv->decisioncnt_update) - return SOLVER_REASON_RESOLVE_JOB; - if (i < solv->decisioncnt_keep) - { - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_UPDATE_INSTALLED; - } - if (i < solv->decisioncnt_resolve) - { - if (solv->focus_installed && i >= solv->decisioncnt_jobs) - return SOLVER_REASON_RESOLVE_JOB; - if (why == 0 && pp < 0) - return SOLVER_REASON_CLEANDEPS_ERASE; - return SOLVER_REASON_KEEP_INSTALLED; - } - if (why > 0) - return SOLVER_REASON_RESOLVE; - /* weak or orphaned */ - if (i < solv->decisioncnt_orphan) - return SOLVER_REASON_WEAKDEP; - return SOLVER_REASON_RESOLVE_ORPHAN; + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + return solv->decisionq_reason.elements[i]; } @@ -4511,14 +4398,15 @@ solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq) break; if (decisionno == solv->decisionq.count) return; /* huh? */ - if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan) + i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p]; + if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP) return; /* huh? */ /* 1) list all packages that recommend us */ for (i = 1; i < pool->nsolvables; i++) { Id *recp, rec, pp2, p2; - if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level) + if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level) continue; s = pool->solvables + i; if (!s->recommends) @@ -4612,8 +4500,10 @@ pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what) Repo *repo = pool_id2repo(pool, what); Solvable *s; if (repo) - FOR_REPO_SOLVABLES(repo, p, s) - queue_push(pkgs, p); + { + FOR_REPO_SOLVABLES(repo, p, s) + queue_push(pkgs, p); + } } else { @@ -4669,349 +4559,6 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what) return 1; } -static int -get_userinstalled_cmp(const void *ap, const void *bp, void *dp) -{ - return *(Id *)ap - *(Id *)bp; -} - -static int -get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp) -{ - Pool *pool = dp; - return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp)); -} - -static int -get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp) -{ - Pool *pool = dp; - int r; - r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0])); - if (r) - return r; - return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1])); -} - -static void -get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags) -{ - Id lastp = -1, lasta = -1; - int i, j; - if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2)) - return; - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool); - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool); - else - solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - for (i = j = 0; i < q->count; i += 2) - if (q->elements[i] != lastp || q->elements[i + 1] != lasta) - { - q->elements[j++] = lastp = q->elements[i]; - q->elements[j++] = lasta = q->elements[i + 1]; - } - } - else - { - for (i = j = 0; i < q->count; i++) - if (q->elements[i] != lastp) - q->elements[j++] = lastp = q->elements[i]; - } - queue_truncate(q, j); -} - -static void -namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job) -{ - int i; - if (!pool->installed) - return; - for (i = 0; i < q->count; i += 2) - { - Id p, pp, name = q->elements[i], arch = q->elements[i + 1]; - FOR_PROVIDES(p, pp, name) - { - Solvable *s = pool->solvables + p; - if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch)) - continue; - if (job) - queue_push(qout, job); - queue_push(qout, p); - } - } -} - -void -solver_get_userinstalled(Solver *solv, Queue *q, int flags) -{ - Pool *pool = solv->pool; - Id p, p2, pp; - Solvable *s; - Repo *installed = solv->installed; - int i, j; - Map userinstalled; - - map_init(&userinstalled, 0); - queue_empty(q); - /* first process jobs */ - for (i = 0; i < solv->job.count; i += 2) - { - Id how = solv->job.elements[i]; - Id what, select; - if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) - { - if (!userinstalled.size) - map_grow(&userinstalled, installed->end - installed->start); - what = solv->job.elements[i + 1]; - select = how & SOLVER_SELECTMASK; - if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) - FOR_REPO_SOLVABLES(installed, p, s) - MAPSET(&userinstalled, p - installed->start); - FOR_JOB_SELECT(p, pp, select, what) - if (pool->solvables[p].repo == installed) - MAPSET(&userinstalled, p - installed->start); - continue; - } - if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL) - continue; - if ((how & SOLVER_NOTBYUSER) != 0) - continue; - what = solv->job.elements[i + 1]; - select = how & SOLVER_SELECTMASK; - FOR_JOB_SELECT(p, pp, select, what) - if (solv->decisionmap[p] > 0) - { - queue_push(q, p); -#ifdef ENABLE_LINKED_PKGS - if (has_package_link(pool, pool->solvables + p)) - { - int j; - Queue lq; - queue_init(&lq); - find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0); - for (j = 0; j < lq.count; j++) - if (solv->decisionmap[lq.elements[j]] > 0) - queue_push(q, lq.elements[j]); - } -#endif - } - } - /* now process updates of userinstalled packages */ - if (installed && userinstalled.size) - { - for (i = 1; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p <= 0) - continue; - s = pool->solvables + p; - if (!s->repo) - continue; - if (s->repo == installed) - { - if (MAPTST(&userinstalled, p - installed->start)) - queue_push(q, p); - continue; - } - /* new package, check if we replace a userinstalled one */ - FOR_PROVIDES(p2, pp, s->name) - { - Solvable *ps = pool->solvables + p2; - if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) - continue; - if (!pool->implicitobsoleteusesprovides && s->name != ps->name) - continue; - if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p); - break; - } - if (!p2 && s->repo != installed && s->obsoletes) - { - Id obs, *obsp = s->repo->idarraydata + s->obsoletes; - while ((obs = *obsp++) != 0) - { - FOR_PROVIDES(p2, pp, obs) - { - Solvable *ps = pool->solvables + p2; - if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) - continue; - if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) - continue; - if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) - continue; - queue_push(q, p); - break; - } - if (p2) - break; - } - } - } - } - map_free(&userinstalled); - - /* convert to desired output format */ - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - int qcount = q->count; - queue_insertn(q, 0, qcount, 0); - for (i = j = 0; i < qcount; i++) - { - s = pool->solvables + q->elements[i + qcount]; - q->elements[j++] = s->name; - q->elements[j++] = s->arch; - } - } - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - { - for (i = 0; i < q->count; i++) - { - s = pool->solvables + q->elements[i]; - q->elements[i] = s->name; - } - } - /* sort and unify */ - get_userinstalled_sort_uniq(pool, q, flags); - - /* invert if asked for */ - if ((flags & GET_USERINSTALLED_INVERTED) != 0) - { - /* first generate queue with all installed packages */ - Queue invq; - queue_init(&invq); - for (i = 1; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p <= 0) - continue; - s = pool->solvables + p; - if (!s->repo) - continue; - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - queue_push2(&invq, s->name, s->arch); - else if ((flags & GET_USERINSTALLED_NAMES) != 0) - queue_push(&invq, s->name); - else - queue_push(&invq, p); - } - /* push q on invq, just in case... */ - queue_insertn(&invq, invq.count, q->count, q->elements); - get_userinstalled_sort_uniq(pool, &invq, flags); - /* subtract queues (easy as they are sorted and invq is a superset of q) */ - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - if (q->count) - { - for (i = j = 0; i < invq.count; i += 2) - if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1]) - { - invq.elements[i] = invq.elements[i + 1] = 0; - j += 2; - if (j >= q->count) - break; - } - queue_empty(q); - } - for (i = 0; i < invq.count; i += 2) - if (invq.elements[i]) - queue_push2(q, invq.elements[i], invq.elements[i + 1]); - } - else - { - if (q->count) - { - for (i = j = 0; i < invq.count; i++) - if (invq.elements[i] == q->elements[j]) - { - invq.elements[i] = 0; - if (++j >= q->count) - break; - } - queue_empty(q); - } - for (i = 0; i < invq.count; i++) - if (invq.elements[i]) - queue_push(q, invq.elements[i]); - } - queue_free(&invq); - } -} - -void -pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) -{ - int i; - - if ((flags & GET_USERINSTALLED_INVERTED) != 0) - { - Queue invq; - Id p, lastid; - Solvable *s; - int bad; - if (!pool->installed) - return; - queue_init(&invq); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - flags &= ~GET_USERINSTALLED_NAMES; /* just in case */ - FOR_REPO_SOLVABLES(pool->installed, p, s) - queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p); - if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) - { - /* for namearch we convert to packages */ - namearch2solvables(pool, q, &invq, 0); - get_userinstalled_sort_uniq(pool, &invq, flags); - namearch2solvables(pool, q, &invq, 0); - flags = 0; - } - else - { - queue_insertn(&invq, invq.count, q->count, q->elements); - get_userinstalled_sort_uniq(pool, &invq, flags); - /* now the fun part, add q again, sort, and remove all dups */ - queue_insertn(&invq, invq.count, q->count, q->elements); - } - if (invq.count > 1) - { - if ((flags & GET_USERINSTALLED_NAMES) != 0) - solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool); - else - solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0); - } - lastid = -1; - bad = 1; - for (i = 0; i < invq.count; i++) - { - if (invq.elements[i] == lastid) - { - bad = 1; - continue; - } - if (!bad) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); - bad = 0; - lastid = invq.elements[i]; - } - if (!bad) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); - queue_free(&invq); - } - else - { - if (flags & GET_USERINSTALLED_NAMEARCH) - namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE); - else - { - for (i = 0; i < q->count; i++) - queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]); - } - } -} - int solver_alternatives_count(Solver *solv) { @@ -5160,6 +4707,12 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask) case SOLVER_ALLOWUNINSTALL: strstart = "allow deinstallation of "; break; + case SOLVER_FAVOR: + strstart = "favor "; + break; + case SOLVER_DISFAVOR: + strstart = "disfavor "; + break; default: strstart = "unknown job "; break; diff --git a/libsolv-0.6.15/src/solver.h b/libsolv-0.7.2/src/solver.h similarity index 90% rename from libsolv-0.6.15/src/solver.h rename to libsolv-0.7.2/src/solver.h index 2ae9c8d..6fc2e9f 100644 --- a/libsolv-0.6.15/src/solver.h +++ b/libsolv-0.7.2/src/solver.h @@ -26,11 +26,11 @@ extern "C" { #endif -struct _Solver { +struct s_Solver { Pool *pool; /* back pointer to pool */ Queue job; /* copy of the job we're solving */ - int (*solution_callback)(struct _Solver *solv, void *data); + int (*solution_callback)(struct s_Solver *solv, void *data); void *solution_callback_data; int pooljobcnt; /* number of pooljob entries in job queue */ @@ -44,6 +44,7 @@ struct _Solver { */ Rule *rules; /* all rules */ Id nrules; /* [Offset] index of the last rule */ + Id lastpkgrule; /* last package rule we added */ Queue ruleassertions; /* Queue of all assertion rules */ @@ -67,6 +68,7 @@ struct _Solver { Id duprules_end; Id bestrules; /* rules from SOLVER_FORCEBEST */ + Id bestrules_up; /* update rule part starts here*/ Id bestrules_end; Id *bestrules_pkg; @@ -107,19 +109,13 @@ struct _Solver { /* our decisions: */ Queue decisionq; /* >0:install, <0:remove/conflict */ Queue decisionq_why; /* index of rule, Offset into rules */ + Queue decisionq_reason; /* reason for decision, indexed by level */ Id *decisionmap; /* map for all available solvables, * = 0: undecided * > 0: level of decision when installed, * < 0: level of decision when conflict */ - int decisioncnt_jobs; - int decisioncnt_update; - int decisioncnt_keep; - int decisioncnt_resolve; - int decisioncnt_weak; - int decisioncnt_orphan; - /* learnt rule history */ Queue learnt_why; Queue learnt_pool; @@ -166,11 +162,17 @@ struct _Solver { int bestobeypolicy; /* true: stay in policy with the best rules */ int noautotarget; /* true: do not assume targeted for up/dup jobs that contain no installed solvable */ int focus_installed; /* true: resolve update rules first */ + int focus_best; /* true: resolve job dependencies first */ int do_yum_obsoletes; /* true: add special yumobs rules */ + int urpmreorder; /* true: do special urpm package reordering */ + int strongrecommends; /* true: create weak rules for recommends */ + int install_also_updates; /* true: do not prune install job rules to installed packages */ + int only_namespace_recommended; /* true: only install packages recommended by namespace */ - Map dupmap; /* dup these packages*/ - int dupmap_all; /* dup all packages */ + int process_orphans; /* true: do special orphan processing */ + Map dupmap; /* dup to those packages */ Map dupinvolvedmap; /* packages involved in dup process */ + int dupinvolvedmap_all; /* all packages are involved */ int dup_allowdowngrade; /* dup mode: allow to downgrade installed solvable */ int dup_allownamechange; /* dup mode: allow to change name of installed solvable */ int dup_allowarchchange; /* dup mode: allow to change architecture of installed solvables */ @@ -199,10 +201,18 @@ struct _Solver { Map allowuninstallmap; /* ok to uninstall those */ int allowuninstall_all; + Queue *favorq; + Map favormap; /* favored / disfavored packages */ + Map isdisfavormap; + + int installedpos; /* for resolve_installed */ + int do_extra_reordering; /* reorder for future installed packages */ + + Queue *recommendsruleq; /* pkg rules comming from recommends */ #endif /* LIBSOLV_INTERNAL */ }; -typedef struct _Solver Solver; +typedef struct s_Solver Solver; /* * queue commands @@ -229,6 +239,8 @@ typedef struct _Solver Solver; #define SOLVER_DROP_ORPHANED 0x0900 #define SOLVER_USERINSTALLED 0x0a00 #define SOLVER_ALLOWUNINSTALL 0x0b00 +#define SOLVER_FAVOR 0x0c00 +#define SOLVER_DISFAVOR 0x0d00 #define SOLVER_JOBMASK 0xff00 @@ -302,6 +314,11 @@ typedef struct _Solver Solver; #define SOLVER_FLAG_FOCUS_INSTALLED 20 #define SOLVER_FLAG_YUM_OBSOLETES 21 #define SOLVER_FLAG_NEED_UPDATEPROVIDE 22 +#define SOLVER_FLAG_URPM_REORDER 23 +#define SOLVER_FLAG_FOCUS_BEST 24 +#define SOLVER_FLAG_STRONG_RECOMMENDS 25 +#define SOLVER_FLAG_INSTALL_ALSO_UPDATES 26 +#define SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED 27 #define GET_USERINSTALLED_NAMES (1 << 0) /* package names instead of ids */ #define GET_USERINSTALLED_INVERTED (1 << 1) /* autoinstalled */ @@ -328,6 +345,7 @@ extern void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Qu extern void solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered); extern void solver_get_userinstalled(Solver *solv, Queue *q, int flags); extern void pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags); +extern void solver_get_cleandeps(Solver *solv, Queue *cleandepsq); extern int solver_describe_decision(Solver *solv, Id p, Id *infop); extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq); @@ -341,7 +359,6 @@ extern void solver_create_state_maps(Solver *solv, Map *installedmap, Map *confl extern void solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps); extern int solver_calc_installsizechange(Solver *solv); -extern void solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res); extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what); extern int pool_isemptyupdatejob(Pool *pool, Id how, Id what); @@ -377,6 +394,9 @@ extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from continue; \ else +/* weird suse stuff */ +extern void solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res); + #ifdef __cplusplus } #endif diff --git a/libsolv-0.7.2/src/solver_private.h b/libsolv-0.7.2/src/solver_private.h new file mode 100644 index 0000000..406b304 --- /dev/null +++ b/libsolv-0.7.2/src/solver_private.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * solver_private.h - private functions + * + */ + +#ifndef LIBSOLV_SOLVER_PRIVATE_H +#define LIBSOLV_SOLVER_PRIVATE_H + +extern void solver_run_sat(Solver *solv, int disablerules, int doweak); +extern void solver_reset(Solver *solv); + +extern int solver_splitprovides(Solver *solv, Id dep, Map *m); +extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m); +extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd); +extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s); +extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m); +extern int solver_is_namespace_dep_slow(Solver *solv, Reldep *rd); + +extern void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded); +extern int solver_check_cleandeps_mistakes(Solver *solv); + + +#define ISSIMPLEDEP(pool, dep) (!ISRELDEP(dep) || GETRELDEP(pool, dep)->flags < 8) + +static inline int +solver_dep_possible(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (!ISSIMPLEDEP(pool, dep)) + return solver_dep_possible_slow(solv, dep, m); + FOR_PROVIDES(p, pp, dep) + { + if (MAPTST(m, p)) + return 1; + } + return 0; +} + +static inline int +solver_dep_fulfilled(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR) + return solver_dep_fulfilled_cplx(solv, rd); + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, 0); + } + FOR_PROVIDES(p, pp, dep) + { + if (solv->decisionmap[p] > 0) + return 1; + } + return 0; +} + +static inline int +solver_is_supplementing(Solver *solv, Solvable *s) +{ + Id sup, *supp; + if (!s->supplements) + return 0; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + if (solver_dep_fulfilled(solv, sup)) + return 1; + return 0; +} + +static inline int +solver_is_enhancing(Solver *solv, Solvable *s) +{ + Id enh, *enhp; + if (!s->enhances) + return 0; + enhp = s->repo->idarraydata + s->enhances; + while ((enh = *enhp++) != 0) + if (solver_dep_fulfilled(solv, enh)) + return 1; + return 0; +} + +static inline int +solver_is_namespace_dep(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Reldep *rd; + if (!ISRELDEP(dep)) + return 0; + rd = GETRELDEP(pool, dep); + if (rd->flags == REL_NAMESPACE) + return 1; + if (ISRELDEP(rd->name)) + return solver_is_namespace_dep_slow(solv, rd); + if (ISRELDEP(rd->evr)) + return solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->evr)); + return 0; +} + +#endif /* LIBSOLV_SOLVER_PRIVATE_H */ diff --git a/libsolv-0.7.2/src/solver_util.c b/libsolv-0.7.2/src/solver_util.c new file mode 100644 index 0000000..fb17bf4 --- /dev/null +++ b/libsolv-0.7.2/src/solver_util.c @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2017, SUSE Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * solver_util.c + * + * Dependency solver helper functions + */ + +#include +#include +#include +#include + +#include "solver.h" +#include "solver_private.h" +#include "bitmap.h" +#include "pool.h" +#include "poolarch.h" +#include "util.h" + + +/*------------------------------------------------------------------- + * check if a installed package p is being updated + */ +static int +solver_is_updating(Solver *solv, Id p) +{ + /* check if the update rule is true */ + Pool *pool = solv->pool; + Rule *r; + Id l, pp; + if (solv->decisionmap[p] >= 0) + return 0; /* old package stayed */ + r = solv->rules + solv->updaterules + (p - solv->installed->start); + FOR_RULELITERALS(l, pp, r) + if (l > 0 && l != p && solv->decisionmap[l] > 0) + return 1; + return 0; +} + +/*------------------------------------------------------------------- + * handle split provides + * + * a splitprovides dep looks like + * namespace:splitprovides(pkg REL_WITH path) + * and is only true if pkg is installed and contains the specified path. + * we also make sure that pkg is selected for an update, otherwise the + * update would always be forced onto the user. + * Map m is the map used when called from dep_possible. + */ +int +solver_splitprovides(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + Reldep *rd; + Solvable *s; + + if (!solv->dosplitprovides || !solv->installed) + return 0; + if (!ISRELDEP(dep)) + return 0; + rd = GETRELDEP(pool, dep); + if (rd->flags != REL_WITH) + return 0; + /* + * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in + * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete + * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag + * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but + * we filter the package name further down anyway). + */ + if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr]) + pp = pool_searchlazywhatprovidesq(pool, rd->evr); + else + pp = pool_whatprovides(pool, dep); + while ((p = pool->whatprovidesdata[pp++]) != 0) + { + /* here we have packages that provide the correct name and contain the path, + * now do extra filtering */ + s = pool->solvables + p; + if (s->repo != solv->installed || s->name != rd->name) + continue; + /* check if the package is updated. if m is set, we're called from dep_possible */ + if (m || solver_is_updating(solv, p)) + return 1; + } + return 0; +} + +int +solver_dep_possible_slow(Solver *solv, Id dep, Map *m) +{ + Pool *pool = solv->pool; + Id p, pp; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags >= 8) + { + if (rd->flags == REL_COND || rd->flags == REL_UNLESS) + return 1; + if (rd->flags == REL_AND) + { + if (!solver_dep_possible_slow(solv, rd->name, m)) + return 0; + return solver_dep_possible_slow(solv, rd->evr, m); + } + if (rd->flags == REL_OR) + { + if (solver_dep_possible_slow(solv, rd->name, m)) + return 1; + return solver_dep_possible_slow(solv, rd->evr, m); + } + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, m); + } + } + FOR_PROVIDES(p, pp, dep) + { + if (MAPTST(m, p)) + return 1; + } + return 0; +} + +int +solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd) +{ + Pool *pool = solv->pool; + if (rd->flags == REL_COND) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + if (solver_dep_fulfilled(solv, rd2->name)) + return solver_dep_fulfilled(solv, rd->name); + return solver_dep_fulfilled(solv, rd2->evr); + } + } + if (solver_dep_fulfilled(solv, rd->name)) + return 1; + return !solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_UNLESS) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + if (!solver_dep_fulfilled(solv, rd2->name)) + return solver_dep_fulfilled(solv, rd->name); + return solver_dep_fulfilled(solv, rd2->evr); + } + } + if (!solver_dep_fulfilled(solv, rd->name)) + return 0; + return !solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_AND) + { + if (!solver_dep_fulfilled(solv, rd->name)) + return 0; + return solver_dep_fulfilled(solv, rd->evr); + } + if (rd->flags == REL_OR) + { + if (solver_dep_fulfilled(solv, rd->name)) + return 1; + return solver_dep_fulfilled(solv, rd->evr); + } + return 0; +} + +static int +solver_dep_fulfilled_complex_func(Solver *solv, Reldep *rd, int (*dep_fullfilled)(Solver *, Id)) +{ + Pool *pool = solv->pool; + int r1, r2; + if (rd->flags == REL_COND) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + r1 = dep_fullfilled(solv, rd2->name); + if (r1) + { + r2 = dep_fullfilled(solv, rd->name); + return r2 && r1 == 2 ? 2 : r2; + } + return dep_fullfilled(solv, rd2->evr); + } + } + r1 = dep_fullfilled(solv, rd->name); + r2 = !dep_fullfilled(solv, rd->evr); + if (!r1 && !r2) + return 0; + return r1 == 2 ? 2 : 1; + } + if (rd->flags == REL_UNLESS) + { + if (ISRELDEP(rd->evr)) + { + Reldep *rd2 = GETRELDEP(pool, rd->evr); + if (rd2->flags == REL_ELSE) + { + r1 = dep_fullfilled(solv, rd2->name); + if (r1) + { + r2 = dep_fullfilled(solv, rd2->evr); + return r2 && r1 == 2 ? 2 : r2; + } + return dep_fullfilled(solv, rd->name); + } + } + /* A AND NOT(B) */ + r1 = dep_fullfilled(solv, rd->name); + r2 = !dep_fullfilled(solv, rd->evr); + if (!r1 || !r2) + return 0; + return r1 == 2 ? 2 : 1; + } + if (rd->flags == REL_AND) + { + r1 = dep_fullfilled(solv, rd->name); + if (!r1) + return 0; + r2 = dep_fullfilled(solv, rd->evr); + if (!r2) + return 0; + return r1 == 2 || r2 == 2 ? 2 : 1; + } + if (rd->flags == REL_OR) + { + r1 = dep_fullfilled(solv, rd->name); + r2 = dep_fullfilled(solv, rd->evr); + if (!r1 && !r2) + return 0; + return r1 == 2 || r2 == 2 ? 2 : 1; + } + return 0; +} + +/* mirrors solver_dep_fulfilled, but returns 2 if a new package + * was involved */ +static int +solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + int r; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR) + return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_alreadyinstalled); + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0; + if (rd->flags == REL_NAMESPACE && solv->installsuppdepq) + { + Queue *q = solv->installsuppdepq; + int i; + for (i = 0; i < q->count; i++) + if (q->elements[i] == dep || q->elements[i] == rd->name) + return 2; + } + } + r = 0; + FOR_PROVIDES(p, pp, dep) + if (solv->decisionmap[p] > 0) + { + Solvable *s = pool->solvables + p; + if (s->repo && s->repo != solv->installed) + return 2; + r = 1; + } + return r; +} + +static int +solver_dep_fulfilled_namespace(Solver *solv, Id dep) +{ + Pool *pool = solv->pool; + Id p, pp; + int r = 1; + + if (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR) + return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_namespace); + if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES) + return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0; + if (rd->flags == REL_NAMESPACE) + r = 2; + } + FOR_PROVIDES(p, pp, dep) + if (solv->decisionmap[p] > 0) + return r; + return 0; +} + +int +solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s) +{ + Id sup, *supp; + supp = s->repo->idarraydata + s->supplements; + while ((sup = *supp++) != 0) + { + if (!solv->addalreadyrecommended && solver_dep_fulfilled_alreadyinstalled(solv, sup) != 2) + continue; + if (solv->only_namespace_recommended && solver_dep_fulfilled_namespace(solv, sup) != 2) + continue; + return 1; + } + return 0; +} + +int +solver_is_namespace_dep_slow(Solver *solv, Reldep *rd) +{ + Pool *pool = solv->pool; + for (;;) + { + if (rd->flags == REL_NAMESPACE) + return 1; + if (ISRELDEP(rd->name) && solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->name))) + return 1; + if (!ISRELDEP(rd->evr)) + return 0; + rd = GETRELDEP(pool, rd->evr); + } +} + +/* + * add all installed packages that package p obsoletes to Queue q. + * Package p is not installed. Also, we know that if + * solv->keepexplicitobsoletes is not set, p is not in the multiversion map. + * Entries may get added multiple times. + */ +static void +solver_add_obsoleted(Solver *solv, Id p, Queue *q) +{ + Pool *pool = solv->pool; + Repo *installed = solv->installed; + Id p2, pp2; + Solvable *s = pool->solvables + p; + Id obs, *obsp; + Id lastp2 = 0; + + if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p))) + { + FOR_PROVIDES(p2, pp2, s->name) + { + Solvable *ps = pool->solvables + p2; + if (ps->repo != installed) + continue; + if (!pool->implicitobsoleteusesprovides && ps->name != s->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p2); + lastp2 = p2; + } + } + if (!s->obsoletes) + return; + obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + FOR_PROVIDES(p2, pp2, obs) + { + Solvable *ps = pool->solvables + p2; + if (ps->repo != installed) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + if (p2 == lastp2) + continue; + queue_push(q, p2); + lastp2 = p2; + } +} + +/* + * Call solver_add_obsoleted and intersect the result with the + * elements in Queue q starting at qstart. + * Assumes that it's the first call if qstart == q->count. + * May use auxillary map m for the intersection process, all + * elements of q starting at qstart must have their bit cleared. + * (This is also true after the function returns.) + * (See solver_add_obsoleted for limitations of the package p) + */ +void +solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m) +{ + int i, j; + int qcount = q->count; + + solver_add_obsoleted(solv, p, q); + if (qcount == qstart) + return; /* first call */ + if (qcount == q->count) + j = qstart; + else if (qcount == qstart + 1) + { + /* easy if there's just one element */ + j = qstart; + for (i = qcount; i < q->count; i++) + if (q->elements[i] == q->elements[qstart]) + { + j++; /* keep the element */ + break; + } + } + else if (!m || (!m->size && q->count - qstart <= 8)) + { + /* faster than a map most of the time */ + int k; + for (i = j = qstart; i < qcount; i++) + { + Id ip = q->elements[i]; + for (k = qcount; k < q->count; k++) + if (q->elements[k] == ip) + { + q->elements[j++] = ip; + break; + } + } + } + else + { + /* for the really pathologic cases we use the map */ + Repo *installed = solv->installed; + if (!m->size) + map_init(m, installed->end - installed->start); + for (i = qcount; i < q->count; i++) + MAPSET(m, q->elements[i] - installed->start); + for (i = j = qstart; i < qcount; i++) + if (MAPTST(m, q->elements[i] - installed->start)) + { + MAPCLR(m, q->elements[i] - installed->start); + q->elements[j++] = q->elements[i]; + } + } + queue_truncate(q, j); +} + diff --git a/libsolv-0.6.15/src/solverdebug.c b/libsolv-0.7.2/src/solverdebug.c similarity index 95% rename from libsolv-0.6.15/src/solverdebug.c rename to libsolv-0.7.2/src/solverdebug.c index 39f5d78..bb74ef6 100644 --- a/libsolv-0.6.15/src/solverdebug.c +++ b/libsolv-0.7.2/src/solverdebug.c @@ -568,36 +568,3 @@ solver_printallsolutions(Solver *solv) } } -void -solver_printtrivial(Solver *solv) -{ - Pool *pool = solv->pool; - Queue in, out; - Id p; - const char *n; - Solvable *s; - int i; - - queue_init(&in); - for (p = 1, s = pool->solvables + p; p < solv->pool->nsolvables; p++, s++) - { - n = pool_id2str(pool, s->name); - if (strncmp(n, "patch:", 6) != 0 && strncmp(n, "pattern:", 8) != 0) - continue; - queue_push(&in, p); - } - if (!in.count) - { - queue_free(&in); - return; - } - queue_init(&out); - solver_trivial_installable(solv, &in, &out); - POOL_DEBUG(SOLV_DEBUG_RESULT, "trivial installable status:\n"); - for (i = 0; i < in.count; i++) - POOL_DEBUG(SOLV_DEBUG_RESULT, " %s: %d\n", pool_solvid2str(pool, in.elements[i]), out.elements[i]); - POOL_DEBUG(SOLV_DEBUG_RESULT, "\n"); - queue_free(&in); - queue_free(&out); -} - diff --git a/libsolv-0.6.15/src/solverdebug.h b/libsolv-0.7.2/src/solverdebug.h similarity index 98% rename from libsolv-0.6.15/src/solverdebug.h rename to libsolv-0.7.2/src/solverdebug.h index 32e427e..b6923b4 100644 --- a/libsolv-0.6.15/src/solverdebug.h +++ b/libsolv-0.7.2/src/solverdebug.h @@ -33,10 +33,12 @@ extern void solver_printprobleminfo(Solver *solv, Id problem); extern void solver_printcompleteprobleminfo(Solver *solv, Id problem); extern void solver_printsolution(Solver *solv, Id problem, Id solution); extern void solver_printallsolutions(Solver *solv); -extern void solver_printtrivial(Solver *solv); extern void transaction_print(Transaction *trans); +/* weird suse stuff */ +extern void solver_printtrivial(Solver *solv); + #ifdef __cplusplus } #endif diff --git a/libsolv-0.6.15/src/solvversion.c b/libsolv-0.7.2/src/solvversion.c similarity index 100% rename from libsolv-0.6.15/src/solvversion.c rename to libsolv-0.7.2/src/solvversion.c diff --git a/libsolv-0.7.2/src/solvversion.h.in b/libsolv-0.7.2/src/solvversion.h.in new file mode 100644 index 0000000..4caba47 --- /dev/null +++ b/libsolv-0.7.2/src/solvversion.h.in @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * solvversion.h + * + */ + +#ifndef LIBSOLV_SOLVVERSION_H +#define LIBSOLV_SOLVVERSION_H + +#define LIBSOLV_VERSION_STRING "@VERSION@" +#define LIBSOLV_VERSION_MAJOR @LIBSOLV_MAJOR@ +#define LIBSOLV_VERSION_MINOR @LIBSOLV_MINOR@ +#define LIBSOLV_VERSION_PATCH @LIBSOLV_PATCH@ +#define LIBSOLV_VERSION (LIBSOLV_VERSION_MAJOR * 10000 + LIBSOLV_VERSION_MINOR * 100 + LIBSOLV_VERSION_PATCH) + +extern const char solv_version[]; +extern int solv_version_major; +extern int solv_version_minor; +extern int solv_version_patch; + +#cmakedefine LIBSOLV_FEATURE_LINKED_PKGS +#cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS +#cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS + +#cmakedefine LIBSOLVEXT_FEATURE_RPMPKG +#cmakedefine LIBSOLVEXT_FEATURE_RPMDB +#cmakedefine LIBSOLVEXT_FEATURE_RPMDB_BYRPMHEADER +#cmakedefine LIBSOLVEXT_FEATURE_PUBKEY +#cmakedefine LIBSOLVEXT_FEATURE_RPMMD +#cmakedefine LIBSOLVEXT_FEATURE_SUSEREPO +#cmakedefine LIBSOLVEXT_FEATURE_COMPS +#cmakedefine LIBSOLVEXT_FEATURE_HELIXREPO +#cmakedefine LIBSOLVEXT_FEATURE_DEBIAN +#cmakedefine LIBSOLVEXT_FEATURE_ARCHREPO +#cmakedefine LIBSOLVEXT_FEATURE_HAIKU +#cmakedefine LIBSOLVEXT_FEATURE_APPDATA +#cmakedefine LIBSOLVEXT_FEATURE_ZLIB_COMPRESSION +#cmakedefine LIBSOLVEXT_FEATURE_LZMA_COMPRESSION +#cmakedefine LIBSOLVEXT_FEATURE_BZIP2_COMPRESSION +#cmakedefine LIBSOLVEXT_FEATURE_ZSTD_COMPRESSION + +/* see tools/common_write.c for toolversion history */ +#define LIBSOLV_TOOLVERSION "1.1" + +#endif diff --git a/libsolv-0.6.15/src/strpool.c b/libsolv-0.7.2/src/strpool.c similarity index 82% rename from libsolv-0.6.15/src/strpool.c rename to libsolv-0.7.2/src/strpool.c index af43e01..b4a09a5 100644 --- a/libsolv-0.6.15/src/strpool.c +++ b/libsolv-0.7.2/src/strpool.c @@ -56,11 +56,7 @@ stringpool_freehash(Stringpool *ss) void stringpool_init_empty(Stringpool *ss) { - const char *emptystrs[] = { - "", - "", - 0, - }; + static const char *emptystrs[] = { "", "", 0 }; stringpool_init(ss, emptystrs); } @@ -76,11 +72,39 @@ stringpool_clone(Stringpool *ss, Stringpool *from) ss->sstrings = from->sstrings; } +void +stringpool_resize_hash(Stringpool *ss, int numnew) +{ + Hashval h, hh, hashmask; + Hashtable hashtbl; + int i; + + if (numnew <= 0) + return; + hashmask = mkmask(ss->nstrings + numnew); + if (hashmask <= ss->stringhashmask) + return; /* same as before */ + + /* realloc hash table */ + ss->stringhashmask = hashmask; + solv_free(ss->stringhashtbl); + ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id)); + + /* rehash all strings into new hashtable */ + for (i = 1; i < ss->nstrings; i++) + { + h = strhash(ss->stringspace + ss->strings[i]) & hashmask; + hh = HASHCHAIN_START; + while (hashtbl[h] != 0) + h = HASHCHAIN_NEXT(h, hh, hashmask); + hashtbl[h] = i; + } +} + Id stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create) { Hashval h, hh, hashmask, oldhashmask; - int i; Id id; Hashtable hashtbl; @@ -90,27 +114,13 @@ stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create return STRID_EMPTY; hashmask = oldhashmask = ss->stringhashmask; - hashtbl = ss->stringhashtbl; - /* expand hashtable if needed */ if ((Hashval)ss->nstrings * 2 > hashmask) { - solv_free(hashtbl); - - /* realloc hash table */ - ss->stringhashmask = hashmask = mkmask(ss->nstrings + STRING_BLOCK); - ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id)); - - /* rehash all strings into new hashtable */ - for (i = 1; i < ss->nstrings; i++) - { - h = strhash(ss->stringspace + ss->strings[i]) & hashmask; - hh = HASHCHAIN_START; - while (hashtbl[h] != 0) - h = HASHCHAIN_NEXT(h, hh, hashmask); - hashtbl[h] = i; - } + stringpool_resize_hash(ss, STRING_BLOCK); + hashmask = ss->stringhashmask; } + hashtbl = ss->stringhashtbl; /* compute hash and check for match */ h = strnhash(str, len) & hashmask; diff --git a/libsolv-0.6.15/src/strpool.h b/libsolv-0.7.2/src/strpool.h similarity index 94% rename from libsolv-0.6.15/src/strpool.h rename to libsolv-0.7.2/src/strpool.h index c97b873..fd13bdb 100644 --- a/libsolv-0.6.15/src/strpool.h +++ b/libsolv-0.7.2/src/strpool.h @@ -17,7 +17,7 @@ extern "C" { #define STRID_NULL 0 #define STRID_EMPTY 1 -struct _Stringpool +struct s_Stringpool { Offset *strings; /* table of offsets into stringspace, indexed by Id: Id -> Offset */ int nstrings; /* number of ids in strings table */ @@ -33,6 +33,7 @@ void stringpool_init_empty(Stringpool *ss); void stringpool_clone(Stringpool *ss, Stringpool *from); void stringpool_free(Stringpool *ss); void stringpool_freehash(Stringpool *ss); +void stringpool_resize_hash(Stringpool *ss, int numnew); Id stringpool_str2id(Stringpool *ss, const char *str, int create); Id stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create); diff --git a/libsolv-0.7.2/src/suse.c b/libsolv-0.7.2/src/suse.c new file mode 100644 index 0000000..9537a33 --- /dev/null +++ b/libsolv-0.7.2/src/suse.c @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2016, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* weird SUSE stuff. better not use it for your projects. */ + +#include +#include +#include +#include + +#include "solver.h" +#include "solver_private.h" +#include "bitmap.h" +#include "pool.h" +#include "poolvendor.h" +#include "util.h" + +Offset +repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens) +{ + Pool *pool = repo->pool; + Id id, idp, idl; + char buf[1024], *p, *dep; + int i, l; + + if (provides) + { + for (i = provides; repo->idarraydata[i]; i++) + { + id = repo->idarraydata[i]; + if (ISRELDEP(id)) + continue; + dep = (char *)pool_id2str(pool, id); + if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2) + { + idp = 0; + strcpy(buf + 2, dep); + dep = buf + 2 + 7; + if ((p = strchr(dep, ':')) != 0 && p != dep) + { + *p++ = 0; + idp = pool_str2id(pool, dep, 1); + dep = p; + } + id = 0; + while ((p = strchr(dep, ';')) != 0) + { + if (p == dep) + { + dep = p + 1; + continue; + } + *p++ = 0; + idl = pool_str2id(pool, dep, 1); + idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); + if (id) + id = pool_rel2id(pool, id, idl, REL_OR, 1); + else + id = idl; + dep = p; + } + if (dep[0] && dep[1]) + { + for (p = dep; *p && *p != ')'; p++) + ; + *p = 0; + idl = pool_str2id(pool, dep, 1); + idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); + if (id) + id = pool_rel2id(pool, id, idl, REL_OR, 1); + else + id = idl; + } + if (idp) + id = pool_rel2id(pool, idp, id, REL_AND, 1); + if (id) + supplements = repo_addid_dep(repo, supplements, id, 0); + } + else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf)) + { + strcpy(buf, dep); + p = buf + (p - dep); + *p++ = 0; + idp = pool_str2id(pool, buf, 1); + /* strip trailing slashes */ + l = strlen(p); + while (l > 1 && p[l - 1] == '/') + p[--l] = 0; + id = pool_str2id(pool, p, 1); + id = pool_rel2id(pool, idp, id, REL_WITH, 1); + id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1); + supplements = repo_addid_dep(repo, supplements, id, 0); + } + } + } + if (supplements) + { + for (i = supplements; repo->idarraydata[i]; i++) + { + id = repo->idarraydata[i]; + if (ISRELDEP(id)) + continue; + dep = (char *)pool_id2str(pool, id); + if (!strncmp(dep, "system:modalias(", 16)) + dep += 7; + if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf)) + { + strcpy(buf, dep); + p = strchr(buf + 9, ':'); + if (p && p != buf + 9 && strchr(p + 1, ':')) + { + *p++ = 0; + idp = pool_str2id(pool, buf + 9, 1); + p[strlen(p) - 1] = 0; + id = pool_str2id(pool, p, 1); + id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); + id = pool_rel2id(pool, idp, id, REL_AND, 1); + } + else + { + p = buf + 9; + p[strlen(p) - 1] = 0; + id = pool_str2id(pool, p, 1); + id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); + } + if (id) + repo->idarraydata[i] = id; + } + else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf)) + { + strcpy(buf, dep); + id = 0; + dep = buf + 11; + while ((p = strchr(dep, ':')) != 0) + { + if (p == dep) + { + dep = p + 1; + continue; + } + /* argh, allow pattern: prefix. sigh */ + if (p - dep == 7 && !strncmp(dep, "pattern", 7)) + { + p = strchr(p + 1, ':'); + if (!p) + break; + } + *p++ = 0; + idp = pool_str2id(pool, dep, 1); + if (id) + id = pool_rel2id(pool, id, idp, REL_AND, 1); + else + id = idp; + dep = p; + } + if (dep[0] && dep[1]) + { + dep[strlen(dep) - 1] = 0; + idp = pool_str2id(pool, dep, 1); + if (id) + id = pool_rel2id(pool, id, idp, REL_AND, 1); + else + id = idp; + } + if (id) + repo->idarraydata[i] = id; + } + else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf)) + { + strcpy(buf, dep + 11); + if ((p = strrchr(buf, ')')) != 0) + *p = 0; + id = pool_str2id(pool, buf, 1); + id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1); + repo->idarraydata[i] = id; + } + } + } + if (freshens && repo->idarraydata[freshens]) + { + Id idsupp = 0, idfresh = 0; + if (!supplements || !repo->idarraydata[supplements]) + return freshens; + for (i = supplements; repo->idarraydata[i]; i++) + { + if (!idsupp) + idsupp = repo->idarraydata[i]; + else + idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1); + } + for (i = freshens; repo->idarraydata[i]; i++) + { + if (!idfresh) + idfresh = repo->idarraydata[i]; + else + idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1); + } + if (!idsupp) + idsupp = idfresh; + else + idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1); + supplements = repo_addid_dep(repo, 0, idsupp, 0); + } + return supplements; +} + +Offset +repo_fix_conflicts(Repo *repo, Offset conflicts) +{ + char buf[1024], *dep; + Pool *pool = repo->pool; + Id id; + int i; + + if (!conflicts) + return conflicts; + for (i = conflicts; repo->idarraydata[i]; i++) + { + id = repo->idarraydata[i]; + if (ISRELDEP(id)) + continue; + dep = (char *)pool_id2str(pool, id); + if (!strncmp(dep, "otherproviders(", 15) && dep[15] && strlen(dep) < sizeof(buf) - 2) + { + strcpy(buf, dep + 15); + buf[strlen(buf) - 1] = 0; + id = pool_str2id(pool, buf, 1); + id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1); + repo->idarraydata[i] = id; + } + } + return conflicts; +} + +void +repo_rewrite_suse_deps(Solvable *s, Offset freshens) +{ + s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, freshens); + if (s->conflicts) + s->conflicts = repo_fix_conflicts(s->repo, s->conflicts); +} + +/**********************************************************************************/ + +static inline Id +dep2name(Pool *pool, Id dep) +{ + while (ISRELDEP(dep)) + { + Reldep *rd = GETRELDEP(pool, dep); + dep = rd->name; + } + return dep; +} + +static int +providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) +{ + Id p, pp; + Solvable *sn = pool->solvables + n; + + FOR_PROVIDES(p, pp, sn->name) + { + Solvable *s = pool->solvables + p; + if (s->name != sn->name || s->arch != sn->arch) + continue; + if (!MAPTST(installed, p)) + continue; + if (pool_match_nevr(pool, pool->solvables + p, con)) + continue; + return 1; /* found installed package that doesn't conflict */ + } + return 0; +} + +static inline int +providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap) +{ + Id p, pp; + FOR_PROVIDES(p, pp, dep) + { + if (p == SYSTEMSOLVABLE) + return -1; + if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) + continue; + if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep)) + if (providedbyinstalled_multiversion(pool, installed, p, dep)) + continue; + if (MAPTST(installed, p)) + return 1; + } + return 0; +} + +/* xmap: + * 1: installed + * 2: conflicts with installed + * 8: interesting (only true if installed) + * 16: undecided + */ + +static int +providedbyinstalled_multiversion_xmap(Pool *pool, unsigned char *map, Id n, Id con) +{ + Id p, pp; + Solvable *sn = pool->solvables + n; + + FOR_PROVIDES(p, pp, sn->name) + { + Solvable *s = pool->solvables + p; + if (s->name != sn->name || s->arch != sn->arch) + continue; + if ((map[p] & 9) != 9) + continue; + if (pool_match_nevr(pool, pool->solvables + p, con)) + continue; + return 1; /* found installed package that doesn't conflict */ + } + return 0; +} + + +static inline int +providedbyinstalled_xmap(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap) +{ + Id p, pp; + int r = 0; + FOR_PROVIDES(p, pp, dep) + { + if (p == SYSTEMSOLVABLE) + return 1; /* always boring, as never constraining */ + if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) + continue; + if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep)) + if (providedbyinstalled_multiversion_xmap(pool, map, p, dep)) + continue; + if ((map[p] & 9) == 9) + return 9; + r |= map[p] & 17; + } + return r; +} + +/* FIXME: this mirrors policy_illegal_vendorchange */ +static int +pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2) +{ + Id v1, v2; + Id vendormask1, vendormask2; + + if (pool->custom_vendorcheck) + return pool->custom_vendorcheck(pool, s1, s2); + /* treat a missing vendor as empty string */ + v1 = s1->vendor ? s1->vendor : ID_EMPTY; + v2 = s2->vendor ? s2->vendor : ID_EMPTY; + if (v1 == v2) + return 0; + vendormask1 = pool_vendor2mask(pool, v1); + if (!vendormask1) + return 1; /* can't match */ + vendormask2 = pool_vendor2mask(pool, v2); + if ((vendormask1 & vendormask2) != 0) + return 0; + return 1; /* no class matches */ +} + +/* check if this patch is relevant according to the vendor. To bad that patches + * don't have a vendor, so we need to do some careful repo testing. */ +int +solvable_is_irrelevant_patch(Solvable *s, Map *installedmap) +{ + Pool *pool = s->repo->pool; + Id con, *conp; + int hadpatchpackage = 0; + + if (!s->conflicts) + return 0; + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + Reldep *rd; + Id p, pp, p2, pp2; + if (!ISRELDEP(con)) + continue; + rd = GETRELDEP(pool, con); + if (rd->flags != REL_LT) + continue; + FOR_PROVIDES(p, pp, con) + { + Solvable *si; + if (!MAPTST(installedmap, p)) + continue; + si = pool->solvables + p; + if (!pool_match_nevr(pool, si, con)) + continue; + FOR_PROVIDES(p2, pp2, rd->name) + { + Solvable *s2 = pool->solvables + p2; + if (!pool_match_nevr(pool, s2, rd->name)) + continue; + if (pool_match_nevr(pool, s2, con)) + continue; /* does not fulfill patch */ + if (s2->repo == s->repo) + { + hadpatchpackage = 1; + /* ok, we have a package from the patch repo that solves the conflict. check vendor */ + if (si->vendor == s2->vendor) + return 0; + if (!pool_illegal_vendorchange(pool, si, s2)) + return 0; + /* vendor change was illegal, ignore conflict */ + } + } + } + } + /* if we didn't find a patchpackage don't claim that the patch is irrelevant */ + if (!hadpatchpackage) + return 0; + return 1; +} + +/* + * solvable_trivial_installable_map - answers if a solvable is installable + * without any other installs/deinstalls. + * The packages considered to be installed are provided via the + * installedmap bitmap. A additional "conflictsmap" bitmap providing + * information about the conflicts of the installed packages can be + * used for extra speed up. Provide a NULL pointer if you do not + * have this information. + * Both maps can be created with pool_create_state_maps() or + * solver_create_state_maps(). + * + * returns: + * 1: solvable is installable without any other package changes + * 0: solvable is not installable + * -1: solvable is installable, but doesn't constrain any installed packages + */ +int +solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap) +{ + Pool *pool = s->repo->pool; + Solvable *s2; + Id p, *dp; + Id *reqp, req; + Id *conp, con; + int r, interesting = 0; + + if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables)) + return 0; + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + if (req == SOLVABLE_PREREQMARKER) + continue; + r = providedbyinstalled(pool, installedmap, req, 0, 0); + if (!r) + return 0; + if (r > 0) + interesting = 1; + } + } + if (s->conflicts) + { + int ispatch = 0; + + if (!strncmp("patch:", pool_id2str(pool, s->name), 6)) + ispatch = 1; + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap)) + { + if (ispatch && solvable_is_irrelevant_patch(s, installedmap)) + return -1; + return 0; + } + if (!interesting && ISRELDEP(con)) + { + con = dep2name(pool, con); + if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap)) + interesting = 1; + } + } + if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap)) + interesting = 0; + } + if (!conflictsmap) + { + int i; + + p = s - pool->solvables; + for (i = 1; i < pool->nsolvables; i++) + { + if (!MAPTST(installedmap, i)) + continue; + s2 = pool->solvables + i; + if (!s2->conflicts) + continue; + conp = s2->repo->idarraydata + s2->conflicts; + while ((con = *conp++) != 0) + { + dp = pool_whatprovides_ptr(pool, con); + for (; *dp; dp++) + if (*dp == p) + return 0; + } + } + } + return interesting ? 1 : -1; +} + +/* + * different interface for solvable_trivial_installable_map, where + * the information about the installed packages is provided + * by a queue. + */ +int +solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap) +{ + Pool *pool = s->repo->pool; + int i; + Id p; + Map installedmap; + int r; + + map_init(&installedmap, pool->nsolvables); + for (i = 0; i < installed->count; i++) + { + p = installed->elements[i]; + if (p > 0) /* makes it work with decisionq */ + MAPSET(&installedmap, p); + } + r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap); + map_free(&installedmap); + return r; +} + +/* + * different interface for solvable_trivial_installable_map, where + * the information about the installed packages is provided + * by a repo containing the installed solvables. + */ +int +solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap) +{ + Pool *pool = s->repo->pool; + Id p; + Solvable *s2; + Map installedmap; + int r; + + map_init(&installedmap, pool->nsolvables); + FOR_REPO_SOLVABLES(installed, p, s2) + MAPSET(&installedmap, p); + r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap); + map_free(&installedmap); + return r; +} + +/* + * pool_trivial_installable - calculate if a set of solvables is + * trivial installable without any other installs/deinstalls of + * packages not belonging to the set. + * + * the state is returned in the result queue: + * 1: solvable is installable without any other package changes + * 0: solvable is not installable + * -1: solvable is installable, but doesn't constrain any installed packages + */ + +void +pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap) +{ + int i, r, m, did; + Id p, *dp, con, *conp, req, *reqp; + unsigned char *map; + Solvable *s; + + map = solv_calloc(pool->nsolvables, 1); + for (p = 1; p < pool->nsolvables; p++) + { + if (!MAPTST(installedmap, p)) + continue; + map[p] |= 9; + s = pool->solvables + p; + if (!s->conflicts) + continue; + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + dp = pool_whatprovides_ptr(pool, con); + for (; *dp; dp++) + map[p] |= 2; /* XXX: self conflict ? */ + } + } + for (i = 0; i < pkgs->count; i++) + map[pkgs->elements[i]] = 16; + + for (i = 0, did = 0; did < pkgs->count; i++, did++) + { + if (i == pkgs->count) + i = 0; + p = pkgs->elements[i]; + if ((map[p] & 16) == 0) + continue; + if ((map[p] & 2) != 0) + { + map[p] = 2; + continue; + } + s = pool->solvables + p; + m = 1; + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + if (req == SOLVABLE_PREREQMARKER) + continue; + r = providedbyinstalled_xmap(pool, map, req, 0, 0); + if (!r) + { + /* decided and miss */ + map[p] = 2; + did = 0; + break; + } + if (r == 16) + break; /* undecided */ + m |= r; /* 1 | 9 | 17 */ + } + if (req) + continue; + if ((m & 9) == 9) + m = 9; + } + if (s->conflicts) + { + int ispatch = 0; /* see solver.c patch handling */ + + if (!strncmp("patch:", pool_id2str(pool, s->name), 6)) + ispatch = 1; + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0) + { + map[p] = 2; + did = 0; + break; + } + if ((m == 1 || m == 17) && ISRELDEP(con)) + { + con = dep2name(pool, con); + if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0) + m = 9; + } + } + if (con) + continue; /* found a conflict */ + } + if (m != map[p]) + { + map[p] = m; + did = 0; + } + } + queue_free(res); + queue_init_clone(res, pkgs); + for (i = 0; i < pkgs->count; i++) + { + m = map[pkgs->elements[i]]; + if ((m & 9) == 9) + r = 1; + else if (m & 1) + r = -1; + else + r = 0; + res->elements[i] = r; + } + free(map); +} + +void +pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res) +{ + pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0); +} + +void +solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res) +{ + Pool *pool = solv->pool; + Map installedmap; + int i; + pool_create_state_maps(pool, &solv->decisionq, &installedmap, 0); + pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0); + for (i = 0; i < res->count; i++) + if (res->elements[i] != -1) + { + Solvable *s = pool->solvables + pkgs->elements[i]; + if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap)) + res->elements[i] = -1; + } + map_free(&installedmap); +} + +void +solver_printtrivial(Solver *solv) +{ + Pool *pool = solv->pool; + Queue in, out; + Id p; + const char *n; + Solvable *s; + int i; + + queue_init(&in); + for (p = 1, s = pool->solvables + p; p < solv->pool->nsolvables; p++, s++) + { + n = pool_id2str(pool, s->name); + if (strncmp(n, "patch:", 6) != 0 && strncmp(n, "pattern:", 8) != 0) + continue; + queue_push(&in, p); + } + if (!in.count) + { + queue_free(&in); + return; + } + queue_init(&out); + solver_trivial_installable(solv, &in, &out); + POOL_DEBUG(SOLV_DEBUG_RESULT, "trivial installable status:\n"); + for (i = 0; i < in.count; i++) + POOL_DEBUG(SOLV_DEBUG_RESULT, " %s: %d\n", pool_solvid2str(pool, in.elements[i]), out.elements[i]); + POOL_DEBUG(SOLV_DEBUG_RESULT, "\n"); + queue_free(&in); + queue_free(&out); +} + + diff --git a/libsolv-0.6.15/src/transaction.c b/libsolv-0.7.2/src/transaction.c similarity index 99% rename from libsolv-0.6.15/src/transaction.c rename to libsolv-0.7.2/src/transaction.c index ffe1ec2..4a4189e 100644 --- a/libsolv-0.6.15/src/transaction.c +++ b/libsolv-0.7.2/src/transaction.c @@ -56,6 +56,14 @@ obsq_sortcmp(const void *ap, const void *bp, void *dp) r = pool_evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE); if (r) return -r; /* highest version first */ + if (oas->arch != obs->arch) + { + /* bring same arch to front */ + if (oas->arch == s->arch) + return -1; + if (obs->arch == s->arch) + return 1; + } return oa - ob; } @@ -820,11 +828,11 @@ transaction_make_installedmap(Transaction *trans, Map *installedmap) } } -int +long long transaction_calc_installsizechange(Transaction *trans) { Map installedmap; - int change; + long long change; transaction_make_installedmap(trans, &installedmap); change = pool_calc_installsizechange(trans->pool, &installedmap); diff --git a/libsolv-0.6.15/src/transaction.h b/libsolv-0.7.2/src/transaction.h similarity index 89% rename from libsolv-0.6.15/src/transaction.h rename to libsolv-0.7.2/src/transaction.h index c840838..5b01354 100644 --- a/libsolv-0.6.15/src/transaction.h +++ b/libsolv-0.7.2/src/transaction.h @@ -21,12 +21,12 @@ extern "C" { #endif -struct _Pool; -struct _DUChanges; -struct _TransactionOrderdata; +struct s_Pool; +struct s_DUChanges; +struct s_TransactionOrderdata; -typedef struct _Transaction { - struct _Pool *pool; /* back pointer to pool */ +typedef struct s_Transaction { + struct s_Pool *pool; /* back pointer to pool */ Queue steps; /* the transaction steps */ @@ -36,7 +36,7 @@ typedef struct _Transaction { Map transactsmap; Map multiversionmap; - struct _TransactionOrderdata *orderdata; + struct s_TransactionOrderdata *orderdata; #endif } Transaction; @@ -92,8 +92,8 @@ typedef struct _Transaction { #define SOLVER_ORDERCYCLE_NORMAL 1 #define SOLVER_ORDERCYCLE_CRITICAL 2 -extern Transaction *transaction_create(struct _Pool *pool); -extern Transaction *transaction_create_decisionq(struct _Pool *pool, Queue *decisionq, Map *multiversionmap); +extern Transaction *transaction_create(struct s_Pool *pool); +extern Transaction *transaction_create_decisionq(struct s_Pool *pool, Queue *decisionq, Map *multiversionmap); extern Transaction *transaction_create_clone(Transaction *srctrans); extern void transaction_free(Transaction *trans); @@ -115,8 +115,8 @@ extern void transaction_classify_pkgs(Transaction *trans, int mode, Id type, Id packages is returned */ extern int transaction_installedresult(Transaction *trans, Queue *installedq); -int transaction_calc_installsizechange(Transaction *trans); -void transaction_calc_duchanges(Transaction *trans, struct _DUChanges *mps, int nmps); +long long transaction_calc_installsizechange(Transaction *trans); +void transaction_calc_duchanges(Transaction *trans, struct s_DUChanges *mps, int nmps); diff --git a/libsolv-0.7.2/src/userinstalled.c b/libsolv-0.7.2/src/userinstalled.c new file mode 100644 index 0000000..0efcdd7 --- /dev/null +++ b/libsolv-0.7.2/src/userinstalled.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2017, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* Functions that help getting/setting userinstalled packages. */ + +#include +#include +#include +#include + +#include "solver.h" +#include "solver_private.h" +#include "bitmap.h" +#include "pool.h" +#include "util.h" +#include "poolarch.h" +#include "linkedpkg.h" + +static int +get_userinstalled_cmp(const void *ap, const void *bp, void *dp) +{ + return *(Id *)ap - *(Id *)bp; +} + +static int +get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp)); +} + +static int +get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp) +{ + Pool *pool = dp; + int r; + r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0])); + if (r) + return r; + return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1])); +} + +static void +get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags) +{ + Id lastp = -1, lasta = -1; + int i, j; + if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2)) + return; + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool); + else if ((flags & GET_USERINSTALLED_NAMES) != 0) + solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool); + else + solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0); + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + { + for (i = j = 0; i < q->count; i += 2) + if (q->elements[i] != lastp || q->elements[i + 1] != lasta) + { + q->elements[j++] = lastp = q->elements[i]; + q->elements[j++] = lasta = q->elements[i + 1]; + } + } + else + { + for (i = j = 0; i < q->count; i++) + if (q->elements[i] != lastp) + q->elements[j++] = lastp = q->elements[i]; + } + queue_truncate(q, j); +} + +static void +namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job) +{ + int i; + if (!pool->installed) + return; + for (i = 0; i < q->count; i += 2) + { + Id p, pp, name = q->elements[i], arch = q->elements[i + 1]; + FOR_PROVIDES(p, pp, name) + { + Solvable *s = pool->solvables + p; + if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch)) + continue; + if (job) + queue_push(qout, job); + queue_push(qout, p); + } + } +} + +void +solver_get_userinstalled(Solver *solv, Queue *q, int flags) +{ + Pool *pool = solv->pool; + Id p, p2, pp; + Solvable *s; + Repo *installed = solv->installed; + int i, j; + Map userinstalled; + + map_init(&userinstalled, 0); + queue_empty(q); + /* first process jobs */ + for (i = 0; i < solv->job.count; i += 2) + { + Id how = solv->job.elements[i]; + Id what, select; + if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED) + { + if (!userinstalled.size) + map_grow(&userinstalled, installed->end - installed->start); + what = solv->job.elements[i + 1]; + select = how & SOLVER_SELECTMASK; + if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid)) + { + FOR_REPO_SOLVABLES(installed, p, s) + MAPSET(&userinstalled, p - installed->start); + } + FOR_JOB_SELECT(p, pp, select, what) + if (pool->solvables[p].repo == installed) + MAPSET(&userinstalled, p - installed->start); + continue; + } + if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL) + continue; + if ((how & SOLVER_NOTBYUSER) != 0) + continue; + what = solv->job.elements[i + 1]; + select = how & SOLVER_SELECTMASK; + FOR_JOB_SELECT(p, pp, select, what) + if (solv->decisionmap[p] > 0) + { + queue_push(q, p); +#ifdef ENABLE_LINKED_PKGS + if (has_package_link(pool, pool->solvables + p)) + { + int j; + Queue lq; + queue_init(&lq); + find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0); + for (j = 0; j < lq.count; j++) + if (solv->decisionmap[lq.elements[j]] > 0) + queue_push(q, lq.elements[j]); + } +#endif + } + } + /* now process updates of userinstalled packages */ + if (installed && userinstalled.size) + { + for (i = 1; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p <= 0) + continue; + s = pool->solvables + p; + if (!s->repo) + continue; + if (s->repo == installed) + { + if (MAPTST(&userinstalled, p - installed->start)) + queue_push(q, p); + continue; + } + /* new package, check if we replace a userinstalled one */ + FOR_PROVIDES(p2, pp, s->name) + { + Solvable *ps = pool->solvables + p2; + if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) + continue; + if (!pool->implicitobsoleteusesprovides && s->name != ps->name) + continue; + if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p); + break; + } + if (!p2 && s->repo != installed && s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + FOR_PROVIDES(p2, pp, obs) + { + Solvable *ps = pool->solvables + p2; + if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start)) + continue; + if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs)) + continue; + if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) + continue; + queue_push(q, p); + break; + } + if (p2) + break; + } + } + } + } + map_free(&userinstalled); + + /* convert to desired output format */ + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + { + int qcount = q->count; + queue_insertn(q, 0, qcount, 0); + for (i = j = 0; i < qcount; i++) + { + s = pool->solvables + q->elements[i + qcount]; + q->elements[j++] = s->name; + q->elements[j++] = s->arch; + } + } + else if ((flags & GET_USERINSTALLED_NAMES) != 0) + { + for (i = 0; i < q->count; i++) + { + s = pool->solvables + q->elements[i]; + q->elements[i] = s->name; + } + } + /* sort and unify */ + get_userinstalled_sort_uniq(pool, q, flags); + + /* invert if asked for */ + if ((flags & GET_USERINSTALLED_INVERTED) != 0) + { + /* first generate queue with all installed packages */ + Queue invq; + queue_init(&invq); + for (i = 1; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p <= 0) + continue; + s = pool->solvables + p; + if (!s->repo) + continue; + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + queue_push2(&invq, s->name, s->arch); + else if ((flags & GET_USERINSTALLED_NAMES) != 0) + queue_push(&invq, s->name); + else + queue_push(&invq, p); + } + /* push q on invq, just in case... */ + queue_insertn(&invq, invq.count, q->count, q->elements); + get_userinstalled_sort_uniq(pool, &invq, flags); + /* subtract queues (easy as they are sorted and invq is a superset of q) */ + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + { + if (q->count) + { + for (i = j = 0; i < invq.count; i += 2) + if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1]) + { + invq.elements[i] = invq.elements[i + 1] = 0; + j += 2; + if (j >= q->count) + break; + } + queue_empty(q); + } + for (i = 0; i < invq.count; i += 2) + if (invq.elements[i]) + queue_push2(q, invq.elements[i], invq.elements[i + 1]); + } + else + { + if (q->count) + { + for (i = j = 0; i < invq.count; i++) + if (invq.elements[i] == q->elements[j]) + { + invq.elements[i] = 0; + if (++j >= q->count) + break; + } + queue_empty(q); + } + for (i = 0; i < invq.count; i++) + if (invq.elements[i]) + queue_push(q, invq.elements[i]); + } + queue_free(&invq); + } +} + +void +pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags) +{ + int i; + + if ((flags & GET_USERINSTALLED_INVERTED) != 0) + { + Queue invq; + Id p, lastid; + Solvable *s; + int bad; + if (!pool->installed) + return; + queue_init(&invq); + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + flags &= ~GET_USERINSTALLED_NAMES; /* just in case */ + FOR_REPO_SOLVABLES(pool->installed, p, s) + queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p); + if ((flags & GET_USERINSTALLED_NAMEARCH) != 0) + { + /* for namearch we convert to packages */ + namearch2solvables(pool, q, &invq, 0); + get_userinstalled_sort_uniq(pool, &invq, flags); + namearch2solvables(pool, q, &invq, 0); + flags = 0; + } + else + { + queue_insertn(&invq, invq.count, q->count, q->elements); + get_userinstalled_sort_uniq(pool, &invq, flags); + /* now the fun part, add q again, sort, and remove all dups */ + queue_insertn(&invq, invq.count, q->count, q->elements); + } + if (invq.count > 1) + { + if ((flags & GET_USERINSTALLED_NAMES) != 0) + solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool); + else + solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0); + } + lastid = -1; + bad = 1; + for (i = 0; i < invq.count; i++) + { + if (invq.elements[i] == lastid) + { + bad = 1; + continue; + } + if (!bad) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); + bad = 0; + lastid = invq.elements[i]; + } + if (!bad) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid); + queue_free(&invq); + } + else + { + if (flags & GET_USERINSTALLED_NAMEARCH) + namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE); + else + { + for (i = 0; i < q->count; i++) + queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]); + } + } +} + diff --git a/libsolv-0.6.15/src/util.c b/libsolv-0.7.2/src/util.c similarity index 98% rename from libsolv-0.6.15/src/util.c rename to libsolv-0.7.2/src/util.c index d611297..65c8629 100644 --- a/libsolv-0.6.15/src/util.c +++ b/libsolv-0.7.2/src/util.c @@ -139,7 +139,7 @@ solv_timems(unsigned int subtract) see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html */ -#if defined(__GLIBC__) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R)) +#if (defined(__GLIBC__) || defined(__NEWLIB__)) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R)) void solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard) @@ -235,7 +235,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) d = c - ('A' - 10); else break; - c = *++str; + c = str[1]; d <<= 4; if (c >= '0' && c <= '9') d |= c - '0'; @@ -246,7 +246,7 @@ solv_hex2bin(const char **strp, unsigned char *buf, int bufl) else break; buf[i] = d; - ++str; + str += 2; } *strp = str; return i; diff --git a/libsolv-0.6.15/src/util.h b/libsolv-0.7.2/src/util.h similarity index 100% rename from libsolv-0.6.15/src/util.h rename to libsolv-0.7.2/src/util.h diff --git a/libsolv-0.6.15/test/CMakeLists.txt b/libsolv-0.7.2/test/CMakeLists.txt similarity index 100% rename from libsolv-0.6.15/test/CMakeLists.txt rename to libsolv-0.7.2/test/CMakeLists.txt diff --git a/libsolv-0.6.15/test/runtestcases b/libsolv-0.7.2/test/runtestcases similarity index 100% rename from libsolv-0.6.15/test/runtestcases rename to libsolv-0.7.2/test/runtestcases diff --git a/libsolv-0.7.2/test/testcases/allowuninstall/conflict.t b/libsolv-0.7.2/test/testcases/allowuninstall/conflict.t new file mode 100644 index 0000000..a66d322 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/allowuninstall/conflict.t @@ -0,0 +1,14 @@ +repo system 0 testtags +#>=Pkg: a 1 1 noarch +#>=Con: b +repo available 0 testtags +#>=Pkg: b 1 1 noarch + +system x86_64 rpm system +solverflags allowuninstall +disable pkg a-1-1.noarch@system +job install name b +result transaction,problems +#>problem a658cbaf info package a-1-1.noarch conflicts with b provided by b-1-1.noarch +#>problem a658cbaf solution 567aa15d erase a-1-1.noarch@system +#>problem a658cbaf solution e98e1a37 deljob install name b diff --git a/libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t b/libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t new file mode 100644 index 0000000..38ade6f --- /dev/null +++ b/libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t @@ -0,0 +1,19 @@ +repo system 0 testtags +#>=Pkg: a 1 1 noarch +#>=Req: b = 1-1 +#>=Pkg: b 1 1 noarch +repo available 0 testtags +#>=Pkg: a 2 1 noarch +#>=Req: b = 2-1 +#>=Pkg: b 2 1 noarch + +system x86_64 rpm system +disable pkg b-1-1.noarch@system +disable pkg b-2-1.noarch@available +job allowuninstall pkg a-1-1.noarch@system +job allowuninstall pkg b-1-1.noarch@system +job update name a [forcebest] +result transaction,problems +#>problem e6d3911d info nothing provides b = 2-1 needed by a-2-1.noarch +#>problem e6d3911d solution 0011b04f allow a-1-1.noarch@system +#>problem e6d3911d solution 44d189a0 erase a-1-1.noarch@system diff --git a/libsolv-0.6.15/test/testcases/choose/default.t b/libsolv-0.7.2/test/testcases/choose/default.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/default.t rename to libsolv-0.7.2/test/testcases/choose/default.t diff --git a/libsolv-0.6.15/test/testcases/choose/enhanced.t b/libsolv-0.7.2/test/testcases/choose/enhanced.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/enhanced.t rename to libsolv-0.7.2/test/testcases/choose/enhanced.t diff --git a/libsolv-0.6.15/test/testcases/choose/oldversion.t b/libsolv-0.7.2/test/testcases/choose/oldversion.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/oldversion.t rename to libsolv-0.7.2/test/testcases/choose/oldversion.t diff --git a/libsolv-0.6.15/test/testcases/choose/suggested.t b/libsolv-0.7.2/test/testcases/choose/suggested.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/suggested.t rename to libsolv-0.7.2/test/testcases/choose/suggested.t diff --git a/libsolv-0.6.15/test/testcases/choose/versioned.t b/libsolv-0.7.2/test/testcases/choose/versioned.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/versioned.t rename to libsolv-0.7.2/test/testcases/choose/versioned.t diff --git a/libsolv-0.6.15/test/testcases/choose/versioned2.t b/libsolv-0.7.2/test/testcases/choose/versioned2.t similarity index 100% rename from libsolv-0.6.15/test/testcases/choose/versioned2.t rename to libsolv-0.7.2/test/testcases/choose/versioned2.t diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t similarity index 60% rename from libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t rename to libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t index 7002434..afebcc4 100644 --- a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t +++ b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t @@ -13,7 +13,8 @@ system i686 rpm system # check untargeted job distupgrade name A [cleandeps] -result transaction,problems +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system #>erase B1-1-1.noarch@system #>install B2-1-1.noarch@test #>upgrade A-1-1.noarch@system A-2-1.noarch@test @@ -21,7 +22,8 @@ result transaction,problems # check targeted nextjob job distupgrade name A = 2 [cleandeps] -result transaction,problems +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system #>erase B1-1-1.noarch@system #>install B2-1-1.noarch@test #>upgrade A-1-1.noarch@system A-2-1.noarch@test @@ -29,5 +31,15 @@ result transaction,problems # check targeted to 1-2 nextjob job distupgrade name A = 1-2 [cleandeps] -result transaction,problems +result transaction,problems,cleandeps #>upgrade A-1-1.noarch@system A-1-2.noarch@test + +# check all packages +nextjob +job distupgrade all packages [cleandeps] +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system +#>erase B1-1-1.noarch@system +#>install B2-1-1.noarch@test +#>upgrade A-1-1.noarch@system A-2-1.noarch@test + diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t similarity index 81% rename from libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t rename to libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t index 3edacb5..e77a7f7 100644 --- a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t +++ b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t @@ -9,7 +9,8 @@ repo test 0 testtags #>=Pkg: B2 1 1 noarch system i686 rpm system job install name A = 2 [cleandeps] -result transaction,problems +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system #>erase B1-1-1.noarch@system #>install B2-1-1.noarch@test #>upgrade A-1-1.noarch@system A-2-1.noarch@test diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t similarity index 54% rename from libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t rename to libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t index 9bb26d2..5560a28 100644 --- a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t +++ b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t @@ -2,6 +2,9 @@ repo system 0 testtags #>=Pkg: A 1 1 noarch #>=Req: B1 #>=Pkg: B1 1 1 noarch +#>=Pkg: C 1 1 noarch +#>=Rec: D +#>=Pkg: D 1 1 noarch repo test 0 testtags #>=Pkg: A 1 2 noarch #>=Req: B1 @@ -9,11 +12,15 @@ repo test 0 testtags #>=Req: B2 = 1 #>=Pkg: B1 1 1 noarch #>=Pkg: B2 1 1 noarch +#>=Pkg: C 1 1 noarch +#>=Rec: D system i686 rpm system # check untargeted job update name A [cleandeps] -result transaction,problems +job update name C [cleandeps] +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system #>erase B1-1-1.noarch@system #>install B2-1-1.noarch@test #>upgrade A-1-1.noarch@system A-2-1.noarch@test @@ -21,7 +28,8 @@ result transaction,problems # check targeted nextjob job update name A = 2 [cleandeps] -result transaction,problems +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system #>erase B1-1-1.noarch@system #>install B2-1-1.noarch@test #>upgrade A-1-1.noarch@system A-2-1.noarch@test @@ -29,5 +37,14 @@ result transaction,problems # check targeted to 1-2 nextjob job update name A = 1-2 [cleandeps] -result transaction,problems +result transaction,problems,cleandeps #>upgrade A-1-1.noarch@system A-1-2.noarch@test + +# check all packages +nextjob +job update all packages [cleandeps] +result transaction,problems,cleandeps +#>cleandeps B1-1-1.noarch@system +#>erase B1-1-1.noarch@system +#>install B2-1-1.noarch@test +#>upgrade A-1-1.noarch@system A-2-1.noarch@test diff --git a/libsolv-0.6.15/test/testcases/cleandeps/mistake.t b/libsolv-0.7.2/test/testcases/cleandeps/mistake.t similarity index 100% rename from libsolv-0.6.15/test/testcases/cleandeps/mistake.t rename to libsolv-0.7.2/test/testcases/cleandeps/mistake.t diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/and.t b/libsolv-0.7.2/test/testcases/cplxdeps/and.t new file mode 100644 index 0000000..d4ef47e --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/and.t @@ -0,0 +1,39 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: X 1 1 x86_64 +#>=Req: A & B +#>=Pkg: Y 1 1 x86_64 +#>=Con: A & B +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 8d94817282778a96505d2865a9b6c417 B1-1-1.x86_64@available +#>rule pkg 8d94817282778a96505d2865a9b6c417 B2-1-1.x86_64@available +#>rule pkg 8d94817282778a96505d2865a9b6c417 -X-1-1.x86_64@available +#>rule pkg 9294f4d070a449a787a945d757c853ac A1-1-1.x86_64@available +#>rule pkg 9294f4d070a449a787a945d757c853ac A2-1-1.x86_64@available +#>rule pkg 9294f4d070a449a787a945d757c853ac -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/andor.t b/libsolv-0.7.2/test/testcases/cplxdeps/andor.t new file mode 100644 index 0000000..f60745d --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/andor.t @@ -0,0 +1,73 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: C1 1 1 x86_64 +#>=Prv: C +#>=Pkg: C2 1 1 x86_64 +#>=Prv: C +#>=Pkg: D1 1 1 x86_64 +#>=Prv: D +#>=Pkg: D2 1 1 x86_64 +#>=Prv: D +#>=Pkg: X 1 1 x86_64 +#>=Req: (A & B) | (C & D) +#>=Pkg: Y 1 1 x86_64 +#>=Con: (A & B) | (C & D) +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 500f33fd32c5be8fb62896b334f580e7 B1-1-1.x86_64@available +#>rule pkg 500f33fd32c5be8fb62896b334f580e7 B2-1-1.x86_64@available +#>rule pkg 500f33fd32c5be8fb62896b334f580e7 D1-1-1.x86_64@available +#>rule pkg 500f33fd32c5be8fb62896b334f580e7 D2-1-1.x86_64@available +#>rule pkg 500f33fd32c5be8fb62896b334f580e7 -X-1-1.x86_64@available +#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 A1-1-1.x86_64@available +#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 A2-1-1.x86_64@available +#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 D1-1-1.x86_64@available +#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 D2-1-1.x86_64@available +#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 -X-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a B1-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a B2-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a C1-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a C2-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a -X-1-1.x86_64@available +#>rule pkg e524681ade2cf622db027a5d989023c4 A1-1-1.x86_64@available +#>rule pkg e524681ade2cf622db027a5d989023c4 A2-1-1.x86_64@available +#>rule pkg e524681ade2cf622db027a5d989023c4 C1-1-1.x86_64@available +#>rule pkg e524681ade2cf622db027a5d989023c4 C2-1-1.x86_64@available +#>rule pkg e524681ade2cf622db027a5d989023c4 -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available +#>rule pkg 57f43a628a3173b517f444966e291dcc -C2-1-1.x86_64@available +#>rule pkg 57f43a628a3173b517f444966e291dcc -D2-1-1.x86_64@available +#>rule pkg 57f43a628a3173b517f444966e291dcc -Y-1-1.x86_64@available +#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -C2-1-1.x86_64@available +#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -D1-1-1.x86_64@available +#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -Y-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available +#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -C1-1-1.x86_64@available +#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -D2-1-1.x86_64@available +#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -Y-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available +#>rule pkg da2fe506ceca44a0c6eafab14af37505 -C1-1-1.x86_64@available +#>rule pkg da2fe506ceca44a0c6eafab14af37505 -D1-1-1.x86_64@available +#>rule pkg da2fe506ceca44a0c6eafab14af37505 -Y-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/if.t b/libsolv-0.7.2/test/testcases/cplxdeps/if.t new file mode 100644 index 0000000..7e3dead --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/if.t @@ -0,0 +1,36 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: X 1 1 x86_64 +#>=Req: A B +#>=Pkg: Y 1 1 x86_64 +#>=Con: A B +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 A1-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 A2-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -B1-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -X-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 A1-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 A2-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -B2-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -A1-1-1.x86_64@available +#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -Y-1-1.x86_64@available +#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -A2-1-1.x86_64@available +#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -Y-1-1.x86_64@available +#>rule pkg 88a787532b7e170c57d67c5123982b0d B1-1-1.x86_64@available +#>rule pkg 88a787532b7e170c57d67c5123982b0d B2-1-1.x86_64@available +#>rule pkg 88a787532b7e170c57d67c5123982b0d -Y-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t b/libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t new file mode 100644 index 0000000..ef5bab9 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t @@ -0,0 +1,70 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: C1 1 1 x86_64 +#>=Prv: C +#>=Pkg: C2 1 1 x86_64 +#>=Prv: C +#>=Pkg: X 1 1 x86_64 +#>=Req: A (B C) +#>=Pkg: Y 1 1 x86_64 +#>=Con: A (B C) +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 A1-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 A2-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -B1-1-1.x86_64@available +#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -X-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 A1-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 A2-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -B2-1-1.x86_64@available +#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -X-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a B1-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a B2-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a C1-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a C2-1-1.x86_64@available +#>rule pkg dee60af94c8ea49c9f99362dcb65806a -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available +#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -A1-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -C1-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -Y-1-1.x86_64@available +#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 B1-1-1.x86_64@available +#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 B2-1-1.x86_64@available +#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 -C1-1-1.x86_64@available +#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 -Y-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available +#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available +#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -A2-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -C1-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -Y-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available +#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available +#>rule pkg c3f6b37277eb48011d0e68c11323ea3e B1-1-1.x86_64@available +#>rule pkg c3f6b37277eb48011d0e68c11323ea3e B2-1-1.x86_64@available +#>rule pkg c3f6b37277eb48011d0e68c11323ea3e -C2-1-1.x86_64@available +#>rule pkg c3f6b37277eb48011d0e68c11323ea3e -Y-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -A2-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -C2-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -Y-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -A1-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -C2-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -Y-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/or.t b/libsolv-0.7.2/test/testcases/cplxdeps/or.t new file mode 100644 index 0000000..7446799 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/or.t @@ -0,0 +1,34 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: X 1 1 x86_64 +#>=Req: A | B +#>=Pkg: Y 1 1 x86_64 +#>=Con: A | B +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 A1-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 A2-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 B1-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 B2-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -A1-1-1.x86_64@available +#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -Y-1-1.x86_64@available +#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -A2-1-1.x86_64@available +#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -Y-1-1.x86_64@available +#>rule pkg 69d83d7a676b6a65f79a6fc5bcf2ca6e -B1-1-1.x86_64@available +#>rule pkg 69d83d7a676b6a65f79a6fc5bcf2ca6e -Y-1-1.x86_64@available +#>rule pkg d6e57752cc50ab9fc0a218fda6dbf172 -B2-1-1.x86_64@available +#>rule pkg d6e57752cc50ab9fc0a218fda6dbf172 -Y-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/orand.t b/libsolv-0.7.2/test/testcases/cplxdeps/orand.t new file mode 100644 index 0000000..8a5108a --- /dev/null +++ b/libsolv-0.7.2/test/testcases/cplxdeps/orand.t @@ -0,0 +1,87 @@ +feature complex_deps +repo available 0 testtags +#>=Pkg: A1 1 1 x86_64 +#>=Prv: A +#>=Pkg: A2 1 1 x86_64 +#>=Prv: A +#>=Pkg: B1 1 1 x86_64 +#>=Prv: B +#>=Pkg: B2 1 1 x86_64 +#>=Prv: B +#>=Pkg: C1 1 1 x86_64 +#>=Prv: C +#>=Pkg: C2 1 1 x86_64 +#>=Prv: C +#>=Pkg: D1 1 1 x86_64 +#>=Prv: D +#>=Pkg: D2 1 1 x86_64 +#>=Prv: D +#>=Pkg: X 1 1 x86_64 +#>=Req: (A | B) & (C | D) +#>=Pkg: Y 1 1 x86_64 +#>=Con: (A | B) & (C | D) +job install name X +result rules +#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d X-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 A1-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 A2-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 B1-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 B2-1-1.x86_64@available +#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 -X-1-1.x86_64@available +#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc C1-1-1.x86_64@available +#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc C2-1-1.x86_64@available +#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc D1-1-1.x86_64@available +#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc D2-1-1.x86_64@available +#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc -X-1-1.x86_64@available +nextjob +job install name Y +result rules +#>rule job 181d7955b2179c4ffdffedf0198f4807 Y-1-1.x86_64@available +#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -B1-1-1.x86_64@available +#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -D1-1-1.x86_64@available +#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -Y-1-1.x86_64@available +#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -A1-1-1.x86_64@available +#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -D2-1-1.x86_64@available +#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -Y-1-1.x86_64@available +#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -A2-1-1.x86_64@available +#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -D1-1-1.x86_64@available +#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -Y-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -A1-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -C1-1-1.x86_64@available +#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -Y-1-1.x86_64@available +#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -B2-1-1.x86_64@available +#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -C2-1-1.x86_64@available +#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -Y-1-1.x86_64@available +#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -B2-1-1.x86_64@available +#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -C1-1-1.x86_64@available +#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -Y-1-1.x86_64@available +#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -B1-1-1.x86_64@available +#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -C1-1-1.x86_64@available +#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -Y-1-1.x86_64@available +#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -B1-1-1.x86_64@available +#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -C2-1-1.x86_64@available +#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -Y-1-1.x86_64@available +#>rule pkg 87928b09a90963097188f62d00bfb3d9 -B2-1-1.x86_64@available +#>rule pkg 87928b09a90963097188f62d00bfb3d9 -D1-1-1.x86_64@available +#>rule pkg 87928b09a90963097188f62d00bfb3d9 -Y-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -A2-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -C1-1-1.x86_64@available +#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -Y-1-1.x86_64@available +#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -B1-1-1.x86_64@available +#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -D2-1-1.x86_64@available +#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -Y-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -A2-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -C2-1-1.x86_64@available +#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -Y-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -A1-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -C2-1-1.x86_64@available +#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -Y-1-1.x86_64@available +#>rule pkg dfd799532ba714fd139acf879992c2de -A2-1-1.x86_64@available +#>rule pkg dfd799532ba714fd139acf879992c2de -D2-1-1.x86_64@available +#>rule pkg dfd799532ba714fd139acf879992c2de -Y-1-1.x86_64@available +#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -B2-1-1.x86_64@available +#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -D2-1-1.x86_64@available +#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -Y-1-1.x86_64@available +#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -A1-1-1.x86_64@available +#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -D1-1-1.x86_64@available +#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -Y-1-1.x86_64@available diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall b/libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t similarity index 100% rename from libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall rename to libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1 b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t similarity index 100% rename from libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1 rename to libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t similarity index 94% rename from libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 rename to libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t index 18909eb..6708896 100644 --- a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t @@ -89,8 +89,10 @@ job multiversion name a job distupgrade all packages # a-1-1 is treated as orphaned and stays behind result transaction,problems -#>erase b-1-1.i686@system +#>erase a-1-1.i686@system #>install a-2-1.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available + nextjob @@ -100,7 +102,8 @@ job multiversion name a job distupgrade repo available # a-1-1 is treated as orphaned and stays behind result transaction,problems -#>erase b-1-1.i686@system +#>erase a-1-1.i686@system #>install a-2-1.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t similarity index 83% rename from libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 rename to libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t index 8be3190..97eb20f 100644 --- a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t @@ -12,17 +12,18 @@ system i686 * system job multiversion name a job distupgrade all packages result transaction,problems -#>problem 251f1f35 info nothing provides c needed by a-2-1.i686 -#>problem 251f1f35 solution 2f2d254c allow a-1-1.i686@system +#>problem fc3d647e info nothing provides c needed by a-2-1.i686 +#>problem fc3d647e solution 179b72ed allow a-1-1.i686@system +#>problem fc3d647e solution e5fc66c9 erase a-1-1.i686@system nextjob job multiversion name a job distupgrade repo available result transaction,problems -#>erase a-1-1.i686@system -#>problem 251f1f35 info nothing provides c needed by a-2-1.i686 -#>problem 251f1f35 solution 2f2d254c allow a-1-1.i686@system +#>problem fc3d647e info nothing provides c needed by a-2-1.i686 +#>problem fc3d647e solution 179b72ed allow a-1-1.i686@system +#>problem fc3d647e solution e5fc66c9 erase a-1-1.i686@system ### same with keeporphans diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange b/libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t similarity index 67% rename from libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange rename to libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t index f500d9b..8231561 100644 --- a/libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t @@ -9,7 +9,8 @@ system i686 * system solverflags !dupallowarchchange job distupgrade all packages result transaction,problems -#>problem c43b1300 info problem with installed package a-1-1.i686 -#>problem c43b1300 solution c43b1300 replace a-1-1.i686@system a-2-1.i586@available +#>problem 7724e627 info problem with installed package a-1-1.i686 +#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system +#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-2-1.i586@available #>upgrade a-1-1.i686@system a-2-1.i586@available #>upgrade b-1-1.i686@system b-2-1.i686@available diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t new file mode 100644 index 0000000..3c4976a --- /dev/null +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t @@ -0,0 +1,78 @@ +# test dup with orphaned packages +# +# part 1: simple update +# +# dup should leave orphaned a installed +# +repo system 0 testtags +#>=Pkg: a 1 1 i686 +#>=Pkg: b 1 1 i686 +repo available 0 testtags +#>=Pkg: b 2 1 i686 +system i686 * system + +job distupgrade all packages +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + +nextjob + +job distupgrade repo available +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +### same with keeporphans + +nextjob + +solverflags keeporphans +job distupgrade all packages +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + +nextjob + +solverflags keeporphans +job distupgrade repo available +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +### same with allowuninstall + +nextjob + +solverflags allowuninstall +job distupgrade all packages +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags allowuninstall +job distupgrade repo available +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +### same with allowuninstall and keeporphans + +nextjob + +solverflags allowuninstall keeporphans +job distupgrade all packages +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags allowuninstall keeporphans +job distupgrade repo available +result transaction,problems +#>upgrade b-1-1.i686@system b-2-1.i686@available + + + diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t new file mode 100644 index 0000000..f4e746e --- /dev/null +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t @@ -0,0 +1,98 @@ +# test dup with orphaned packages +# +# part 2: update conflicts with the orphan +# +# dup should leave orphaned a installed +# for "distupgrade repo available", a is not involved +# in the dup and thus not considered orphan. +# + +repo system 0 testtags +#>=Pkg: a 1 1 i686 +#>=Pkg: b 1 1 i686 +repo available 0 testtags +#>=Pkg: b 2 1 i686 +#>=Con: a +system i686 * system + +job distupgrade all packages +result transaction,problems +#>erase a-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + +nextjob + +job distupgrade repo available +result transaction,problems +#>erase a-1-1.i686@system +#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686 +#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system +#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system +#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + +### keeporphans + +nextjob + +solverflags keeporphans +job distupgrade all packages +result transaction,problems +#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686 +#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system +#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system +#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system + +nextjob + +solverflags keeporphans +job distupgrade repo available +result transaction,problems +#>erase a-1-1.i686@system +#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686 +#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system +#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system +#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +### same with allowuninstall + +nextjob + +solverflags allowuninstall +job distupgrade all packages +result transaction,problems +#>erase a-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags allowuninstall +job distupgrade repo available +result transaction,problems +#>erase b-1-1.i686@system + + +### same with allowuninstall and keeporphans + +nextjob + +solverflags allowuninstall keeporphans +job distupgrade all packages +result transaction,problems +#>erase a-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags allowuninstall keeporphans +job distupgrade repo available +result transaction,problems +#>erase a-1-1.i686@system +#>upgrade b-1-1.i686@system b-2-1.i686@available + + + diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t new file mode 100644 index 0000000..361649a --- /dev/null +++ b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t @@ -0,0 +1,98 @@ +# test dup with orphaned packages +# +# part 3: a is not really an orphan, but cannot be downgraded +# + +repo system 0 testtags +#>=Pkg: a 1 1 i686 +#>=Pkg: b 1 1 i686 +repo available 0 testtags +#>=Pkg: a 1 0 i686 +#>=Pkg: b 2 1 i686 +system i686 * system + +solverflags !dupallowdowngrade +job distupgrade all packages +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available +#>problem 7724e627 info problem with installed package a-1-1.i686 +#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system +#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available + +nextjob + +solverflags !dupallowdowngrade +job distupgrade repo available +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available +#>problem 7724e627 info problem with installed package a-1-1.i686 +#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system +#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available + +### keeporphans + +nextjob + +solverflags !dupallowdowngrade keeporphans +job distupgrade all packages +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available +#>problem 7724e627 info problem with installed package a-1-1.i686 +#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system +#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available + +nextjob + +solverflags !dupallowdowngrade keeporphans +job distupgrade repo available +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available +#>problem 7724e627 info problem with installed package a-1-1.i686 +#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system +#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available + +### same with allowuninstall + +nextjob + +solverflags !dupallowdowngrade allowuninstall +job distupgrade all packages +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags !dupallowdowngrade allowuninstall +job distupgrade repo available +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +### same with allowuninstall and keeporphans + +nextjob + +solverflags !dupallowdowngrade allowuninstall keeporphans +job distupgrade all packages +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available + + +nextjob + +solverflags !dupallowdowngrade allowuninstall keeporphans +job distupgrade repo available +result transaction,problems +#>downgrade a-1-1.i686@system a-1-0.i686@available +#>upgrade b-1-1.i686@system b-2-1.i686@available + + + diff --git a/libsolv-0.7.2/test/testcases/evrcmp/caret.t b/libsolv-0.7.2/test/testcases/evrcmp/caret.t new file mode 100644 index 0000000..d0c3a07 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/evrcmp/caret.t @@ -0,0 +1,74 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A1 1.0 0 +#>=Pkg: A2 1.0^ 0 +system i686 rpm system + +evrcmp 1.0~rc1 1.0~rc1 +evrcmp 1.0~rc1 1.0 +evrcmp 1.0 1.0~rc1 +evrcmp 1.0~rc1 1.0~rc2 +evrcmp 1.0~rc2 1.0~rc1 +evrcmp 1.0~rc1~git123 1.0~rc1~git123 +evrcmp 1.0~rc1~git123 1.0~rc1 +evrcmp 1.0~rc1 1.0~rc1~git123 + +evrcmp 1.0^ 1.0^ +evrcmp 1.0^ 1.0 +evrcmp 1.0 1.0^ +evrcmp 1.0^git1 1.0^git1 +evrcmp 1.0^git1 1.0 +evrcmp 1.0 1.0^git1 +evrcmp 1.0^git1 1.0^git2 +evrcmp 1.0^git2 1.0^git1 +evrcmp 1.0^git1 1.01 +evrcmp 1.01 1.0^git1 +evrcmp 1.0^20160101 1.0^20160101 +evrcmp 1.0^20160101 1.0.1 +evrcmp 1.0.1 1.0^20160101 +evrcmp 1.0^20160101^git1 1.0^20160101^git1 +evrcmp 1.0^20160102 1.0^20160101^git1 +evrcmp 1.0^20160101^git1 1.0^20160102 + +evrcmp 1.0~rc1^git1 1.0~rc1^git1 +evrcmp 1.0~rc1^git1 1.0~rc1 +evrcmp 1.0~rc1 1.0~rc1^git1 +evrcmp 1.0^git1~pre 1.0^git1~pre +evrcmp 1.0^git1 1.0^git1~pre +evrcmp 1.0^git1~pre 1.0^git1 +evrcmp 1.0^1 1.0~1 +evrcmp 1.0~1 1.0^1 + +result jobs +#>job noop provides 1.0~rc1 = 1.0~rc1 +#>job noop provides 1.0~rc1 < 1.0 +#>job noop provides 1.0 > 1.0~rc1 +#>job noop provides 1.0~rc1 < 1.0~rc2 +#>job noop provides 1.0~rc2 > 1.0~rc1 +#>job noop provides 1.0~rc1~git123 = 1.0~rc1~git123 +#>job noop provides 1.0~rc1~git123 < 1.0~rc1 +#>job noop provides 1.0~rc1 > 1.0~rc1~git123 +#>job noop provides 1.0^ = 1.0^ +#>job noop provides 1.0^ > 1.0 +#>job noop provides 1.0 < 1.0^ +#>job noop provides 1.0^git1 = 1.0^git1 +#>job noop provides 1.0^git1 > 1.0 +#>job noop provides 1.0 < 1.0^git1 +#>job noop provides 1.0^git1 < 1.0^git2 +#>job noop provides 1.0^git2 > 1.0^git1 +#>job noop provides 1.0^git1 < 1.01 +#>job noop provides 1.01 > 1.0^git1 +#>job noop provides 1.0^20160101 = 1.0^20160101 +#>job noop provides 1.0^20160101 < 1.0.1 +#>job noop provides 1.0.1 > 1.0^20160101 +#>job noop provides 1.0^20160101^git1 = 1.0^20160101^git1 +#>job noop provides 1.0^20160102 > 1.0^20160101^git1 +#>job noop provides 1.0^20160101^git1 < 1.0^20160102 +#>job noop provides 1.0~rc1^git1 = 1.0~rc1^git1 +#>job noop provides 1.0~rc1^git1 > 1.0~rc1 +#>job noop provides 1.0~rc1 < 1.0~rc1^git1 +#>job noop provides 1.0^git1~pre = 1.0^git1~pre +#>job noop provides 1.0^git1 > 1.0^git1~pre +#>job noop provides 1.0^git1~pre < 1.0^git1 +#>job noop provides 1.0^1 > 1.0~1 +#>job noop provides 1.0~1 < 1.0^1 diff --git a/libsolv-0.6.15/test/testcases/evrcmp/conflicts.repo b/libsolv-0.7.2/test/testcases/evrcmp/conflicts.repo similarity index 100% rename from libsolv-0.6.15/test/testcases/evrcmp/conflicts.repo rename to libsolv-0.7.2/test/testcases/evrcmp/conflicts.repo diff --git a/libsolv-0.6.15/test/testcases/evrcmp/system.repo b/libsolv-0.7.2/test/testcases/evrcmp/system.repo similarity index 100% rename from libsolv-0.6.15/test/testcases/evrcmp/system.repo rename to libsolv-0.7.2/test/testcases/evrcmp/system.repo diff --git a/libsolv-0.6.15/test/testcases/evrcmp/testevr.t b/libsolv-0.7.2/test/testcases/evrcmp/testevr.t similarity index 100% rename from libsolv-0.6.15/test/testcases/evrcmp/testevr.t rename to libsolv-0.7.2/test/testcases/evrcmp/testevr.t diff --git a/libsolv-0.7.2/test/testcases/favor/recommends.t b/libsolv-0.7.2/test/testcases/favor/recommends.t new file mode 100644 index 0000000..c802d4a --- /dev/null +++ b/libsolv-0.7.2/test/testcases/favor/recommends.t @@ -0,0 +1,50 @@ +repo system 0 empty +repo test 0 testtags +#>=Ver: 2.0 +#>=Pkg: A 1 1 noarch +#>=Rec: X +#>=Pkg: B 1 1 noarch +#>=Prv: X +#>=Pkg: C 1 1 noarch +#>=Prv: X +system unset * system + +# first favor B +job install name A +job favor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +# then favor C +nextjob +job install name A +job favor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +# check disfavor +nextjob +job install name A +job disfavor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +nextjob +job install name A +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +# check disfavor both, this is different from +# the requires case + +nextjob +job install name A +job disfavor name B +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test diff --git a/libsolv-0.7.2/test/testcases/favor/requires.t b/libsolv-0.7.2/test/testcases/favor/requires.t new file mode 100644 index 0000000..e96a905 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/favor/requires.t @@ -0,0 +1,112 @@ +repo system 0 empty +repo test 0 testtags +#>=Ver: 2.0 +#>=Pkg: A 1 1 noarch +#>=Req: X +#>=Pkg: B 1 1 noarch +#>=Prv: X +#>=Pkg: C 1 1 noarch +#>=Prv: X +system unset * system + +# first favor B +job install name A +job favor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +# then favor C +nextjob +job install name A +job favor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + + +# if both are favored, the last one wins +nextjob +job install name A +job favor name C +job favor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +nextjob +job install name A +job favor name B +job favor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +# now test disfavor + +# first disfavor B +nextjob +job install name A +job disfavor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +# then disfavor C +nextjob +job install name A +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +# then both +nextjob +job install name A +job disfavor name B +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +nextjob +job install name A +job disfavor name C +job disfavor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +# then test combination +nextjob +job install name A +job favor name B +job disfavor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +nextjob +job install name A +job disfavor name B +job favor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +nextjob +job install name A +job favor name C +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +nextjob +job install name A +job disfavor name C +job favor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + diff --git a/libsolv-0.7.2/test/testcases/favor/supplements.t b/libsolv-0.7.2/test/testcases/favor/supplements.t new file mode 100644 index 0000000..7f415b0 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/favor/supplements.t @@ -0,0 +1,71 @@ +repo system 0 empty +repo test 0 testtags +#>=Ver: 2.0 +#>=Pkg: A 1 1 noarch +#>=Pkg: B 1 1 noarch +#>=Sup: A +#>=Pkg: C 1 1 noarch +#>=Sup: A +#>=Pkg: A2 1 1 noarch +#>=Pkg: B2 1 1 noarch +#>=Sup: A2 +#>=Pkg: C2 1 1 noarch +#>=Sup: A2 +#>=Con: B2 +system unset * system + +# first favor B +job install name A +job favor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test +#>install C-1-1.noarch@test + +# then favor C +nextjob +job install name A +job favor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test +#>install C-1-1.noarch@test + +# same with A2 where B2 and C2 conflict + +nextjob +job install name A2 +job favor name B2 +result transaction,problems +#>install A2-1-1.noarch@test +#>install B2-1-1.noarch@test + +nextjob +job install name A2 +job favor name C2 +result transaction,problems +#>install A2-1-1.noarch@test +#>install C2-1-1.noarch@test + + +# check disfavor +nextjob +job install name A +job disfavor name B +result transaction,problems +#>install A-1-1.noarch@test +#>install C-1-1.noarch@test + +nextjob +job install name A +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test +#>install B-1-1.noarch@test + +nextjob +job install name A +job disfavor name B +job disfavor name C +result transaction,problems +#>install A-1-1.noarch@test diff --git a/libsolv-0.7.2/test/testcases/focus/best.t b/libsolv-0.7.2/test/testcases/focus/best.t new file mode 100644 index 0000000..a7a46b9 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/focus/best.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A 2 1 noarch +#>=Pkg: B 1 1 noarch +#>=Req: A = 1 +#>=Pkg: B 2 1 noarch +#>=Req: A = 2 +#>=Pkg: A2 1 1 noarch +#>=Pkg: A2 2 1 noarch +#>=Pkg: B2 1 1 noarch +#>=Req: A2 = 1 +#>=Pkg: B2 2 1 noarch +#>=Req: A2 = 2 +#>=Pkg: C 1 1 noarch +#>=Req: B2 +system i686 rpm system +solverflags focusbest + +job install name B +job install name C diff --git a/libsolv-0.7.2/test/testcases/focus/installed.t b/libsolv-0.7.2/test/testcases/focus/installed.t new file mode 100644 index 0000000..4f49d35 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/focus/installed.t @@ -0,0 +1,23 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A 2 1 noarch +#>=Pkg: B 1 1 noarch +#>=Req: A = 1 +#>=Pkg: B 2 1 noarch +#>=Req: A = 2 +#>=Pkg: A2 1 1 noarch +#>=Pkg: A2 2 1 noarch +#>=Pkg: B2 1 1 noarch +#>=Req: A2 = 1 +#>=Pkg: B2 2 1 noarch +#>=Req: A2 = 2 +#>=Pkg: C 1 1 noarch +#>=Req: B2 +system i686 rpm system +solverflags focusinstalled + +job install name B +job install name C diff --git a/libsolv-0.7.2/test/testcases/focus/normal.t b/libsolv-0.7.2/test/testcases/focus/normal.t new file mode 100644 index 0000000..6e562a3 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/focus/normal.t @@ -0,0 +1,22 @@ +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A2 1 1 noarch +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A 2 1 noarch +#>=Pkg: B 1 1 noarch +#>=Req: A = 1 +#>=Pkg: B 2 1 noarch +#>=Req: A = 2 +#>=Pkg: A2 1 1 noarch +#>=Pkg: A2 2 1 noarch +#>=Pkg: B2 1 1 noarch +#>=Req: A2 = 1 +#>=Pkg: B2 2 1 noarch +#>=Req: A2 = 2 +#>=Pkg: C 1 1 noarch +#>=Req: B2 +system i686 rpm system + +job install name B +job install name C diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_dup.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_dup.t similarity index 100% rename from libsolv-0.6.15/test/testcases/forcebest/forcebest_dup.t rename to libsolv-0.7.2/test/testcases/forcebest/forcebest_dup.t diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t similarity index 75% rename from libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t rename to libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t index aaf2aa1..93165c8 100644 --- a/libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t +++ b/libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t @@ -11,19 +11,15 @@ system i686 rpm system job install name A [forcebest] result transaction,problems -#>erase D-1-1.noarch@system -#>install A-3-1.noarch@available #>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch #>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system -#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest] +#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest] # currently bestobeypolicy is a noop for install jobs nextjob solverflags bestobeypolicy job install name A [forcebest] result transaction,problems -#>erase D-1-1.noarch@system -#>install A-3-1.noarch@available #>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch #>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system -#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest] +#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest] diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_up.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_up.t similarity index 100% rename from libsolv-0.6.15/test/testcases/forcebest/forcebest_up.t rename to libsolv-0.7.2/test/testcases/forcebest/forcebest_up.t diff --git a/libsolv-0.6.15/test/testcases/lockstep/lockstep_install.t b/libsolv-0.7.2/test/testcases/lockstep/lockstep_install.t similarity index 100% rename from libsolv-0.6.15/test/testcases/lockstep/lockstep_install.t rename to libsolv-0.7.2/test/testcases/lockstep/lockstep_install.t diff --git a/libsolv-0.6.15/test/testcases/lockstep/lockstep_update.t b/libsolv-0.7.2/test/testcases/lockstep/lockstep_update.t similarity index 100% rename from libsolv-0.6.15/test/testcases/lockstep/lockstep_update.t rename to libsolv-0.7.2/test/testcases/lockstep/lockstep_update.t diff --git a/libsolv-0.6.15/test/testcases/multiversion/multiversion.t b/libsolv-0.7.2/test/testcases/multiversion/multiversion.t similarity index 100% rename from libsolv-0.6.15/test/testcases/multiversion/multiversion.t rename to libsolv-0.7.2/test/testcases/multiversion/multiversion.t diff --git a/libsolv-0.7.2/test/testcases/multiversion/update.t b/libsolv-0.7.2/test/testcases/multiversion/update.t new file mode 100644 index 0000000..c3a2d9a --- /dev/null +++ b/libsolv-0.7.2/test/testcases/multiversion/update.t @@ -0,0 +1,65 @@ +repo system 0 testtags +#>=Pkg: k 1 0 x86_64 +#>=Pkg: k-m 1 0 x86_64 +#>=Req: k = 1-0 +#>=Pkg: k-freak-1-0 1 0 x86_64 +#>=Req: k = 1-0 +#>=Pkg: k 1 1 x86_64 +#>=Pkg: k-m 1 1 x86_64 +#>=Req: k = 1-1 +#>=Pkg: k 2 0 x86_64 +#>=Pkg: k-m 2 0 x86_64 +#>=Req: k = 2-0 +#>=Pkg: k 3 0 x86_64 +#>=Pkg: k-m 3 0 x86_64 +#>=Req: k = 3-0 +repo available 0 testtags +#>=Pkg: k 3 1 x86_64 +#>=Pkg: k-m 3 1 x86_64 +#>=Req: k = 3-1 +#>=Pkg: k 3 6 x86_64 +#>=Pkg: k-m 3 6 x86_64 +#>=Req: k = 3-6 +#>=Pkg: c 1 1 noarch +#>=Con: k = 3-6 +system x86_64 rpm system +poolflags implicitobsoleteusescolors + +job multiversion provides k +job multiversion provides k-m +job update all packages +result transaction,problems +#>install k-3-6.x86_64@available +#>install k-m-3-6.x86_64@available + +nextjob + +job multiversion provides k +job multiversion provides k-m +job install name c +job update all packages +result transaction,problems +#>install k-3-1.x86_64@available +#>install k-m-3-1.x86_64@available +#>install c-1-1.noarch@available + + +nextjob + +job multiversion provides k +job multiversion provides k-m +job install name c +job update all packages [forcebest] +result transaction,problems +#>install k-3-6.x86_64@available +#>install k-m-3-6.x86_64@available +#>problem ca7106eb info package c-1-1.noarch conflicts with k = 3-6 provided by k-3-6.x86_64 +#>problem ca7106eb solution 4d4bc71f allow k-1-0.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-1-1.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-2-0.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-3-0.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-m-1-0.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-m-1-1.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-m-2-0.x86_64@system +#>problem ca7106eb solution 4d4bc71f allow k-m-3-0.x86_64@system +#>problem ca7106eb solution 86764155 deljob install name c diff --git a/libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t b/libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t similarity index 74% rename from libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t rename to libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t index 62ca982..609b58a 100644 --- a/libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t +++ b/libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t @@ -11,6 +11,13 @@ repo test 0 testtags #>=Prv: locale(C:de) #>=Pkg: C-en 1 1 noarch #>=Prv: locale(C:en) +#>=Pkg: D 1 1 noarch +#>=Sup: C +#>=Pkg: E 1 1 noarch +#>=Prv: locale(F:de) +#>=Pkg: F 1 1 noarch +#>=Pkg: G 1 1 noarch +#>=Sup: F system i686 rpm system # first test an empty job @@ -24,6 +31,7 @@ solverflags addalreadyrecommended result transaction,problems #>install A-1-1.noarch@test #>install C-de-1-1.noarch@test +#>install D-1-1.noarch@test nextjob namespace namespace:language(de) @SYSTEM @@ -59,3 +67,19 @@ result transaction,problems #>erase B-1-1.noarch@system #>install A-1-1.noarch@test #>install C-de-1-1.noarch@test + +nextjob +namespace namespace:language(de) @SYSTEM +solverflags addalreadyrecommended onlynamespacerecommended +result transaction,problems +#>install A-1-1.noarch@test +#>install C-de-1-1.noarch@test + +nextjob +namespace namespace:language(de) @SYSTEM +solverflags onlynamespacerecommended +job install name F +result transaction,problems +#>install E-1-1.noarch@test +#>install F-1-1.noarch@test + diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t new file mode 100644 index 0000000..92afd75 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t @@ -0,0 +1,16 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Rec: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Con: A +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>recommended B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t new file mode 100644 index 0000000..0addaf4 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t @@ -0,0 +1,19 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Rec: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +repo other 0 testtags +#>=Pkg: B 4 1 noarch +#>=Pkg: B 6 1 noarch +#>=Pkg: B 5 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>recommended B-6-1.noarch@other diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t new file mode 100644 index 0000000..27c62f1 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Rec: B < 3 +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>recommended B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t new file mode 100644 index 0000000..2b8a842 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Rec: B = 2-1 +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>recommended B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_version.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_version.t new file mode 100644 index 0000000..b2e3637 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/recommended_version.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Rec: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>recommended B-3-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t new file mode 100644 index 0000000..8de6f3d --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t @@ -0,0 +1,16 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Sug: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Con: A +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>suggested B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t new file mode 100644 index 0000000..c0a6d8f --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t @@ -0,0 +1,19 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Sug: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +repo other 0 testtags +#>=Pkg: B 4 1 noarch +#>=Pkg: B 6 1 noarch +#>=Pkg: B 5 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>suggested B-6-1.noarch@other diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t new file mode 100644 index 0000000..b259b65 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Sug: B < 3 +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>suggested B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t new file mode 100644 index 0000000..01da811 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Sug: B = 2-1 +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>suggested B-2-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_version.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_version.t new file mode 100644 index 0000000..1af6a77 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/recommendations/suggested_version.t @@ -0,0 +1,15 @@ +repo system 0 empty +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Sug: B +#>=Pkg: B 1 1 noarch +#>=Pkg: B 3 1 noarch +#>=Pkg: B 2 1 noarch +system i686 rpm system + +solverflags ignorerecommended +job install name A + +result transaction,recommended,problems +#>install A-1-1.noarch@available +#>suggested B-3-1.noarch@available diff --git a/libsolv-0.6.15/test/testcases/sat/assert.t b/libsolv-0.7.2/test/testcases/sat/assert.t similarity index 100% rename from libsolv-0.6.15/test/testcases/sat/assert.t rename to libsolv-0.7.2/test/testcases/sat/assert.t diff --git a/libsolv-0.6.15/test/testcases/sat/mm-test.t b/libsolv-0.7.2/test/testcases/sat/mm-test.t similarity index 100% rename from libsolv-0.6.15/test/testcases/sat/mm-test.t rename to libsolv-0.7.2/test/testcases/sat/mm-test.t diff --git a/libsolv-0.7.2/test/testcases/sat/reuse.t b/libsolv-0.7.2/test/testcases/sat/reuse.t new file mode 100644 index 0000000..7abb266 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/sat/reuse.t @@ -0,0 +1,20 @@ +repo system 0 testtags +#>=Pkg: X 1 1 x86_64 +repo available 0 testtags +#>=Pkg: A 1 1 x86_64 +#>=Req: X +#>=Pkg: B 1 1 x86_64 +job install name A +result transaction,problems,rules +#>install A-1-1.x86_64@available +#>install X-1-1.x86_64@system +#>rule job 300db6ce502dde94261e267a8c535441 A-1-1.x86_64@available +#>rule pkg 11c27e407a56aad27bd6b3eadc17374b X-1-1.x86_64@system +#>rule pkg 11c27e407a56aad27bd6b3eadc17374b -A-1-1.x86_64@available +nextjob reusesolver +job install name B +result transaction,problems,rules +#>install B-1-1.x86_64@available +#>rule job ad168c1819736b8aa6f507ab075b3494 B-1-1.x86_64@available +#>rule pkg 11c27e407a56aad27bd6b3eadc17374b X-1-1.x86_64@system +#>rule pkg 11c27e407a56aad27bd6b3eadc17374b -A-1-1.x86_64@available diff --git a/libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t b/libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t new file mode 100644 index 0000000..018db31 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t @@ -0,0 +1,53 @@ +repo available 0 testtags +#>=Pkg: A 1 1 noarch +#>=Pkg: A 2 1 noarch +#>=Prv: A = 3.1 +#>=Pkg: A 2 2 i686 +#>=Pkg: A 1:1 1 i686 +#>=Pkg: A 2 2 badarch +#>=Pkg: A 1:3 1 i686 +system i686 rpm + +disable pkg E-1-1.src@available +disable pkg F-1-1.src@available + +job noop selection A-2 canon +result jobs +#>job noop name A = 2 [setev] + +nextjob +job noop selection A-2-1 canon +result jobs +#>job noop name A = 2-1 [setevr] + +nextjob +job noop selection A-3 canon +result jobs +#>job noop name A = 1:3 [setev] + +nextjob +job noop selection A-3-1 canon +result jobs +#>job noop name A = 1:3-1 [setevr] + +nextjob +job noop selection A-1 canon +result jobs +#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available + +nextjob +job noop selection A-1-1 canon +result jobs +#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available + + +nextjob +job noop selection A-0:1-1 canon +result jobs +#>job noop name A = 0:1-1 [setevr] + +nextjob +job noop selection A-1:1-1 canon +result jobs +#>job noop name A = 1:1-1 [setevr] + diff --git a/libsolv-0.7.2/test/testcases/selection/selection_filelist.t b/libsolv-0.7.2/test/testcases/selection/selection_filelist.t new file mode 100644 index 0000000..2005643 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_filelist.t @@ -0,0 +1,20 @@ +repo available 0 testtags +#>=Pkg: bash 1 1 noarch +#>=Fls: /usr/bin/bash +#>=Fls: /usr/bin/bashbug +#>=Pkg: bash 2 1 noarch +#>=Fls: /usr/bin/bash +#>=Fls: /usr/bin/bashbug +#>=Pkg: coreutils 1 1 noarch +#>=Fls: /usr/bin/basename +system i686 rpm + +job noop selection /usr/bin/ba* filelist,glob +result jobs +#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available +#>job noop pkg coreutils-1-1.noarch@available [noautoset] + +nextjob +job noop selection /usr/bin/ba* filelist,glob,flat +result jobs +#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available coreutils-1-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t b/libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t new file mode 100644 index 0000000..cdf9ebc --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t @@ -0,0 +1,54 @@ +repo available 0 testtags +#>=Pkg: A 2 1 noarch +#>=Pkg: AP 3 1 noarch +#>=Prv: A = 3.1 +#>=Pkg: A 2 2 i686 +#>=Req: BBB > 5 +#>=Pkg: B 1 1 src +#>=Pkg: A 2 2 badarch +system i686 rpm + +job noop selection_matchdeps solvable:name a = 2 rel,flat,nocase +result jobs +#>job noop oneof A-2-1.noarch@available A-2-2.i686@available + +nextjob +job noop selection_matchdeps solvable:name a = 2-* flat,glob,nocase,depstr +result jobs +#>job noop oneof A-2-1.noarch@available A-2-2.i686@available + +nextjob +job noop selection_matchdepid solvable:name A = 2-1 flat +result jobs +#>job noop pkg A-2-1.noarch@available [noautoset] + +nextjob +job noop selection_matchdepid solvable:name A = 2-2 flat,depstr +result jobs +#>job noop pkg A-2-2.i686@available [noautoset] + +nextjob +job noop selection_matchdepid solvable:name A = 2-2 flat,depstr,withbadarch +result jobs +#>job noop oneof A-2-2.i686@available A-2-2.badarch@available + +nextjob +job noop selection_matchdeps solvable:requires bbb < 10 rel,flat,nocase +result jobs +#>job noop pkg A-2-2.i686@available [noautoset] + +nextjob +job noop selection_matchdeps solvable:requires bbb >* depstr,glob,flat,nocase +result jobs +#>job noop pkg A-2-2.i686@available [noautoset] + +nextjob +job noop selection_matchdepid solvable:requires BBB < 10 flat +result jobs +#>job noop pkg A-2-2.i686@available [noautoset] + +nextjob +job noop selection_matchdepid solvable:requires BBB > 5 flat,depstr +result jobs +#>job noop pkg A-2-2.i686@available [noautoset] + diff --git a/libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t b/libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t new file mode 100644 index 0000000..545abc4 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t @@ -0,0 +1,27 @@ +repo available 0 testtags +#>=Pkg: A1 1 1 noarch +#>=Req: B > 1 + B < 3 +#>=Pkg: A2 1 1 noarch +#>=Req: B > 1 & B < 3 +#>=Pkg: X 1 1 noarch +#>=Prv: B = 4 +#>=Pkg: Y 1 1 noarch +#>=Prv: B = 2 +#>=Pkg: A1 2 1 noarch +system i686 rpm + +job noop selection_matchsolvable solvable:requires X-1-1.noarch@available flat +result jobs +#>job noop pkg A2-1-1.noarch@available [noautoset] + +nextjob +job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat +result jobs +#>job noop oneof A1-1-1.noarch@available A2-1-1.noarch@available + +nextjob +job noop selection A1 name +job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat,filter +result jobs +#>job noop pkg A1-1-1.noarch@available [noautoset] + diff --git a/libsolv-0.7.2/test/testcases/selection/selection_name.t b/libsolv-0.7.2/test/testcases/selection/selection_name.t new file mode 100644 index 0000000..b0a8520 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_name.t @@ -0,0 +1,85 @@ +repo available 0 testtags +#>=Pkg: A 2 1 noarch +#>=Pkg: AP 3 1 noarch +#>=Prv: A = 3.1 +#>=Pkg: A 2 2 i686 +#>=Req: BBB > 5 +#>=Pkg: B 1 1 src +#>=Pkg: A 2 2 badarch +#>=Pkg: C 2 2 badarch +#>=Pkg: D 2 2 noarch +#>=Pkg: D 2 2 badarch +#>=Pkg: E 1 1 src +#>=Pkg: F 1 1 src +#>=Pkg: F 1 2 src +#>=Pkg: G 1 1 src +#>=Pkg: G 1 2 src +system i686 rpm + +disable pkg E-1-1.src@available +disable pkg F-1-1.src@available + +job noop selection A name +result jobs +#>job noop name A + +nextjob +job noop selection A.i686 name,dotarch +result jobs +#>job noop name A . i686 [setarch] + +nextjob +job noop selection A.i686>1 name,dotarch,rel +result jobs +#>job noop name (A . i686) > 1 [setarch] + +nextjob +job noop selection B* glob,name,withsource +result jobs +#>job noop pkg B-1-1.src@available [noautoset] + +nextjob +job noop selection A=2-2 name,dotarch,rel,withbadarch +result jobs +#>job noop oneof A-2-2.i686@available A-2-2.badarch@available [setevr] + +nextjob +job noop selection C name,withbadarch +result jobs +#>job noop pkg C-2-2.badarch@available [noautoset] + +nextjob +job noop selection D name,withbadarch +result jobs +#>job noop oneof D-2-2.noarch@available D-2-2.badarch@available + +nextjob +job noop selection E name,sourceonly,withdisabled +result jobs +#>job noop pkg E-1-1.src@available [noautoset] + +nextjob +job noop selection E name,withsource,withdisabled +result jobs +#>job noop pkg E-1-1.src@available [noautoset] + +nextjob +job noop selection F name,sourceonly,withdisabled +result jobs +#>job noop oneof F-1-1.src@available F-1-2.src@available + +nextjob +job noop selection F name,withsource,withdisabled +result jobs +#>job noop oneof F-1-1.src@available F-1-2.src@available + +nextjob +job noop selection G name,sourceonly,withdisabled +result jobs +#>job noop name G . src + +nextjob +job noop selection G name,withsource,withdisabled +result jobs +#>job noop oneof G-1-1.src@available G-1-2.src@available + diff --git a/libsolv-0.7.2/test/testcases/selection/selection_provides.t b/libsolv-0.7.2/test/testcases/selection/selection_provides.t new file mode 100644 index 0000000..cb3a029 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/selection/selection_provides.t @@ -0,0 +1,49 @@ +repo available 0 testtags +#>=Pkg: A 2 1 noarch +#>=Pkg: AP 3 1 noarch +#>=Prv: A = 3.1 +#>=Pkg: A 2 2 i686 +#>=Req: BBB > 5 +#>=Pkg: B 1 1 src +#>=Pkg: A 2 2 badarch +#>=Pkg: C 2 2 badarch +#>=Pkg: D 2 2 badarch +#>=Pkg: D 2 2 noarch +system i686 rpm + +job noop selection A provides +result jobs +#>job noop provides A + +nextjob +job noop selection A.i686 provides,dotarch +result jobs +#>job noop provides A . i686 [setarch] + +nextjob +job noop selection A.i686>1 provides,dotarch,rel +result jobs +#>job noop provides (A . i686) > 1 [setarch] + +nextjob +job noop selection A* glob,provides,withbadarch +result jobs +#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available +#>job noop provides AP + +nextjob +job noop selection A*>=2 glob,provides,dotarch,rel,withbadarch +result jobs +#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available +#>job noop provides AP >= 2 + +nextjob +job noop selection C provides,withbadarch +result jobs +#>job noop pkg C-2-2.badarch@available [noautoset] + + +nextjob +job noop selection D provides,withbadarch +result jobs +#>job noop oneof D-2-2.badarch@available D-2-2.noarch@available diff --git a/libsolv-0.7.2/test/testcases/strongrecommends/break.t b/libsolv-0.7.2/test/testcases/strongrecommends/break.t new file mode 100644 index 0000000..54031c0 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/strongrecommends/break.t @@ -0,0 +1,28 @@ +# +# A recommends B and B recommends C +# +# With strongrecommends, we get the following +# rules: +# A -> B +# B -> C +# after pkg rules sorting, this will be (-B is less than -A) +# B -> C (weak) +# A -> B (weak) +# If just the last weak rule is broken, only A will be +# installed but but B. So the code now breaks all weak +# recommends rules. +repo system 0 testtags +#>=Pkg: X 1 1 noarch +#>=Con: C +repo available 0 testtags +#>=Pkg: A 1 2 noarch +#>=Rec: B +#>=Pkg: B 1 1 noarch +#>=Rec: C +#>=Pkg: C 1 1 noarch +system i686 rpm system +solverflags strongrecommends +job install name A +result transaction,problems +#>install A-1-2.noarch@available +#>install B-1-1.noarch@available diff --git a/libsolv-0.7.2/test/testcases/strongrecommends/strongr.t b/libsolv-0.7.2/test/testcases/strongrecommends/strongr.t new file mode 100644 index 0000000..e6f5295 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/strongrecommends/strongr.t @@ -0,0 +1,27 @@ +# test strong recommends +# +# with normal recommends, the solver will +# not backtrack to fulfill them. +# +repo system 0 testtags +#>=Pkg: A 1 1 noarch +#>=Con: C +#>=Pkg: A2 1 1 noarch +#>=Con: C2 +repo available 0 testtags +#>=Pkg: A 1 2 noarch +#>=Pkg: B 1 1 noarch +#>=Rec: C +#>=Pkg: C 1 1 noarch +#>=Pkg: B2 1 1 noarch +#>=Rec: C2 +#>=Pkg: C2 1 1 noarch +system i686 rpm system +solverflags strongrecommends +job install name B +job install name B2 +result transaction,problems +#>install B-1-1.noarch@available +#>install B2-1-1.noarch@available +#>install C-1-1.noarch@available +#>upgrade A-1-1.noarch@system A-1-2.noarch@available diff --git a/libsolv-0.6.15/test/testcases/targeted/targeted_dup.t b/libsolv-0.7.2/test/testcases/targeted/targeted_dup.t similarity index 100% rename from libsolv-0.6.15/test/testcases/targeted/targeted_dup.t rename to libsolv-0.7.2/test/testcases/targeted/targeted_dup.t diff --git a/libsolv-0.6.15/test/testcases/targeted/targeted_up.t b/libsolv-0.7.2/test/testcases/targeted/targeted_up.t similarity index 97% rename from libsolv-0.6.15/test/testcases/targeted/targeted_up.t rename to libsolv-0.7.2/test/testcases/targeted/targeted_up.t index 1ab09e4..a3cdd45 100644 --- a/libsolv-0.6.15/test/testcases/targeted/targeted_up.t +++ b/libsolv-0.7.2/test/testcases/targeted/targeted_up.t @@ -40,7 +40,7 @@ result transaction,problems # second check forced to untargeted nextjob solverflags noautotarget -job distupgrade name A = 2-1 +job update name A = 2-1 result transaction,problems # then targeted to D diff --git a/libsolv-0.7.2/test/testcases/testcase/nested.t b/libsolv-0.7.2/test/testcases/testcase/nested.t new file mode 100644 index 0000000..355f014 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/testcase/nested.t @@ -0,0 +1,56 @@ +# regression test for testcase_dep2str of deeply nested dependencies +# this used to segfault or return wrong roundtrip results +genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y |z +result genid +#>genid 1: genid lit a +#>genid 2: genid lit b +#>genid 3: genid lit c +#>genid 4: genid lit d +#>genid 5: genid lit e +#>genid 6: genid lit f +#>genid 7: genid lit g +#>genid 8: genid lit h +#>genid 9: genid lit i +#>genid 10: genid lit j +#>genid 11: genid lit k +#>genid 12: genid lit l +#>genid 13: genid lit m +#>genid 14: genid lit n +#>genid 15: genid lit o +#>genid 16: genid lit p +#>genid 17: genid lit q +#>genid 18: genid lit r +#>genid 19: genid lit s +#>genid 20: genid lit t +#>genid 21: genid lit u +#>genid 22: genid lit v +#>genid 23: genid lit w +#>genid 24: genid lit x +#>genid 25: genid lit y +#>genid 26: genid lit z +#>genid 27: genid op | +#>genid 28: genid op | +#>genid 29: genid op | +#>genid 30: genid op | +#>genid 31: genid op | +#>genid 32: genid op | +#>genid 33: genid op | +#>genid 34: genid op | +#>genid 35: genid op | +#>genid 36: genid op | +#>genid 37: genid op | +#>genid 38: genid op | +#>genid 39: genid op | +#>genid 40: genid op | +#>genid 41: genid op | +#>genid 42: genid op | +#>genid 43: genid op | +#>genid 44: genid op | +#>genid 45: genid op | +#>genid 46: genid op | +#>genid 47: genid op | +#>genid 48: genid op | +#>genid 49: genid op | +#>genid 50: genid op | +#>genid 51: genid op | +#>genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z diff --git a/libsolv-0.6.15/test/testcases/testcase/str2dep.t b/libsolv-0.7.2/test/testcases/testcase/str2dep.t similarity index 100% rename from libsolv-0.6.15/test/testcases/testcase/str2dep.t rename to libsolv-0.7.2/test/testcases/testcase/str2dep.t diff --git a/libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t b/libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t new file mode 100644 index 0000000..6de4544 --- /dev/null +++ b/libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t @@ -0,0 +1,20 @@ +repo system 0 empty +repo test 0 testtags +#>=Ver: 2.0 +#>=Pkg: A 1 1 noarch +#>=Pkg: B 1 1 x86_64 +#>=Sup: A +#>=Pkg: B 1 1 i686 +#>=Sup: A +#>=Pkg: A2 1 1 noarch +#>=Pkg: B2 1 1 x86_64 +#>=Sup: A2 +#>=Req: XX +#>=Pkg: B2 1 1 i686 +#>=Sup: A2 +system x86_64 * system +poolflags implicitobsoleteusescolors +job install name A + +nextjob +job install name A2 diff --git a/libsolv-0.6.15/test/testcases/yumobs/split.t b/libsolv-0.7.2/test/testcases/yumobs/split.t similarity index 100% rename from libsolv-0.6.15/test/testcases/yumobs/split.t rename to libsolv-0.7.2/test/testcases/yumobs/split.t diff --git a/libsolv-0.6.15/tools/CMakeLists.txt b/libsolv-0.7.2/tools/CMakeLists.txt similarity index 91% rename from libsolv-0.6.15/tools/CMakeLists.txt rename to libsolv-0.7.2/tools/CMakeLists.txt index 16fa097..802dc50 100644 --- a/libsolv-0.6.15/tools/CMakeLists.txt +++ b/libsolv-0.7.2/tools/CMakeLists.txt @@ -4,21 +4,24 @@ ADD_LIBRARY (toolstuff STATIC common_write.c) -SET (tools_list mergesolv dumpsolv installcheck testsolv) +SET (tools_list mergesolv dumpsolv installcheck testsolv repo2solv) IF (ENABLE_RPMDB) ADD_EXECUTABLE (rpmdb2solv rpmdb2solv.c) TARGET_LINK_LIBRARIES (rpmdb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) -ADD_EXECUTABLE (rpms2solv rpms2solv.c) -TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) - ADD_EXECUTABLE (findfileconflicts findfileconflicts.c) TARGET_LINK_LIBRARIES (findfileconflicts libsolvext libsolv ${SYSTEM_LIBRARIES}) -SET (tools_list ${tools_list} rpmdb2solv rpms2solv) +SET (tools_list ${tools_list} rpmdb2solv) ENDIF (ENABLE_RPMDB) +IF (ENABLE_RPMPKG) +ADD_EXECUTABLE (rpms2solv rpms2solv.c) +TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) +SET (tools_list ${tools_list} rpms2solv) +ENDIF (ENABLE_RPMPKG) + IF (ENABLE_RPMMD) ADD_EXECUTABLE (repomdxml2solv repomdxml2solv.c) TARGET_LINK_LIBRARIES (repomdxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) @@ -88,11 +91,6 @@ ENDIF (ENABLE_CUDFREPO) ADD_EXECUTABLE (installcheck installcheck.c) TARGET_LINK_LIBRARIES (installcheck libsolvext libsolv ${SYSTEM_LIBRARIES}) -IF (SUSE) -ADD_EXECUTABLE (patchcheck patchcheck.c) -TARGET_LINK_LIBRARIES (patchcheck libsolvext libsolv ${SYSTEM_LIBRARIES}) -ENDIF (SUSE) - IF (ENABLE_APPDATA) ADD_EXECUTABLE (appdata2solv appdata2solv.c) TARGET_LINK_LIBRARIES (appdata2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) @@ -109,6 +107,8 @@ TARGET_LINK_LIBRARIES (mergesolv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES ADD_EXECUTABLE (testsolv testsolv.c) TARGET_LINK_LIBRARIES (testsolv libsolvext libsolv ${SYSTEM_LIBRARIES}) +ADD_EXECUTABLE (repo2solv repo2solv.c ) +TARGET_LINK_LIBRARIES (repo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}) + INSTALL (TARGETS ${tools_list} DESTINATION ${BIN_INSTALL_DIR}) -INSTALL (PROGRAMS repo2solv.sh DESTINATION ${BIN_INSTALL_DIR}) diff --git a/libsolv-0.6.15/tools/appdata2solv.c b/libsolv-0.7.2/tools/appdata2solv.c similarity index 95% rename from libsolv-0.6.15/tools/appdata2solv.c rename to libsolv-0.7.2/tools/appdata2solv.c index a8753a1..e5a42cf 100644 --- a/libsolv-0.6.15/tools/appdata2solv.c +++ b/libsolv-0.7.2/tools/appdata2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include @@ -72,7 +70,7 @@ main(int argc, char **argv) exit(1); } } - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/archpkgs2solv.c b/libsolv-0.7.2/tools/archpkgs2solv.c similarity index 93% rename from libsolv-0.6.15/tools/archpkgs2solv.c rename to libsolv-0.7.2/tools/archpkgs2solv.c index 4ce95a4..14c3ba4 100644 --- a/libsolv-0.6.15/tools/archpkgs2solv.c +++ b/libsolv-0.7.2/tools/archpkgs2solv.c @@ -57,16 +57,12 @@ main(int argc, char **argv) Repo *repo; FILE *fp; char buf[4096], *p; - const char *basefile = 0; int flags = 0; - while ((c = getopt(argc, argv, "0b:m:i")) >= 0) + while ((c = getopt(argc, argv, "0:m:i")) >= 0) { switch(c) { - case 'b': - basefile = optarg; - break; case 'm': manifest = optarg; break; @@ -124,7 +120,7 @@ main(int argc, char **argv) res = 1; } repo_internalize(repo); - tool_write(repo, basefile, 0); + tool_write(repo, stdout); pool_free(pool); for (c = 0; c < npkgs; c++) solv_free((char *)pkgs[c]); diff --git a/libsolv-0.6.15/tools/archrepo2solv.c b/libsolv-0.7.2/tools/archrepo2solv.c similarity index 94% rename from libsolv-0.6.15/tools/archrepo2solv.c rename to libsolv-0.7.2/tools/archrepo2solv.c index 6dcb076..e60960f 100644 --- a/libsolv-0.6.15/tools/archrepo2solv.c +++ b/libsolv-0.7.2/tools/archrepo2solv.c @@ -15,12 +15,10 @@ */ #include -#include -#include #include #include #include -#include +#include #include "pool.h" #include "repo.h" @@ -75,7 +73,7 @@ main(int argc, char **argv) fprintf(stderr, "archrepo2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.7.2/tools/common_write.c b/libsolv-0.7.2/tools/common_write.c new file mode 100644 index 0000000..36f8dd8 --- /dev/null +++ b/libsolv-0.7.2/tools/common_write.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_write.h" +#include "common_write.h" +#include "solvversion.h" + +/* toolversion history + * 1.0: initial tool version + * 1.1: changed PRODUCT_ENDOFLIFE parsing +*/ + +static int +keyfilter_solv(Repo *repo, Repokey *key, void *kfdata) +{ + if (key->name == SUSETAGS_SHARE_NAME || key->name == SUSETAGS_SHARE_EVR || key->name == SUSETAGS_SHARE_ARCH) + return KEY_STORAGE_DROPPED; + return repo_write_stdkeyfilter(repo, key, kfdata); +} + +/* + * Write to fp + */ +void +tool_write(Repo *repo, FILE *fp) +{ + Repodata *info; + Queue addedfileprovides; + Repowriter *writer; + + info = repo_add_repodata(repo, 0); /* add new repodata for our meta info */ + repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION); + repodata_unset(info, SOLVID_META, REPOSITORY_EXTERNAL); /* do not propagate this */ + + queue_init(&addedfileprovides); + pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0); + if (addedfileprovides.count) + repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides); + else + repodata_unset(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES); + queue_free(&addedfileprovides); + + pool_freeidhashes(repo->pool); /* free some mem */ + + repodata_internalize(info); + writer = repowriter_create(repo); + repowriter_set_keyfilter(writer, keyfilter_solv, 0); + if (repowriter_write(writer, fp) != 0) + { + fprintf(stderr, "repo write failed: %s\n", pool_errstr(repo->pool)); + exit(1); + } + if (fflush(fp)) + { + perror("fflush"); + exit(1); + } + repowriter_free(writer); + repodata_free(info); /* delete meta info repodata again */ +} diff --git a/libsolv-0.6.15/tools/common_write.h b/libsolv-0.7.2/tools/common_write.h similarity index 74% rename from libsolv-0.6.15/tools/common_write.h rename to libsolv-0.7.2/tools/common_write.h index 7630edd..fda1fd5 100644 --- a/libsolv-0.6.15/tools/common_write.h +++ b/libsolv-0.7.2/tools/common_write.h @@ -10,6 +10,6 @@ #include "repo.h" -void tool_write(Repo *repo, const char *basename, const char *attrname); +void tool_write(Repo *repo, FILE *fp); #endif diff --git a/libsolv-0.6.15/tools/comps2solv.c b/libsolv-0.7.2/tools/comps2solv.c similarity index 91% rename from libsolv-0.6.15/tools/comps2solv.c rename to libsolv-0.7.2/tools/comps2solv.c index 73854d2..ebb39b5 100644 --- a/libsolv-0.6.15/tools/comps2solv.c +++ b/libsolv-0.7.2/tools/comps2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include @@ -36,7 +34,7 @@ main(int argc, char **argv) fprintf(stderr, "comps2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/cudftest.c b/libsolv-0.7.2/tools/cudftest.c similarity index 100% rename from libsolv-0.6.15/tools/cudftest.c rename to libsolv-0.7.2/tools/cudftest.c diff --git a/libsolv-0.6.15/tools/deb2solv.c b/libsolv-0.7.2/tools/deb2solv.c similarity index 76% rename from libsolv-0.6.15/tools/deb2solv.c rename to libsolv-0.7.2/tools/deb2solv.c index 0d22f24..ad27541 100644 --- a/libsolv-0.6.15/tools/deb2solv.c +++ b/libsolv-0.7.2/tools/deb2solv.c @@ -58,17 +58,18 @@ main(int argc, char **argv) FILE *fp; char buf[4096], *p; const char *basefile = 0; + int is_repo = 0; - while ((c = getopt(argc, argv, "0b:m:")) >= 0) + while ((c = getopt(argc, argv, "0:m:r")) >= 0) { switch(c) { - case 'b': - basefile = optarg; - break; case 'm': manifest = optarg; break; + case 'r': + is_repo = 1; + break; case '0': manifest0 = 1; break; @@ -113,8 +114,32 @@ main(int argc, char **argv) repo = repo_create(pool, "deb2solv"); repo_add_repodata(repo, 0); res = 0; + if (!ndebs && !manifest && is_repo) + { + if (repo_add_debpackages(repo, stdin, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE)) + { + fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool)); + res = 1; + } + } for (i = 0; i < ndebs; i++) { + if (is_repo) + { + if ((fp = fopen(debs[i], "r")) == 0) + { + perror(debs[i]); + res = 1; + continue; + } + if (repo_add_debpackages(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE)) + { + fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool)); + res = 1; + } + fclose(fp); + continue; + } if (repo_add_deb(repo, debs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0) { fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool)); @@ -122,7 +147,7 @@ main(int argc, char **argv) } } repo_internalize(repo); - tool_write(repo, basefile, 0); + tool_write(repo, stdout); pool_free(pool); for (c = 0; c < ndebs; c++) free((char *)debs[c]); diff --git a/libsolv-0.6.15/tools/deltainfoxml2solv.c b/libsolv-0.7.2/tools/deltainfoxml2solv.c similarity index 76% rename from libsolv-0.6.15/tools/deltainfoxml2solv.c rename to libsolv-0.7.2/tools/deltainfoxml2solv.c index 41616ba..906b3ad 100644 --- a/libsolv-0.6.15/tools/deltainfoxml2solv.c +++ b/libsolv-0.7.2/tools/deltainfoxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -22,10 +20,9 @@ static void usage(int status) { fprintf(stderr, "\nUsage:\n" - "deltainfoxml2solv [-a][-h][-n ]\n" + "deltainfoxml2solv [-h]\n" " reads a 'deltainfo.xml' file from and writes a .solv file to \n" " -h : print help & exit\n" - " -n : save attributes as .attr\n" ); exit(status); } @@ -34,21 +31,17 @@ int main(int argc, char **argv) { int c, flags = 0; - char *attrname = 0; Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); - while ((c = getopt(argc, argv, "hn:")) >= 0) + while ((c = getopt(argc, argv, "h")) >= 0) { switch(c) { case 'h': usage(0); break; - case 'n': - attrname = optarg; - break; default: usage(1); break; @@ -59,7 +52,7 @@ main(int argc, char **argv) fprintf(stderr, "deltainfoxml2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, attrname); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/diskusagexml2solv.c b/libsolv-0.7.2/tools/diskusagexml2solv.c similarity index 79% rename from libsolv-0.6.15/tools/diskusagexml2solv.c rename to libsolv-0.7.2/tools/diskusagexml2solv.c index 59ac79a..850b02c 100644 --- a/libsolv-0.6.15/tools/diskusagexml2solv.c +++ b/libsolv-0.7.2/tools/diskusagexml2solv.c @@ -22,10 +22,9 @@ static void usage(int status) { fprintf(stderr, "\nUsage:\n" - "diskusagexml2solv [-a][-h][-n ]\n" + "diskusagexml2solv [-h]\n" " reads a 'diskusage.xml' file from and writes a .solv file to \n" " -h : print help & exit\n" - " -n : save attributes as .attr\n" ); exit(status); } @@ -34,21 +33,17 @@ int main(int argc, char **argv) { int c, flags = 0; - char *attrname = 0; Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); - while ((c = getopt(argc, argv, "hn:")) >= 0) + while ((c = getopt(argc, argv, "h")) >= 0) { switch(c) { case 'h': usage(0); break; - case 'n': - attrname = optarg; - break; default: usage(1); break; @@ -59,7 +54,7 @@ main(int argc, char **argv) fprintf(stderr, "diskusagexml2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, attrname); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/dumpsolv.c b/libsolv-0.7.2/tools/dumpsolv.c similarity index 99% rename from libsolv-0.6.15/tools/dumpsolv.c rename to libsolv-0.7.2/tools/dumpsolv.c index 1aaee16..bdd521e 100644 --- a/libsolv-0.6.15/tools/dumpsolv.c +++ b/libsolv-0.7.2/tools/dumpsolv.c @@ -54,7 +54,6 @@ dump_attr(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv) case REPOKEY_TYPE_VOID: printf("%s: (void)\n", keyname); break; - case REPOKEY_TYPE_U32: case REPOKEY_TYPE_CONSTANT: printf("%s: %u\n", keyname, kv->num); break; @@ -225,7 +224,6 @@ dump_attr_json(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv, struct cb case REPOKEY_TYPE_VOID: printf("null"); break; - case REPOKEY_TYPE_U32: case REPOKEY_TYPE_CONSTANT: printf("%u", kv->num); break; diff --git a/libsolv-0.6.15/tools/findfileconflicts.c b/libsolv-0.7.2/tools/findfileconflicts.c similarity index 100% rename from libsolv-0.6.15/tools/findfileconflicts.c rename to libsolv-0.7.2/tools/findfileconflicts.c diff --git a/libsolv-0.6.15/tools/helix2solv.c b/libsolv-0.7.2/tools/helix2solv.c similarity index 91% rename from libsolv-0.6.15/tools/helix2solv.c rename to libsolv-0.7.2/tools/helix2solv.c index d893fb1..8ab531e 100644 --- a/libsolv-0.6.15/tools/helix2solv.c +++ b/libsolv-0.7.2/tools/helix2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include @@ -35,7 +33,7 @@ main(int argc, char **argv) fprintf(stderr, "helix2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/installcheck.c b/libsolv-0.7.2/tools/installcheck.c similarity index 96% rename from libsolv-0.6.15/tools/installcheck.c rename to libsolv-0.7.2/tools/installcheck.c index e8be171..6c090d8 100644 --- a/libsolv-0.6.15/tools/installcheck.c +++ b/libsolv-0.7.2/tools/installcheck.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "pool.h" #include "poolarch.h" @@ -49,6 +48,7 @@ usage(char** argv) exit(1); } +#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) static int strlen_comp(const char *str) { @@ -63,6 +63,7 @@ strlen_comp(const char *str) return l - 5; return l; } +#endif int main(int argc, char **argv) @@ -97,7 +98,10 @@ main(int argc, char **argv) for (i = 2; i < argc; i++) { FILE *fp; - int r, l; + int r; +#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) + int l; +#endif if (!strcmp(argv[i], "--withsrc")) { @@ -126,7 +130,9 @@ main(int argc, char **argv) ++i; continue; } +#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO) l = strlen_comp(argv[i]); +#endif if (!strcmp(argv[i], "-")) fp = stdin; else if ((fp = solv_xfopen(argv[i], 0)) == 0) diff --git a/libsolv-0.6.15/tools/mdk2solv.c b/libsolv-0.7.2/tools/mdk2solv.c similarity index 94% rename from libsolv-0.6.15/tools/mdk2solv.c rename to libsolv-0.7.2/tools/mdk2solv.c index dcf9d6f..3a6cf94 100644 --- a/libsolv-0.6.15/tools/mdk2solv.c +++ b/libsolv-0.7.2/tools/mdk2solv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Novell Inc. + * Copyright (c) 2012, Novell Inc.); * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -15,12 +15,10 @@ */ #include -#include -#include #include #include #include -#include +#include #include "pool.h" #include "repo.h" @@ -106,7 +104,7 @@ main(int argc, char **argv) fclose(fp); } repo_internalize(repo); - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/mergesolv.c b/libsolv-0.7.2/tools/mergesolv.c similarity index 90% rename from libsolv-0.6.15/tools/mergesolv.c rename to libsolv-0.7.2/tools/mergesolv.c index 6719c8c..8746ac6 100644 --- a/libsolv-0.6.15/tools/mergesolv.c +++ b/libsolv-0.7.2/tools/mergesolv.c @@ -12,8 +12,6 @@ #include #include -#include -#include #include #include #include @@ -62,7 +60,6 @@ main(int argc, char **argv) { Pool *pool; Repo *repo; - const char *basefile = 0; int with_attr = 0; #ifdef SUSE int add_auto = 0; @@ -72,7 +69,7 @@ main(int argc, char **argv) pool = pool_create(); repo = repo_create(pool, ""); - while ((c = getopt(argc, argv, "ahb:X")) >= 0) + while ((c = getopt(argc, argv, "ahX")) >= 0) { switch (c) { @@ -82,9 +79,6 @@ main(int argc, char **argv) case 'a': with_attr = 1; break; - case 'b': - basefile = optarg; - break; case 'X': #ifdef SUSE add_auto = 1; @@ -117,7 +111,7 @@ main(int argc, char **argv) if (add_auto) repo_add_autopattern(repo, 0); #endif - tool_write(repo, basefile, 0); + tool_write(repo, stdout); pool_free(pool); return 0; } diff --git a/libsolv-0.7.2/tools/repo2solv.c b/libsolv-0.7.2/tools/repo2solv.c new file mode 100644 index 0000000..d5b3328 --- /dev/null +++ b/libsolv-0.7.2/tools/repo2solv.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2018, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" + +#ifdef ENABLE_RPMPKG +#include "repo_rpmdb.h" +#endif + +#ifdef ENABLE_RPMMD +#include "repo_repomdxml.h" +#include "repo_rpmmd.h" +#include "repo_updateinfoxml.h" +#include "repo_deltainfoxml.h" +#endif + +#ifdef ENABLE_SUSEREPO +#include "repo_content.h" +#include "repo_susetags.h" +#endif + +#ifdef SUSE +#include "repo_autopattern.h" +#endif +#ifdef ENABLE_APPDATA +#include "repo_appdata.h" +#endif +#include "common_write.h" +#include "solv_xfopen.h" + + +#ifdef SUSE +int add_auto = 0; +#endif +#ifdef ENABLE_APPDATA +int add_appdata = 0; +#endif +int recursive = 0; +int add_filelist = 0; +int add_changelog = 0; +int filtered_filelist = 0; + + +#define REPO_PLAINDIR 1 +#define REPO_RPMMD 2 +#define REPO_RPMMD_REPODATA 3 +#define REPO_SUSETAGS 4 + +int +autodetect_repotype(Pool *pool, const char *dir) +{ + struct stat stb; + char *tmp; + FILE *fp; + + tmp = pool_tmpjoin(pool, dir, "/repomd.xml", 0); + if (stat(tmp, &stb) == 0) + return REPO_RPMMD; + tmp = pool_tmpjoin(pool, dir, "/repodata/repomd.xml", 0); + if (stat(tmp, &stb) == 0) + return REPO_RPMMD_REPODATA; + tmp = pool_tmpjoin(pool, dir, "/content", 0); + if ((fp = fopen(tmp, "r")) != 0) + { + char buf[512], *descrdir = 0; + while (fgets(buf, sizeof(buf), fp)) + { + int l = strlen(buf); + char *bp = buf; + if (buf[l - 1] != '\n') + { + int c; + while ((c = getc(fp)) != EOF && c != '\n') + ; + continue; + } + while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t')) + l--; + buf[l] = 0; + while (*bp == ' ' || *bp == '\t') + bp++; + if (strncmp(bp, "DESCRDIR", 8) != 0 || (bp[8] != ' ' && bp[8] != '\t')) + continue; + bp += 9; + while (*bp == ' ' || *bp == '\t') + bp++; + descrdir = bp; + break; + } + fclose(fp); + if (descrdir) + { + tmp = pool_tmpjoin(pool, dir, "/", descrdir); + if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode)) + return REPO_SUSETAGS; + } + } + tmp = pool_tmpjoin(pool, dir, "/suse/setup/descr", 0); + if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode)) + return REPO_SUSETAGS; + return REPO_PLAINDIR; +} + + +#ifdef ENABLE_RPMPKG + +int +read_plaindir_repo(Repo *repo, const char *dir) +{ + Pool *pool = repo->pool; + Repodata *data; + int c; + FILE *fp; + int wstatus; + int fds[2]; + pid_t pid; + char *buf = 0; + char *buf_end = 0; + char *bp = 0; + char *rpm; + int res = 0; + Id p; + + /* run find command */ + if (pipe(fds)) + { + perror("pipe"); + exit(1); + } + while ((pid = fork()) == (pid_t)-1) + { + if (errno != EAGAIN) + { + perror("fork"); + exit(1); + } + sleep(3); + } + if (pid == 0) + { + if (chdir(dir)) + { + perror(dir); + _exit(1); + } + close(fds[0]); + if (fds[1] != 1) + { + if (dup2(fds[1], 1) == -1) + { + perror("dup2"); + _exit(1); + } + close(fds[1]); + } + if (recursive) + execl("/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0); + else + execl("/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0); + perror("/usr/bin/find"); + _exit(1); + } + close(fds[1]); + if ((fp = fdopen(fds[0], "r")) == 0) + { + perror("fdopen"); + exit(1); + } + data = repo_add_repodata(repo, 0); + bp = buf; + while ((c = getc(fp)) != EOF) + { + if (bp == buf_end) + { + size_t len = bp - buf; + buf = solv_realloc(buf, len + 4096); + bp = buf + len; + buf_end = bp + 4096; + } + *bp++ = c; + if (c) + continue; + bp = buf; + rpm = solv_dupjoin(dir, "/", bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp); + if ((p = repo_add_rpm(repo, rpm, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0) + { + fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool)); +#if 0 + res = 1; +#endif + } + else + repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp); + solv_free(rpm); + } + fclose(fp); + while (waitpid(pid, &wstatus, 0) == -1) + { + if (errno == EINTR) + continue; + perror("waitpid"); + exit(1); + } + if (wstatus) + { + fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8); +#if 0 + res = 1; +#endif + } + repo_internalize(repo); + return res; +} + +#else + +int +read_plaindir_repo(Repo *repo, const char *dir) +{ + fprintf(stderr, "plaindir repo type is not supported\n"); + exit(1); +} + +#endif + +#ifdef ENABLE_SUSEREPO + +static const char * +susetags_find(char **files, int nfiles, const char *what) +{ + int i; + size_t l = strlen(what); + for (i = 0; i < nfiles; i++) + { + char *fn = files[i]; + if (strncmp(fn, what, l) != 0) + continue; + if (fn[l] == 0) + return fn; + if (fn[l] != '.') + continue; + if (strchr(fn + l + 1, '.') != 0) + continue; + if (solv_xfopen_iscompressed(fn) <= 0) + continue; + return fn; + } + return 0; +} + +static FILE * +susetags_open(const char *dir, const char *filename, char **tmpp, int missingok) +{ + FILE *fp; + if (!filename) + { + *tmpp = 0; + return 0; + } + *tmpp = solv_dupjoin(dir, "/", filename); + if ((fp = solv_xfopen(*tmpp, "r")) == 0) + { + if (!missingok) + { + perror(*tmpp); + exit(1); + } + *tmpp = solv_free(*tmpp); + return 0; + } + return fp; +} + +static void +susetags_extend(Repo *repo, const char *dir, char **files, int nfiles, char *what, Id defvendor, char *language, int missingok) +{ + const char *filename; + FILE *fp; + char *tmp; + + filename = susetags_find(files, nfiles, what); + if (!filename) + return; + if ((fp = susetags_open(dir, filename, &tmp, missingok)) != 0) + { + if (repo_add_susetags(repo, fp, defvendor, language, REPO_EXTEND_SOLVABLES)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool)); + exit(1); + } + fclose(fp); + solv_free(tmp); + } +} + +static void +susetags_extend_languages(Repo *repo, const char *dir, char **files, int nfiles, Id defvendor, int missingok) +{ + int i; + for (i = 0; i < nfiles; i++) + { + char *fn = files[i]; + char lang[64], *p; + if (strncmp(fn, "packages.", 9) != 0) + continue; + if (strlen(fn + 9) + 1 >= sizeof(lang)) + continue; + strncpy(lang, fn + 9, sizeof(lang) - 1); + lang[sizeof(lang) - 1] = 0; + p = strrchr(lang, '.'); + if (p) + { + if (solv_xfopen_iscompressed(lang) <= 0) + continue; + *p = 0; + } + if (strchr(lang, '.')) + continue; + if (!strcmp(lang, "en")) + continue; /* already did that one */ + if (!strcmp(lang, "DU")) + continue; /* disk usage */ + if (!strcmp(lang, "FL")) + continue; /* file list */ + if (!strcmp(lang, "DL")) + continue; /* deltas */ + susetags_extend(repo, dir, files, nfiles, fn, defvendor, lang, missingok); + } +} + +static int +susetags_dircmp(const void *ap, const void *bp, void *dp) +{ + return strcmp(*(const char **)ap, *(const char **)bp); +} + +int +read_susetags_repo(Repo *repo, const char *dir) +{ + Pool *pool = repo->pool; + const char *filename; + char *ddir; + char *tmp; + FILE *fp; + Id defvendor = 0; + const char *descrdir = 0; + char **files = 0; + int nfiles = 0; + DIR *dp; + struct dirent *de; + + /* read content file */ + repo_add_repodata(repo, 0); + tmp = solv_dupjoin(dir, "/content", 0); + if ((fp = fopen(tmp, "r")) != 0) + { + if (repo_add_content(repo, fp, REPO_REUSE_REPODATA)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); + defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); + } + if (!descrdir) + descrdir = "suse/setup/descr"; + tmp = solv_free(tmp); + + /* get content of descrdir directory */ + ddir = solv_dupjoin(dir, "/", descrdir); + if ((dp = opendir(ddir)) == 0) + { + perror(ddir); + exit(1); + } + while ((de = readdir(dp)) != 0) + { + if (de->d_name[0] == 0 || de->d_name[0] == '.') + continue; + files = solv_extend(files, nfiles, 1, sizeof(char *), 63); + files[nfiles++] = solv_strdup(de->d_name); + } + closedir(dp); + if (nfiles > 1) + solv_sort(files, nfiles, sizeof(char *), susetags_dircmp, 0); + + /* add packages */ + filename = susetags_find(files, nfiles, "packages"); + if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0) + { + if (repo_add_susetags(repo, fp, defvendor, 0, SUSETAGS_RECORD_SHARES)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + + /* now extend the packages */ + susetags_extend(repo, ddir, files, nfiles, "packages.DU", defvendor, 0, 1); + susetags_extend(repo, ddir, files, nfiles, "packages.en", defvendor, 0, 1); + susetags_extend_languages(repo, ddir, files, nfiles, defvendor, 1); + if (add_filelist) + susetags_extend(repo, ddir, files, nfiles, "packages.FL", defvendor, 0, 1); + } + + /* add deltas */ + filename = susetags_find(files, nfiles, "packages.DL"); + if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0) + { + if (repo_add_susetags(repo, fp, defvendor, 0, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } + + /* add legacy patterns */ + tmp = solv_dupjoin(ddir, "/patterns", 0); + if ((fp = fopen(tmp, "r")) != 0) + { + char pbuf[4096]; + + repo_add_repodata(repo, 0); + while (fgets(pbuf, sizeof(pbuf), fp)) + { + char *p; + FILE *pfp; + if (strchr(pbuf, '/') != 0) + continue; + if ((p = strchr(pbuf, '\n')) != 0) + *p = 0; + if (*pbuf == 0) + continue; + solv_free(tmp); + tmp = solv_dupjoin(ddir, "/", pbuf); + if ((pfp = solv_xfopen(tmp, "r")) != 0) + { + if (repo_add_susetags(repo, pfp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(pfp); + } + } + fclose(fp); + } + tmp = solv_free(tmp); + +#ifdef ENABLE_APPDATA + /* appdata */ + filename = add_appdata ? susetags_find(files, nfiles, "appdata.xml") : 0; + if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } +#endif + + while (nfiles > 0) + solv_free(files[--nfiles]); + solv_free(files); + solv_free(ddir); + repo_internalize(repo); + return 0; +} + +#else + +int +read_susetags_repo(Repo *repo, const char *dir) +{ + fprintf(stderr, "susetags repo type is not supported\n"); + exit(1); +} + +#endif + + +#ifdef ENABLE_RPMMD + +static const char * +repomd_find(Repo *repo, const char *what) +{ + Pool *pool = repo->pool; + Dataiterator di; + const char *filename; + + filename = 0; + dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING); + dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD); + if (dataiterator_step(&di)) + { + dataiterator_setpos_parent(&di); + filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION); + } + dataiterator_free(&di); + if (filename && strncmp(filename, "repodata/", 9) == 0) + filename += 9; + return filename; +} + +static FILE * +repomd_open(const char *dir, const char *filename, char **tmpp, int missingok) +{ + FILE *fp; + if (!filename) + { + *tmpp = 0; + return 0; + } + *tmpp = solv_dupjoin(dir, "/", filename); + if ((fp = solv_xfopen(*tmpp, "r")) == 0) + { + if (!missingok) + { + perror(*tmpp); + exit(1); + } + *tmpp = solv_free(*tmpp); + return 0; + } + return fp; +} + +static void +repomd_extend(Repo *repo, const char *dir, const char *what, const char *language, int missingok) +{ + const char *filename; + FILE *fp; + char *tmp; + + filename = repomd_find(repo, what); + if (!filename) + return; + fp = repomd_open(dir, filename, &tmp, missingok); + if (fp) + { + if (repo_add_rpmmd(repo, fp, language, REPO_EXTEND_SOLVABLES)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool)); + exit(1); + } + fclose(fp); + } + solv_free(tmp); +} + +static void +repomd_extend_languages(Repo *repo, const char *dir, int missingok) +{ + char **susedatas = 0; + int nsusedatas = 0, i; + Dataiterator di; + dataiterator_init(&di, repo->pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, "susedata.", SEARCH_STRINGSTART); + dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD); + while (dataiterator_step(&di)) + { + susedatas = solv_extend(susedatas, nsusedatas, 1, sizeof(char *), 15); + susedatas[nsusedatas++] = solv_strdup(di.kv.str); + } + dataiterator_free(&di); + for (i = 0; i < nsusedatas; i++) + { + repomd_extend(repo, dir, susedatas[i], susedatas[i] + 9, missingok); + susedatas[i] = solv_free(susedatas[i]); + } + solv_free(susedatas); +} + +static void +add_rpmmd_file(Repo *repo, const char *dir, const char *filename, int missingok) +{ + FILE *fp; + char *tmp; + + fp = repomd_open(dir, filename, &tmp, missingok); + if (!fp) + return; + if (repo_add_rpmmd(repo, fp, 0, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool)); + exit(1); + } + fclose(fp); + solv_free(tmp); +} + +int +read_rpmmd_repo(Repo *repo, const char *dir) +{ + Pool *pool = repo->pool; + FILE *fp; + char *tmp = 0; + const char *filename; + + /* add repomd.xml and suseinfo.xml */ + fp = repomd_open(dir, "repomd.xml", &tmp, 0); + if (repo_add_repomdxml(repo, fp, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + filename = repomd_find(repo, "suseinfo"); + if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0) + { + if (repo_add_repomdxml(repo, fp, REPO_REUSE_REPODATA)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } + + /* first all primary packages */ + filename = repomd_find(repo, "primary"); + if (filename) + { + add_rpmmd_file(repo, dir, filename, 0); + repomd_extend(repo, dir, "susedata", 0, 1); + repomd_extend_languages(repo, dir, 1); + if (add_filelist) + repomd_extend(repo, dir, "filelists", 0, 1); + if (add_changelog) + repomd_extend(repo, dir, "other", 0, 1); + } + + /* some legacy stuff */ + filename = repomd_find(repo, "products"); + if (!filename) + filename = repomd_find(repo, "product"); + if (filename) + add_rpmmd_file(repo, dir, filename, 1); + filename = repomd_find(repo, "patterns"); + add_rpmmd_file(repo, dir, filename, 1); + + /* updateinfo */ + filename = repomd_find(repo, "updateinfo"); + if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0) + { + if (repo_add_updateinfoxml(repo, fp, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } + + /* deltainfo */ + filename = repomd_find(repo, "deltainfo"); + if (!filename) + filename = repomd_find(repo, "prestodelta"); + if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0) + { + if (repo_add_deltainfoxml(repo, fp, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } + +#ifdef ENABLE_APPDATA + /* appdata */ + filename = add_appdata ? repomd_find(repo, "appdata") : 0; + if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool)); + exit(1); + } + fclose(fp); + tmp = solv_free(tmp); + } +#endif + + repo_internalize(repo); + return 0; +} + +#else + +int +read_rpmmd_repo(Repo *repo, const char *dir) +{ + fprintf(stderr, "rpmmd repo type is not supported\n"); + exit(1); +} + +#endif + +static void +usage(int status) +{ + fprintf(stderr, "\nUsage:\n" + "repo2solv [-R] [-X] [-A] [-o ] \n" + " Convert a repository in to a solv file\n" + " -h : print help & exit\n" + " -o : write to this file instead of stdout\n" + " -F : add filelist\n" + " -R : also search subdirectories for rpms\n" + " -X : generate pattern/product pseudo packages\n" + " -A : add appdata packages\n" + ); + exit(status); +} + +int +main(int argc, char **argv) +{ + int c, res; + int repotype = 0; + char *outfile = 0; + char *dir; + struct stat stb; + + Pool *pool = pool_create(); + Repo *repo = repo_create(pool, ""); + + while ((c = getopt(argc, argv, "hAXRFCo:")) >= 0) + { + switch(c) + { + case 'h': + usage(0); + break; + case 'X': +#ifdef SUSE + add_auto = 1; +#endif + break; + case 'A': +#ifdef ENABLE_APPDATA + add_appdata = 1; +#endif + break; + case 'R': + repotype = REPO_PLAINDIR; + recursive = 1; + break; + case 'F': + add_filelist = 1; + break; + case 'C': + add_changelog = 1; + break; + case 'o': + outfile = optarg; + break; + default: + usage(1); + break; + } + } + if (optind + 1 != argc) + usage(1); + dir = argv[optind]; + if (stat(dir, &stb)) + { + perror(dir); + exit(1); + } + if (!S_ISDIR(stb.st_mode)) + { + fprintf(stderr, "%s: not a directory\n", dir); + exit(1); + } + dir = solv_strdup(dir); + if (repotype == 0) + repotype = autodetect_repotype(pool, dir); + + switch (repotype) + { + case REPO_RPMMD: + res = read_rpmmd_repo(repo, dir); + break; + case REPO_RPMMD_REPODATA: + dir = solv_dupappend(dir, "/repodata", 0); + res = read_rpmmd_repo(repo, dir); + break; + case REPO_SUSETAGS: + res = read_susetags_repo(repo, dir); + break; + case REPO_PLAINDIR: + res = read_plaindir_repo(repo, dir); + break; + default: + fprintf(stderr, "unknown repotype %d\n", repotype); + exit(1); + } + if (outfile && freopen(outfile, "w", stdout) == 0) + { + perror(outfile); + exit(1); + } +#ifdef SUSE + if (add_auto) + repo_add_autopattern(repo, 0); +#endif + tool_write(repo, stdout); + pool_free(pool); + solv_free(dir); + exit(res); +} diff --git a/libsolv-0.6.15/tools/repomdxml2solv.c b/libsolv-0.7.2/tools/repomdxml2solv.c similarity index 97% rename from libsolv-0.6.15/tools/repomdxml2solv.c rename to libsolv-0.7.2/tools/repomdxml2solv.c index f32c35d..fdf7666 100644 --- a/libsolv-0.6.15/tools/repomdxml2solv.c +++ b/libsolv-0.7.2/tools/repomdxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -117,7 +115,7 @@ main(int argc, char **argv) if (query) doquery(pool, repo, query); else - tool_write(repo, 0, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/rpmdb2solv.c b/libsolv-0.7.2/tools/rpmdb2solv.c similarity index 84% rename from libsolv-0.6.15/tools/rpmdb2solv.c rename to libsolv-0.7.2/tools/rpmdb2solv.c index 3b1d41b..58ef567 100644 --- a/libsolv-0.6.15/tools/rpmdb2solv.c +++ b/libsolv-0.7.2/tools/rpmdb2solv.c @@ -15,8 +15,6 @@ */ #include -#include -#include #include #include #include @@ -45,7 +43,6 @@ usage(int status) fprintf(stderr, "\nUsage:\n" "rpmdb2solv [-n] [-b ] [-p ] [-r ]\n" " -n : No packages, do not read rpmdb, useful to only parse products\n" - " -b : Write .solv to .solv instead of stdout\n" " -p : Scan for .prod files, representing installed products\n" " -r : Prefix rpmdb path and with \n" " -o : Write .solv to file instead of stdout\n" @@ -63,8 +60,8 @@ main(int argc, char **argv) Repodata *data; int c, percent = 0; int nopacks = 0; + int add_changelog = 0; const char *root = 0; - const char *basefile = 0; const char *refname = 0; #ifdef ENABLE_SUSEREPO char *proddir = 0; @@ -84,7 +81,7 @@ main(int argc, char **argv) * parse arguments */ - while ((c = getopt(argc, argv, "APhnkxXb:r:p:o:")) >= 0) + while ((c = getopt(argc, argv, "ACPhnkxXr:p:o:")) >= 0) switch (c) { case 'h': @@ -93,9 +90,6 @@ main(int argc, char **argv) case 'r': root = optarg; break; - case 'b': - basefile = optarg; - break; case 'n': nopacks = 1; break; @@ -128,6 +122,9 @@ main(int argc, char **argv) pubkeys = 1; break; #endif + case 'C': + add_changelog = 1; + break; default: usage(1); } @@ -167,7 +164,12 @@ main(int argc, char **argv) if (!nopacks) { - if (repo_add_rpmdb_reffp(repo, reffp, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | (percent ? RPMDB_REPORT_PROGRESS : 0))) + int flags = REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE; + if (percent) + flags |= RPMDB_REPORT_PROGRESS; + if (add_changelog) + flags |= RPM_ADD_WITH_CHANGELOG; + if (repo_add_rpmdb_reffp(repo, reffp, flags)) { fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool)); exit(1); @@ -207,7 +209,10 @@ main(int argc, char **argv) #ifdef ENABLE_APPDATA if (add_appdata) - repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST); + { + repo_add_appdata_dir(repo, "/usr/share/metainfo", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST); + repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST); + } #endif repodata_internalize(data); @@ -219,7 +224,7 @@ main(int argc, char **argv) repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS); #endif - tool_write(repo, basefile, 0); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.7.2/tools/rpmmd2solv.c b/libsolv-0.7.2/tools/rpmmd2solv.c new file mode 100644 index 0000000..ad75025 --- /dev/null +++ b/libsolv-0.7.2/tools/rpmmd2solv.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_rpmmd.h" +#ifdef SUSE +#include "repo_autopattern.h" +#endif +#include "common_write.h" +#include "solv_xfopen.h" + + +static void +usage(int status) +{ + fprintf(stderr, "\nUsage:\n" + "rpmmd2solv [-h]\n" + " reads 'primary' from a 'rpmmd' repository from and writes a .solv file to \n" + " -h : print help & exit\n" + ); + exit(status); +} + +int +main(int argc, char **argv) +{ + int c; +#ifdef SUSE + int add_auto = 0; +#endif + + Pool *pool = pool_create(); + Repo *repo = repo_create(pool, ""); + + while ((c = getopt (argc, argv, "hX")) >= 0) + { + switch (c) + { + case 'h': + usage(0); + break; + case 'X': +#ifdef SUSE + add_auto = 1; +#endif + break; + default: + usage(1); + break; + } + } + if (repo_add_rpmmd(repo, stdin, 0, 0)) + { + fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool)); + exit(1); + } +#ifdef SUSE + if (add_auto) + repo_add_autopattern(repo, 0); +#endif + tool_write(repo, stdout); + pool_free(pool); + exit(0); +} diff --git a/libsolv-0.6.15/tools/rpms2solv.c b/libsolv-0.7.2/tools/rpms2solv.c similarity index 95% rename from libsolv-0.6.15/tools/rpms2solv.c rename to libsolv-0.7.2/tools/rpms2solv.c index 7852b08..c012b46 100644 --- a/libsolv-0.6.15/tools/rpms2solv.c +++ b/libsolv-0.7.2/tools/rpms2solv.c @@ -64,7 +64,6 @@ main(int argc, char **argv) Repo *repo; FILE *fp; char buf[4096], *p; - const char *basefile = 0; #ifdef ENABLE_PUBKEY int pubkeys = 0; #endif @@ -73,13 +72,10 @@ main(int argc, char **argv) #endif int filtered_filelist = 0; - while ((c = getopt(argc, argv, "0XkKb:m:F")) >= 0) + while ((c = getopt(argc, argv, "0XkKm:F")) >= 0) { switch(c) { - case 'b': - basefile = optarg; - break; case 'm': manifest = optarg; break; @@ -184,7 +180,7 @@ main(int argc, char **argv) if (add_auto) repo_add_autopattern(repo, 0); #endif - tool_write(repo, basefile, 0); + tool_write(repo, stdout); pool_free(pool); for (c = 0; c < nrpms; c++) free((char *)rpms[c]); diff --git a/libsolv-0.6.15/tools/susetags2solv.c b/libsolv-0.7.2/tools/susetags2solv.c similarity index 86% rename from libsolv-0.6.15/tools/susetags2solv.c rename to libsolv-0.7.2/tools/susetags2solv.c index 71c65d8..f7544dc 100644 --- a/libsolv-0.6.15/tools/susetags2solv.c +++ b/libsolv-0.7.2/tools/susetags2solv.c @@ -8,14 +8,11 @@ #define _GNU_SOURCE #include -#include -#include #include #include #include #include -#include -#include +#include #include "pool.h" #include "repo.h" @@ -32,13 +29,11 @@ static void usage(int status) { fprintf(stderr, "\nUsage:\n" - "susetags2solv [-b ][-c ][-d ][-h][-n ]\n" + "susetags2solv [-c ][-d ][-h][-n ]\n" " reads a 'susetags' repository from and writes a .solv file to \n" - " -b : save as multiple files starting with \n" " -c : parse given contentfile (for product information)\n" " -d : do not read from stdin, but use data in descrdir\n" " -h : print help & exit\n" - " -n : save attributes as .attr\n" ); exit(status); } @@ -64,9 +59,7 @@ int main(int argc, char **argv) { const char *contentfile = 0; - const char *attrname = 0; const char *descrdir = 0; - const char *basefile = 0; const char *query = 0; const char *mergefile = 0; Id defvendor = 0; @@ -78,25 +71,19 @@ main(int argc, char **argv) Pool *pool; Repo *repo; - while ((c = getopt(argc, argv, "hn:c:d:b:q:M:X")) >= 0) + while ((c = getopt(argc, argv, "hc:d:q:M:X")) >= 0) { switch (c) { case 'h': usage(0); break; - case 'n': - attrname = optarg; - break; case 'c': contentfile = optarg; break; case 'd': descrdir = optarg; break; - case 'b': - basefile = optarg; - break; case 'q': query = optarg; break; @@ -135,20 +122,6 @@ main(int argc, char **argv) fclose(fp); } - if (attrname) - { - /* ensure '.attr' suffix */ - const char *dot = strrchr(attrname, '.'); - if (!dot || strcmp(dot, ".attr")) - { - int len = strlen (attrname); - char *newname = (char *)malloc(len + 6); /* alloc for +'.attr'+'\0' */ - strcpy (newname, attrname); - strcpy (newname+len, ".attr"); - attrname = newname; - } - } - /* * descrdir path given, open files and read from there */ @@ -200,7 +173,7 @@ main(int argc, char **argv) perror(fn); exit(1); } - if (repo_add_susetags(repo, fp, defvendor, 0, flags | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE)) + if (repo_add_susetags(repo, fp, defvendor, 0, flags | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | SUSETAGS_RECORD_SHARES)) { fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool)); exit(1); @@ -314,7 +287,7 @@ main(int argc, char **argv) if (query) doquery(pool, repo, query); else - tool_write(repo, basefile, attrname); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/libsolv-0.6.15/tools/testsolv.c b/libsolv-0.7.2/tools/testsolv.c similarity index 76% rename from libsolv-0.6.15/tools/testsolv.c rename to libsolv-0.7.2/tools/testsolv.c index d0328ae..3331fae 100644 --- a/libsolv-0.6.15/tools/testsolv.c +++ b/libsolv-0.7.2/tools/testsolv.c @@ -21,6 +21,9 @@ static struct resultflags2str { { TESTCASE_RESULT_ALTERNATIVES, "alternatives" }, { TESTCASE_RESULT_RULES, "rules" }, { TESTCASE_RESULT_GENID, "genid" }, + { TESTCASE_RESULT_REASON, "reason" }, + { TESTCASE_RESULT_CLEANDEPS, "cleandeps" }, + { TESTCASE_RESULT_JOBS, "jobs" }, { 0, 0 } }; @@ -68,7 +71,7 @@ main(int argc, char **argv) Pool *pool; Queue job; Queue solq; - Solver *solv; + Solver *solv, *reusesolv = 0; char *result = 0; int resultflags = 0; int debuglevel = 0; @@ -79,11 +82,12 @@ main(int argc, char **argv) int c; int ex = 0; const char *list = 0; + int list_with_deps = 0; FILE *fp; const char *p; queue_init(&solq); - while ((c = getopt(argc, argv, "vmrhl:s:T:")) >= 0) + while ((c = getopt(argc, argv, "vmrhL:l:s:T:")) >= 0) { switch (c) { @@ -101,6 +105,11 @@ main(int argc, char **argv) break; case 'l': list = optarg; + list_with_deps = 0; + break; + case 'L': + list = optarg; + list_with_deps = 1; break; case 's': if ((p = strchr(optarg, ':'))) @@ -122,6 +131,8 @@ main(int argc, char **argv) { pool = pool_create(); pool_setdebuglevel(pool, debuglevel); + /* report all errors */ + pool_setdebugmask(pool, pool->debugmask | SOLV_ERROR); fp = fopen(argv[optind], "r"); if (!fp) @@ -140,7 +151,12 @@ main(int argc, char **argv) pool_free(pool); exit(resultflags == 77 ? 77 : 1); } - + if (reusesolv) + { + solver_free(solv); + solv = reusesolv; + reusesolv = 0; + } if (!multijob && !feof(fp)) multijob = 1; @@ -148,11 +164,17 @@ main(int argc, char **argv) printf("test %d:\n", multijob++); if (list) { + Id p = 0; int selflags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL|SELECTION_GLOB|SELECTION_FLAT; if (*list == '/') selflags |= SELECTION_FILELIST; queue_empty(&job); - selection_make(pool, &job, list, selflags); + if (list_with_deps) + p = testcase_str2solvid(pool, list); + if (p) + queue_push2(&job, SOLVER_SOLVABLE, p); + else + selection_make(pool, &job, list, selflags); if (!job.elements) printf("No match\n"); else @@ -162,7 +184,34 @@ main(int argc, char **argv) queue_init(&q); selection_solvables(pool, &job, &q); for (i = 0; i < q.count; i++) - printf(" - %s\n", testcase_solvid2str(pool, q.elements[i])); + { + printf(" - %s\n", testcase_solvid2str(pool, q.elements[i])); + if (list_with_deps) + { + int j, k; + const char *vendor; + static Id deps[] = { + SOLVABLE_PROVIDES, SOLVABLE_REQUIRES, SOLVABLE_CONFLICTS, SOLVABLE_OBSOLETES, + SOLVABLE_RECOMMENDS, SOLVABLE_SUGGESTS, SOLVABLE_SUPPLEMENTS, SOLVABLE_ENHANCES, + SOLVABLE_PREREQ_IGNOREINST, + 0 + }; + vendor = pool_lookup_str(pool, q.elements[i], SOLVABLE_VENDOR); + if (vendor) + printf(" %s: %s\n", pool_id2str(pool, SOLVABLE_VENDOR), vendor); + for (j = 0; deps[j]; j++) + { + Queue dq; + queue_init(&dq); + pool_lookup_idarray(pool, q.elements[i], deps[j], &dq); + if (dq.count) + printf(" %s:\n", pool_id2str(pool, deps[j])); + for (k = 0; k < dq.count; k++) + printf(" %s\n", pool_dep2str(pool, dq.elements[k])); + queue_free(&dq); + } + } + } queue_free(&q); } } @@ -179,8 +228,8 @@ main(int argc, char **argv) solver_solve(solv, &job); solv->solution_callback = 0; solv->solution_callback_data = 0; - if (!resultflags) - resultflags = TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS; + if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) == 0) + resultflags |= TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS; myresult = testcase_solverresult(solv, resultflags); if (rescallback && reportsolutiondata.result) { @@ -292,8 +341,13 @@ main(int argc, char **argv) } } queue_free(&job); - solver_free(solv); + if ((resultflags & TESTCASE_RESULT_REUSE_SOLVER) != 0 && !feof(fp)) + reusesolv = solv; + else + solver_free(solv); } + if (reusesolv) + solver_free(reusesolv); pool_free(pool); fclose(fp); } diff --git a/libsolv-0.6.15/tools/updateinfoxml2solv.c b/libsolv-0.7.2/tools/updateinfoxml2solv.c similarity index 76% rename from libsolv-0.6.15/tools/updateinfoxml2solv.c rename to libsolv-0.7.2/tools/updateinfoxml2solv.c index 5432150..9bc038e 100644 --- a/libsolv-0.6.15/tools/updateinfoxml2solv.c +++ b/libsolv-0.7.2/tools/updateinfoxml2solv.c @@ -6,8 +6,6 @@ */ #include -#include -#include #include #include #include @@ -22,10 +20,9 @@ static void usage(int status) { fprintf(stderr, "\nUsage:\n" - "updateinfoxml2solv [-h][-n ]\n" + "updateinfoxml2solv [-h]\n" " reads a 'updateinfo.xml' file from and writes a .solv file to \n" " -h : print help & exit\n" - " -n : save attributes as .attr\n" ); exit(status); } @@ -34,21 +31,17 @@ int main(int argc, char **argv) { int c, flags = 0; - char *attrname = 0; Pool *pool = pool_create(); Repo *repo = repo_create(pool, ""); - while ((c = getopt(argc, argv, "hn:")) >= 0) + while ((c = getopt(argc, argv, "h")) >= 0) { switch(c) { case 'h': usage(0); break; - case 'n': - attrname = optarg; - break; default: usage(1); break; @@ -59,7 +52,7 @@ main(int argc, char **argv) fprintf(stderr, "updateinfoxml2solv: %s\n", pool_errstr(pool)); exit(1); } - tool_write(repo, 0, attrname); + tool_write(repo, stdout); pool_free(pool); exit(0); } diff --git a/packaging/perl-BSSolv.spec b/packaging/perl-BSSolv.spec index 80986a0..25e1cca 100644 --- a/packaging/perl-BSSolv.spec +++ b/packaging/perl-BSSolv.spec @@ -17,39 +17,24 @@ Name: perl-BSSolv -Version: 0.28.0 +Version: 0.37.0 Release: 1.1 Url: https://github.com/openSUSE/perl-BSSolv Source: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?mandriva_version} -# force this version on mandriva -BuildRequires: libneon0.26-devel -%endif %if 0%{?fedora_version} -BuildRequires: db4-devel BuildRequires: perl-devel %endif %if 0%{?suse_version} Requires: perl = %perl_version -%if 0%{?suse_version} < 1030 -BuildRequires: expat -%else -BuildRequires: libexpat-devel -%endif -%else -BuildRequires: expat-devel -%endif -%if 0%{?rhel_version} || 0%{?centos_version} -BuildRequires: db4-devel %endif BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: perl -BuildRequires: rpm-devel BuildRequires: xz-devel BuildRequires: zlib-devel +BuildRequires: libzstd-devel #RHEL6 moved ExtUtils::MakeMaker outside the main perl package BuildRequires: perl(ExtUtils::MakeMaker) # the testsuite uses the check framework @@ -76,10 +61,6 @@ export CFLAGS="$RPM_OPT_FLAGS" export CXXFLAGS="$CFLAGS" CMAKE_FLAGS= -%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version} -CMAKE_FLAGS="-DFEDORA=1" -%endif - %if 0%{?rhel_version} || 0%{?centos_version} CFLAGS="$CFLAGS -DUSE_OWN_QSORT" %endif @@ -89,17 +70,23 @@ cmake $CMAKE_FLAGS \ -DDISABLE_SHARED=1 \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_SKIP_RPATH=1 \ - -DENABLE_RPMDB=1 \ + -DENABLE_RPMPKG=1 \ -DENABLE_DEBIAN=1 \ -DENABLE_ARCHREPO=1 \ -DENABLE_LZMA_COMPRESSION=1 \ + -DENABLE_ZSTD_COMPRESSION=1 \ + -DENABLE_COMPLEX_DEPS=1 \ -DMULTI_SEMANTICS=1 pushd src ; make ; popd pushd ext ; make ; popd popd + perl Makefile.PL --bundled-libsolv make +%check +make test + %install make DESTDIR=$RPM_BUILD_ROOT install_vendor %if 0%{?suse_version} @@ -123,123 +110,4 @@ find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \; %endif %changelog -* Fri Apr 1 2016 mls@suse.de -- update to version 0.28.0 (perl module 0.08 version) - * fix typo, rename obscpiostats to obscpiostorestats -* Fri Apr 1 2016 mls@suse.de -- update to version 0.27.0 (perl module 0.07 version) - * add delta storage support -* Tue Mar 15 2016 mls@suse.de -- update to version 0.26.0 (perl module 0.06 version) - * add preparehashes pool method to speed up the scheduler -* Tue Aug 18 2015 mls@suse.de -- update to version 0.25.0 (perl module 0.05 version) - * make checksums pass our writefilter -* Tue Aug 18 2015 mls@suse.de -- update to version 0.24.0 (perl module 0.04 version) - * allow setting of the dodcookie without a dodurl -* Thu Jul 30 2015 mls@suse.de -- update to version 0.23.0 (perl module 0.03 version) - * implement download on demand data updating -* Thu Jun 11 2015 adrian@suse.de -- update to version 0.22.0 (perl module 0.02 version) - * implement handling of conflicts (aka '!') deps in expander - * treat ARCH_ANY like ARCH_ALL - * improve conflictsinfo handling - * support --ignoreignore-- flag - * improved debug output -* Thu Sep 18 2014 ro@suse.de -- update to BSSolv.xs from GIT -* Fri Oct 18 2013 mls@suse.de -- update to libsolv-0.4.0 to get REL_MULTIARCH support -* Wed Feb 6 2013 mls@suse.de -- update to libsolv-0.2.4 -* Wed Nov 14 2012 mls@suse.de -- update BSSolv.xs to get debugstr support -* Tue Nov 13 2012 mls@suse.de -- support 'ignoreconflicts' expandflag -* Tue Nov 13 2012 mls@suse.de -- use REPO_NO_LOCATION -* Mon Nov 12 2012 mls@suse.de -- update libsolv to current version to fix deb parsing -- bump repocookie -* Mon Oct 15 2012 mls@suse.de -- update libsolv and BSSolv.xs to current version - * export all dependencies - * obey package conflicts when expanding -* Fri Apr 27 2012 mls@suse.de -- update BSSolv.xs so that the worker caches binaries again -* Wed Apr 25 2012 mls@suse.de -- bump version to 0.18.2 -- update to libsolv-0.1.0 to fix opensuse 11.4 builds -* Wed Apr 4 2012 mls@suse.de -- bump version to 0.18.1 -- update to current libsolv -- enable arch linux support -* Wed Nov 30 2011 adrian@suse.de -- bump version to 0.18.0 -- base package on libsolv tar ball -* Wed Nov 30 2011 mls@suse.de -- update BSSolv.xs: - * fix prefer order handling bug - * add repo->tofile_fd -* Wed Nov 16 2011 mls@suse.de -- fix debian control file extraction, thanks djszapi! -* Thu Aug 25 2011 mls@suse.de -- fix debian dependency compare function -* Tue Jun 28 2011 coolo@novell.com -- add requires to correct perl version -* Tue Feb 15 2011 mls@suse.de -- define USE_OWN_QSORT instead of using glib -* Mon Feb 14 2011 adrian@suse.de -- update to 0.16.4 -* Thu Dec 9 2010 adrian@suse.de -- update to 0.16.2 -- fix build for Factory -* Fri Oct 29 2010 adrian@suse.de -- follow the version of satsolver for this package -* Sat Oct 23 2010 mrdocs@opensuse.org -- fix the build with the correct source version -* Tue Oct 19 2010 adrian@suse.de -- adapt spec to version 0.16.0 -* Fri Jul 23 2010 adrian@suse.de -- update BSSolv.xs from current build-service git repo -* Fri May 14 2010 adrian@suse.de -- adapt spec to version 0.15.0 -* Wed Apr 7 2010 mls@suse.de -- adapt spec to version 0.14.17 -* Mon Mar 15 2010 chris@computersalat.de -- fix spec - o new version 0.14.16 (zypp:Head) -* Tue Mar 2 2010 chris@computersalat.de -- hmm, cause of undocumented SOURCE changes - (satsolver-0.14.15 from zypp:Head), - util patch (SLES 10 fix) now obsolete - o hence removed -* Sun Feb 28 2010 adrian@suse.de -- fixed SLES 10 fix -* Tue Feb 23 2010 chris@computersalat.de -- fix spec - o new version 0.14.15 (zypp:Head) -- reworked patch for SLE_10 -* Fri Feb 12 2010 chris@computersalat.de -- spec mods - o added header - o fixed source version -- fix build for SLE_10 - o added satsolver-0.14.14-util.patch -- BuildReq ruby-devel > 1.8.4 - o /usr/bin/ruby: no such file to - load -- vendor-specific (LoadError) -* Mon Dec 21 2009 mls@suse.de -- add dod changes -- fix bug in debian dep parsing -- add support for whatprovides/whatrequires -* Fri Oct 23 2009 mls@suse.de -- strip trailing spaces in dep2id -* Wed Oct 21 2009 mls@suse.de -- add pkg2sizek -* Wed Oct 7 2009 mls@suse.de -- update BSSolv.xs -* Tue Oct 6 2009 mls@suse.de -- initial version + -- 2.7.4