From 54873fab8f0a01720cf081454d224bf22101af2f Mon Sep 17 00:00:00 2001 From: Packit Date: Aug 20 2020 12:58:15 +0000 Subject: libsolv-0.7.11 base --- diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..2b91665 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,34 @@ +build: false + +platform: + - x64 + +image: + - Visual Studio 2017 + +environment: + matrix: + - MINICONDA: C:\libsolv-conda + +init: + - "ECHO %MINICONDA%" + - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" set VCARGUMENT=%PLATFORM% + - if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" set VCVARPATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + - echo "%VCVARPATH% %VCARGUMENT%" + - "%VCVARPATH% %VCARGUMENT%" + - ps: if($env:Platform -eq "x64"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86_64.exe' C:\Miniconda.exe; echo "Done"} + - ps: if($env:Platform -eq "x86"){Start-FileDownload 'http://repo.continuum.io/miniconda/Miniconda3-latest-Windows-x86.exe' C:\Miniconda.exe; echo "Done"} + - cmd: C:\Miniconda.exe /S /D=C:\libsolv-conda + - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH%" + +install: + - conda config --set always_yes yes --set changeps1 no + - conda update -q conda + - conda info -a + - conda install cmake zlib xz -c conda-forge + - cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%MINICONDA%\\LIBRARY -DDISABLE_SHARED=1 -DWITHOUT_COOKIEOPEN=1 -DMULTI_SEMANTICS=1 -DENABLE_COMPLEX_DEPS=1 -DENABLE_EXAMPLES=0 . + - nmake + +build_script: + - ctest diff --git a/.emacs-dirvars b/.emacs-dirvars new file mode 100644 index 0000000..e224534 --- /dev/null +++ b/.emacs-dirvars @@ -0,0 +1,9 @@ +;; -*- emacs-lisp -*- +;; +;; This file is processed by the dirvars emacs package. Each variable +;; setting below is performed when this dirvars file is loaded. +;; +c-file-style: "gnu"; +fill-column: 78 +indent-tabs-mode: nil +tab-width: 8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..08fac49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*~ +build +doc/*.xml +tests/solver/data.libzypp/*/*.result +src/solvversion.h diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a115095 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: C +matrix: + fast_finish: true + include: + - os: linux + addons: + apt: + packages: + - cmake + - os: osx + osx_image: xcode9.4 + compiler: clang + addons: + homebrew: + packages: + - cmake + - zlib +script: +- mkdir build +- cd build +- cmake -DDEBIAN=1 -DMULTI_SEMANTICS=1 .. +- make +- make test diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c1ada00 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,480 @@ +PROJECT (libsolv) + +CMAKE_MINIMUM_REQUIRED (VERSION 2.8.5) + +OPTION (ENABLE_STATIC "Build a static version of the libraries?" OFF) +OPTION (DISABLE_SHARED "Do not build a shared version of the libraries?" OFF) + +OPTION (ENABLE_PERL "Build the perl bindings?" OFF) +OPTION (ENABLE_PYTHON "Build the python bindings?" OFF) +OPTION (ENABLE_RUBY "Build the ruby bindings?" OFF) +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_RPMDB_BDB "Use BerkeleyDB 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) +OPTION (ENABLE_HELIXREPO "Build with helix repository support?" OFF) +OPTION (ENABLE_DEBIAN "Build with debian database/repository support?" OFF) +OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF) +OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF) +OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF) +OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF) +OPTION (ENABLE_CONDA "Build with conda dependency support?" OFF) +OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF) + +OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF) + +OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF) +OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF) +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) +OPTION (WITHOUT_COOKIEOPEN "Disable the use of stdio cookie opens?" OFF) + +include (GNUInstallDirs) +message (STATUS "Libraries will be installed in ${CMAKE_INSTALL_FULL_LIBDIR}") +message (STATUS "Header files will be installed in ${CMAKE_INSTALL_FULL_INCLUDEDIR}") +message (STATUS "Binaries will be installed in ${CMAKE_INSTALL_FULL_BINDIR}") +message (STATUS "Man pages will be installed in ${CMAKE_INSTALL_FULL_MANDIR}") + +IF (NOT PKGCONFIG_INSTALL_DIR) + SET (PKGCONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +ENDIF (NOT PKGCONFIG_INSTALL_DIR) +#################################################################### +# CONFIGURATION # +#################################################################### + +# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked +SET (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) +INSTALL( FILES ${CMAKE_MODULE_PATH}/FindLibSolv.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules ) + +INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake) + +SET (have_system x) + +IF (FEDORA) +MESSAGE(STATUS "Building for Fedora") +ADD_DEFINITIONS (-DFEDORA) +SET (ENABLE_RPMDB ON) +SET (ENABLE_RPMMD ON) +SET (have_system ${have_system}x) +ENDIF (FEDORA) + +IF (DEBIAN) +MESSAGE (STATUS "Building for Debian") +ADD_DEFINITIONS (-DDEBIAN) +SET (ENABLE_DEBIAN ON) +SET (have_system ${have_system}x) +ENDIF (DEBIAN) + +IF (SUSE) +MESSAGE (STATUS "Building for SUSE") +ADD_DEFINITIONS (-DSUSE) +SET (ENABLE_RPMDB ON) +SET (ENABLE_PUBKEY ON) +SET (ENABLE_RPMDB_BYRPMHEADER ON) +SET (ENABLE_RPMMD ON) +SET (ENABLE_SUSEREPO ON) +SET (ENABLE_HELIXREPO ON) +SET (ENABLE_LINKED_PKGS ON) +SET (have_system ${have_system}x) +ENDIF (SUSE) + +IF (ARCHLINUX) +MESSAGE (STATUS "Building for Archlinux") +ADD_DEFINITIONS (-DARCHLINUX) +SET (ENABLE_ARCHREPO ON) +SET (have_system ${have_system}x) +ENDIF (ARCHLINUX) + +IF (MANDRIVA) +MESSAGE (STATUS "Building for Mandriva") +ADD_DEFINITIONS (-DMANDRIVA) +SET (ENABLE_MDKREPO ON) +SET (ENABLE_RPMDB ON) +SET (have_system ${have_system}x) +ENDIF (MANDRIVA) + +IF (MAGEIA) +MESSAGE (STATUS "Building for Mageia") +ADD_DEFINITIONS (-DMAGEIA) +SET (ENABLE_MDKREPO ON) +SET (ENABLE_RPMDB ON) +SET (ENABLE_RPMMD ON) +SET (ENABLE_LZMA_COMPRESSION ON) +SET (have_system ${have_system}x) +ENDIF (MAGEIA) + +IF (HAIKU) +MESSAGE(STATUS "Building for Haiku") +FIND_LIBRARY(HAIKU_BE_LIBRARY NAMES be) +FIND_LIBRARY(HAIKU_NETWORK_LIBRARY NAMES network) +FIND_LIBRARY(HAIKU_PACKAGE_LIBRARY NAMES package) +SET (HAIKU_SYSTEM_LIBRARIES + ${HAIKU_BE_LIBRARY} ${HAIKU_NETWORK_LIBRARY} ${HAIKU_PACKAGE_LIBRARY}) +ADD_DEFINITIONS (-DHAIKU) +SET (ENABLE_HAIKU ON) +SET (have_system ${have_system}x) +ENDIF (HAIKU) + +SET (CMAKE_MACOSX_RPATH ON) + +IF (${have_system} STREQUAL x) + MESSAGE (STATUS "Building for no system") +ENDIF (${have_system} STREQUAL x) +IF (${have_system} STRGREATER xx) + MESSAGE (FATAL_ERROR "Can only compile for one system type.") +ENDIF (${have_system} STRGREATER xx) + +SET (ENABLE_ZLIB_COMPRESSION ON) +IF (ENABLE_ARCHREPO OR ENABLE_DEBIAN) +SET (ENABLE_LZMA_COMPRESSION ON) +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) +INCLUDE_DIRECTORIES (${ZLIB_INCLUDE_DIRS}) +ENDIF (ENABLE_ZLIB_COMPRESSION) + +IF (ENABLE_LZMA_COMPRESSION) +FIND_PACKAGE (LZMA REQUIRED) +INCLUDE_DIRECTORIES (${LZMA_INCLUDE_DIR}) +ENDIF (ENABLE_LZMA_COMPRESSION) + +IF (ENABLE_BZIP2_COMPRESSION) +FIND_PACKAGE (BZip2 REQUIRED) +INCLUDE_DIRECTORIES (${BZIP2_INCLUDE_DIRS}) +ENDIF (ENABLE_BZIP2_COMPRESSION) + +IF (ENABLE_ZSTD_COMPRESSION) +FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd) +FIND_PATH (ZSTD_INCLUDE_DIRS zstd.h) +INCLUDE_DIRECTORIES (${ZSTD_INCLUDE_DIRS}) +ENDIF (ENABLE_ZSTD_COMPRESSION) + +IF (RPM5) +MESSAGE (STATUS "Enabling RPM 5 support") +ADD_DEFINITIONS (-DRPM5) +SET (ENABLE_RPMDB ON) +SET (ENABLE_RPMMD ON) +FIND_PACKAGE (PkgConfig REQUIRED) +PKG_CHECK_MODULES (RPM REQUIRED rpm) +INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS}) +ENDIF (RPM5) + +IF (ENABLE_CONDA) +SET (MULTI_SEMANTICS ON) +ENDIF (ENABLE_CONDA) + +IF (MULTI_SEMANTICS) +MESSAGE (STATUS "Enabling multi dist support") +ENDIF (MULTI_SEMANTICS) + +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) + FIND_LIBRARY (RPMDB_LIBRARY NAMES rpm) + ENDIF (NOT RPMDB_LIBRARY) + + FIND_LIBRARY (RPMIO_LIBRARY NAMES rpmio) + IF (RPMIO_LIBRARY) + SET(RPMDB_LIBRARY ${RPMIO_LIBRARY} ${RPMDB_LIBRARY}) + ENDIF (RPMIO_LIBRARY) + + IF (RPM5) + FIND_LIBRARY (RPMMISC_LIBRARY NAMES rpmmisc) + IF (RPMMISC_LIBRARY) + SET (RPMDB_LIBRARY ${RPMMISC_LIBRARY} ${RPMDB_LIBRARY}) + ENDIF (RPMMISC_LIBRARY) + ENDIF (RPM5) + + IF (ENABLE_RPMDB) + IF (NOT ENABLE_RPMDB_BDB) + SET (ENABLE_RPMDB_LIBRPM ON) + ENDIF (NOT ENABLE_RPMDB_BDB) + + # check if rpm contains a bundled berkeley db + CHECK_INCLUDE_FILE(rpm/db.h 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) + ENDIF (ENABLE_RPMDB) + + INCLUDE (CheckLibraryExists) + CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS) + CHECK_LIBRARY_EXISTS(rpm rpmdbNextIteratorHeaderBlob "" HAVE_RPMDBNEXTITERATORHEADERBLOB) + CHECK_LIBRARY_EXISTS(rpm rpmdbFStat "" HAVE_RPMDBFSTAT) +ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM) + +IF (ENABLE_PUBKEY) + SET (ENABLE_PGPVRFY ON) +ENDIF (ENABLE_PUBKEY) + +INCLUDE (CheckFunctionExists) +INCLUDE (TestBigEndian) + +CHECK_FUNCTION_EXISTS (strchrnul HAVE_STRCHRNUL) +CHECK_FUNCTION_EXISTS (fopencookie HAVE_FOPENCOOKIE) +CHECK_FUNCTION_EXISTS (funopen HAVE_FUNOPEN) +TEST_BIG_ENDIAN (WORDS_BIGENDIAN) + +IF (${CMAKE_MAJOR_VERSION} GREATER 2) +INCLUDE (CMakePushCheckState) +INCLUDE (CheckCCompilerFlag) +MACRO (check_linker_flag FLAG VAR) + CMAKE_PUSH_CHECK_STATE (RESET) + SET (CMAKE_REQUIRED_FLAGS "${FLAG}") + CHECK_C_COMPILER_FLAG ("" "${VAR}") + CMAKE_POP_CHECK_STATE () +ENDMACRO (check_linker_flag) +check_linker_flag("-Wl,--as-needed" HAVE_LINKER_AS_NEEDED) +check_linker_flag("-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver" HAVE_LINKER_VERSION_SCRIPT) +ELSE (${CMAKE_MAJOR_VERSION} GREATER 2) +SET (HAVE_LINKER_AS_NEEDED 1) +SET (HAVE_LINKER_VERSION_SCRIPT 1) +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 HAVE_RPMDBNEXTITERATORHEADERBLOB HAVE_RPMDBFSTAT + WITH_LIBXML2 WITHOUT_COOKIEOPEN) + 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 ENABLE_CONDA) + 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_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) + +SET (PACKAGE "libsolv") +SET (VERSION "${LIBSOLV_MAJOR}.${LIBSOLV_MINOR}.${LIBSOLV_PATCH}") + +ADD_DEFINITIONS (-D_FILE_OFFSET_BITS=64) +CONFIGURE_FILE (src/solvversion.h.in src/solvversion.h) + +SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Package dependency solver library") +SET (CPACK_PACKAGE_VENDOR "SUSE") +SET (CPACK_PACKAGE_VERSION_MAJOR ${LIBSOLV_MAJOR}) +SET (CPACK_PACKAGE_VERSION_MINOR ${LIBSOLV_MINOR}) +SET (CPACK_PACKAGE_VERSION_PATCH ${LIBSOLV_PATCH}) +SET (CPACK_GENERATOR "TBZ2") +SET (CPACK_SOURCE_GENERATOR "TBZ2") +SET (CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE}-${VERSION}") +SET (CPACK_SOURCE_TOPLEVEL_TAG "Linux-Source:") +SET (CPACK_TOPLEVEL_TAG "Linux-Source:") + +# The following components are regex's to match anywhere (unless anchored) +# in absolute path + filename to find files or directories to be excluded +# from source tarball. +SET (CPACK_SOURCE_IGNORE_FILES +# temporary files +"\\\\.swp$" +# backup files +"~$" +# eclipse files +"\\\\.cdtproject$" +"\\\\.cproject$" +"\\\\.project$" +"\\\\.settings/" +# others +"\\\\.#" +"/#" +"/build/" +"/_build/" +"/\\\\.git/" +# used before +"/\\\\.libs/" +"/\\\\.deps/" +"\\\\.o$" +"\\\\.lo$" +"\\\\.la$" +"Makefile$" +"Makefile\\\\.in$" +# cmake cache files +"DartConfiguration.tcl$" +"CMakeCache.txt" +"CMakeFiles" +"cmake_install.cmake$" +"CMakeLists.txt.auto$" +"CTestTestfile.cmake" +"CPackConfig.cmake$" +"CPackSourceConfig.cmake$" +"libsolv.spec$" +) + +INCLUDE(CPack) + +#################################################################### +# INCLUDES # +#################################################################### + +#SET (CMAKE_INCLUDE_DIRECTORIES_BEFORE ON) +INCLUDE_DIRECTORIES (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/ext ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/src SYSTEM ) + +#################################################################### + +MESSAGE (STATUS "Looking for modules in ${CMAKE_MODULE_PATH}") + +IF (MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4244 /wd4267") + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +ELSE () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + 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") +ENDIF () + +# 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) +IF (ENABLE_HAIKU) +SET (SYSTEM_LIBRARIES ${HAIKU_SYSTEM_LIBRARIES} ${SYSTEM_LIBRARIES}) +ENDIF (ENABLE_HAIKU) +IF (HAVE_LINKER_AS_NEEDED) +SET (SYSTEM_LIBRARIES "-Wl,--as-needed" ${SYSTEM_LIBRARIES}) +ENDIF (HAVE_LINKER_AS_NEEDED) + +ADD_SUBDIRECTORY (src) +ADD_SUBDIRECTORY (ext) +ADD_SUBDIRECTORY (tools) +IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL) + ADD_SUBDIRECTORY (bindings) +ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL) +ADD_SUBDIRECTORY (examples) +ADD_SUBDIRECTORY (doc) + +MESSAGE (STATUS "Version: ${VERSION}") + +#################################################################### +# RPM SPEC # +#################################################################### + +MACRO (SPECFILE) + MESSAGE (STATUS "Writing spec file...") + CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/package/libsolv.spec.in ${CMAKE_BINARY_DIR}/package/libsolv.spec @ONLY) +ENDMACRO (SPECFILE) + +MACRO (PCFILE) + 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 ${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 () +PCFILE () + +SET (AUTOBUILD_COMMAND + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/package/*.tar.bz2 + COMMAND mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG} + COMMAND ${CMAKE_MAKE_PROGRAM} package_source + COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 ${CMAKE_BINARY_DIR}/package + COMMAND ${CMAKE_COMMAND} -E remove ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/package/libsolv.changes" "${CMAKE_BINARY_DIR}/package/libsolv.changes" +) + +ADD_CUSTOM_TARGET (srcpackage + ${AUTOBUILD_COMMAND} +) + +ADD_CUSTOM_TARGET (srcpackage_local + ${AUTOBUILD_COMMAND} +) + +ENABLE_TESTING() +ADD_SUBDIRECTORY (test) diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..38f89f9 --- /dev/null +++ b/CREDITS @@ -0,0 +1,28 @@ + +Klaus Kaempf + - old language bindings + +Duncan Mac-Vicar Prett + - cmake support + - old ruby bindings + - many of the xml parsers + +Michael Matz + - repodata storage + - repopage compression + - dataiterator code + +Michael Schroeder + - overall design + - pool & solver implementation + - new language + - debian support + - mandriva/mageia support + - archlinux support + +Ingo Weinhold + - haiku support + +Wolf Vollprecht + - win32 port + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..5b1df67 --- /dev/null +++ b/INSTALL @@ -0,0 +1,18 @@ +Compiling and installing the software + +Requirements: + +- C compiler +- cmake +- make +- expat + +Steps to compile/install: + +1. mkdir build +2. cd build +3. cmake .. +4. make + +5. make install + diff --git a/LICENSE.BSD b/LICENSE.BSD new file mode 100644 index 0000000..79c9f2d --- /dev/null +++ b/LICENSE.BSD @@ -0,0 +1,28 @@ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of Novell nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..9d2d833 --- /dev/null +++ b/NEWS @@ -0,0 +1,261 @@ + +This file contains the major changes between +libsolv versions: + +Version 0.7.11 +- ENABLE_RPMDB_LIBRPM is now the default +- selected bug fixes: + * fixed solv_zchunk decoding error if large chunks are used + * treat retracted pathes as irrelevant + * made add_update_target work with multiversion installs + +Version 0.7.10 +- new features: + * new rpm_stat_database() function + * new rpm_hash_database_state() function + +Version 0.7.9 +- new features: + * support conda constrains dependencies + +Version 0.7.8 +- selected bug fixes: + * support arch<->noarch package changes when creating patch + conflicts from the updateinfo data + * also support other rpm database types +- new features: + * support for SOLVER_BLACKLIST jobs that block the installation + of matched packages unless they are directly selected by an + SOLVER_INSTALL job + * libsolv now also parses the patch status in the updateinfo + parser + * new solvable_matchessolvable() function + +Version 0.7.7 +- selected bug fixes: + * fix updating of too many packages in focusbest mode + * fix handling of disabled installed packages in distupgrade +- new features + * new POOL_FLAG_WHATPROVIDESWITHDISABLED pool flag + +Version 0.7.6 +- selected bug fixes: + * fix repository priority handling for multiversion packages + * better support of inverval deps in pool_match_dep() + * support src rpms that have non-empty provides +- new features + * bindings: add get_disabled_list() and set_disabled_list() + * bindings: add whatcontainsdep() + * bindings: make the selection filters return the self object + +Version 0.7.5 +- selected bug fixes: + * fix favorq leaking between solver runs if the solver is reused + * fix SOLVER_FLAG_FOCUS_BEST updateing packages without reason + * be more correct with multiversion packages that obsolete their + own name + * allow building with swig-4.0.0 + * lock jobs now take precedence over dup and forcebest jobs +- new features + * MSVC compilation support + +Version 0.7.4 +- selected bug fixes: + * repo_add_rpmdb: do not copy bad solvables from the old solv file + * fix cleandeps updates not updating all packages +- new features: + * bindings: support pool.matchsolvable(), pool.whatmatchessolvable() + pool.best_solvables() and selection.matchsolvable() + * experimental DISTTYPE_CONDA and REL_CONDA support + +Version 0.7.3 +- selected bug fixes: + * fixed a couple of null pointer derefs and potential memory + leaks + * made disfavoring recommended packages work if strong recommends + is enabled + * no longer disable infarch rules when they don't conflict with + the job +- new features: + * do favor evaluation before pruning allowing to (dis)favor + specific package 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/README b/README new file mode 100644 index 0000000..41fe168 --- /dev/null +++ b/README @@ -0,0 +1,49 @@ +Libsolv +======= + +This is libsolv, a free package dependency solver using a satisfiability +algorithm. + +The code is based on two major, but independent, blocks: + + 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. + +The sat-solver code has been written to aim for the newest packages, +record the decision tree to provide introspection, and also provides +the user with suggestions on how to deal with unsolvable +problems. It also takes advantage of 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) + - arch linux + - red carpet helix format + - haiku + +Build instructions +================== + +Requires: cmake 2.8.5 or later + + mkdir build + cd build + cmake .. + make + +//// +vim: syntax=asciidoc +//// diff --git a/TODO_1.0 b/TODO_1.0 new file mode 100644 index 0000000..9166930 --- /dev/null +++ b/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) + +- write more manpages + +- forcebest pruning is not optimal: it should keep multiple packages + with the same version instead of reducing to just one package for + each name + +IDEAS: + +drop SEARCH_FILES and add SEARCH_BASENAME instead? diff --git a/VERSION.cmake b/VERSION.cmake new file mode 100644 index 0000000..180eda5 --- /dev/null +++ b/VERSION.cmake @@ -0,0 +1,53 @@ +# ================================================== +# Versioning +# ========== +# +# MAJOR Major number for this branch. +# +# MINOR The most recent interface number this +# library implements. +# +# COMPATMINOR The latest binary compatible minor number +# this library implements. +# +# PATCH The implementation number of the current interface. +# +# +# - The package VERSION will be MAJOR.MINOR.PATCH. +# +# - Libtool's -version-info will be derived from MAJOR, MINOR, PATCH +# and COMPATMINOR (see configure.ac). +# +# - Changing MAJOR always breaks binary compatibility. +# +# - Changing MINOR doesn't break binary compatibility by default. +# Only if COMPATMINOR is changed as well. +# +# +# 1) After branching from TRUNK increment TRUNKs MAJOR and +# start with version `MAJOR.0.0' and also set COMPATMINOR to 0. +# +# 2) Update the version information only immediately before a public release +# of your software. More frequent updates are unnecessary, and only guarantee +# that the current interface number gets larger faster. +# +# 3) If the library source code has changed at all since the last update, +# then increment PATCH. +# +# 4) If any interfaces have been added, removed, or changed since the last +# update, increment MINOR, and set PATCH to 0. +# +# 5) If any interfaces have been added since the last public release, then +# leave COMPATMINOR unchanged. (binary compatible change) +# +# 6) If any interfaces have been removed since the last public release, then +# set COMPATMINOR to MINOR. (binary incompatible change) +# + +SET(LIBSOLV_SOVERSION "1") +SET(LIBSOLVEXT_SOVERSION "1") + +SET(LIBSOLV_MAJOR "0") +SET(LIBSOLV_MINOR "7") +SET(LIBSOLV_PATCH "11") + diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000..737cee4 --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,22 @@ +SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + +FIND_PACKAGE (SWIG) + +MESSAGE (STATUS "Found SWIG version ${SWIG_VERSION}") +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) +IF (ENABLE_RUBY) + ADD_SUBDIRECTORY (ruby) +ENDIF (ENABLE_RUBY) +IF (ENABLE_TCL) + ADD_SUBDIRECTORY (tcl) +ENDIF (ENABLE_TCL) diff --git a/bindings/perl/CMakeLists.txt b/bindings/perl/CMakeLists.txt new file mode 100644 index 0000000..49a3902 --- /dev/null +++ b/bindings/perl/CMakeLists.txt @@ -0,0 +1,37 @@ +FIND_PACKAGE (Perl) + +EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccflags}" OUTPUT_VARIABLE PERL_CCFLAGS) +EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{archlib}.\"/CORE\"" OUTPUT_VARIABLE PERL_CORE_DIR) +EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccldflags}" OUTPUT_VARIABLE PERL_CCLDFLAGS) +EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installsitearch}" OUTPUT_VARIABLE PERL_SITEARCHDIR) +EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installvendorarch}" OUTPUT_VARIABLE PERL_VENDORARCHDIR) + +IF (USE_VENDORDIRS) + SET (PERL_INSTALL_DIR ${PERL_VENDORARCHDIR}) +ELSE (USE_VENDORDIRS) + SET (PERL_INSTALL_DIR ${PERL_SITEARCHDIR}) +ENDIF (USE_VENDORDIRS) + +MESSAGE (STATUS "Perl executable: ${PERL_EXECUTABLE}") +MESSAGE (STATUS "Perl installation dir: ${PERL_INSTALL_DIR}") + +ADD_CUSTOM_COMMAND ( + OUTPUT solv_perl.c + COMMAND ${SWIG_EXECUTABLE} -perl ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_perl.c ${CMAKE_SOURCE_DIR}/bindings/solv.i + COMMAND sed -i -e "s/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/" solv_perl.c + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i + VERBATIM +) + +ADD_DEFINITIONS(${PERL_CCFLAGS} -Wno-unused -Wno-nonnull) +LINK_DIRECTORIES (${PERL_CORE_DIR}) +INCLUDE_DIRECTORIES (${PERL_INCLUDE_PATH} ${PERL_CORE_DIR}) + +ADD_LIBRARY (bindings_perl MODULE solv_perl.c) +SET_TARGET_PROPERTIES (bindings_perl PROPERTIES PREFIX "" OUTPUT_NAME "solv") +SET_TARGET_PROPERTIES (bindings_perl PROPERTIES LINK_FLAGS "${PERL_CCLDFLAGS}") +TARGET_LINK_LIBRARIES (bindings_perl libsolvext libsolv ${SYSTEM_LIBRARIES}) + +INSTALL (TARGETS bindings_perl LIBRARY DESTINATION ${PERL_INSTALL_DIR}) +INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.pm DESTINATION ${PERL_INSTALL_DIR}) diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt new file mode 100644 index 0000000..64ef528 --- /dev/null +++ b/bindings/python/CMakeLists.txt @@ -0,0 +1,46 @@ +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) + +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) + SET (PYTHON_VERSION_MAJOR 2) +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 + COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python ${SWIG_PY_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 (${PYTHON_INCLUDE_PATH}) + +ADD_LIBRARY (bindings_python MODULE solv_python.c) +SET_TARGET_PROPERTIES (bindings_python PROPERTIES PREFIX "" OUTPUT_NAME "_solv") +TARGET_LINK_LIBRARIES (bindings_python libsolvext libsolv ${SYSTEM_LIBRARIES}) + +INSTALL (TARGETS bindings_python LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}) +INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON_INSTALL_DIR}) + diff --git a/bindings/python3/CMakeLists.txt b/bindings/python3/CMakeLists.txt new file mode 100644 index 0000000..28e8e00 --- /dev/null +++ b/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/bindings/ruby/CMakeLists.txt b/bindings/ruby/CMakeLists.txt new file mode 100644 index 0000000..6c3bd50 --- /dev/null +++ b/bindings/ruby/CMakeLists.txt @@ -0,0 +1,26 @@ +FIND_PACKAGE (Ruby) + +IF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR) + SET (RUBY_INSTALL_DIR ${RUBY_VENDORARCH_DIR}) +ELSE (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR) + SET (RUBY_INSTALL_DIR ${RUBY_SITEARCH_DIR}) +ENDIF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR) + +MESSAGE (STATUS "Ruby executable: ${RUBY_EXECUTABLE}") +MESSAGE (STATUS "Ruby installation dir: ${RUBY_INSTALL_DIR}") + +ADD_CUSTOM_COMMAND ( + OUTPUT solv_ruby.c + COMMAND ${SWIG_EXECUTABLE} -ruby ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_ruby.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 (${RUBY_INCLUDE_PATH}) + +ADD_LIBRARY (bindings_ruby MODULE solv_ruby.c) +SET_TARGET_PROPERTIES (bindings_ruby PROPERTIES PREFIX "" OUTPUT_NAME "solv") +TARGET_LINK_LIBRARIES (bindings_ruby libsolvext libsolv ${SYSTEM_LIBRARIES}) + +INSTALL (TARGETS bindings_ruby LIBRARY DESTINATION ${RUBY_INSTALL_DIR}) diff --git a/bindings/solv.i b/bindings/solv.i new file mode 100644 index 0000000..48d3f1f --- /dev/null +++ b/bindings/solv.i @@ -0,0 +1,4208 @@ +/* + * WARNING: for perl iterator/array support you need to run + * sed -i -e 's/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/' + * on the generated c code + */ + +%module solv + +#ifdef SWIGRUBY +%markfunc Pool "mark_Pool"; +#endif + +/** + ** binaryblob handling + **/ + +%{ +typedef struct { + const void *data; + size_t len; +} BinaryBlob; +%} + +%typemap(in,noblock=1,fragment="SWIG_AsCharPtrAndSize") (const unsigned char *str, size_t len) (int res, char *buf = 0, size_t size = 0, int alloc = 0) { +#if defined(SWIGTCL) + { + int bal; + unsigned char *ba; + res = SWIG_TypeError; + ba = Tcl_GetByteArrayFromObj($input, &bal); + if (ba) { + buf = (char *)ba; + size = bal; + res = SWIG_OK; + alloc = SWIG_OLDOBJ; + } + } +#else + res = SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc); + if (buf && size) + size--; +#endif + if (!SWIG_IsOK(res)) { +#if defined(SWIGPYTHON) + const void *pybuf = 0; + Py_ssize_t pysize = 0; + res = PyObject_AsReadBuffer($input, &pybuf, &pysize); + if (res < 0) { + %argument_fail(res, "BinaryBlob", $symname, $argnum); + } else { + buf = (void *)pybuf; + size = pysize; + } +#else + %argument_fail(res, "const char *", $symname, $argnum); +#endif + } + $1 = (unsigned char *)buf; + $2 = size; +} + +%typemap(freearg,noblock=1,match="in") (const unsigned char *str, int len) { + if (alloc$argnum == SWIG_NEWOBJ) %delete_array(buf$argnum); +} + +%typemap(out,noblock=1,fragment="SWIG_FromCharPtrAndSize") BinaryBlob { +#if defined(SWIGPYTHON) && defined(PYTHON3) + $result = $1.data ? Py_BuildValue("y#", $1.data, $1.len) : SWIG_Py_Void(); +#elif defined(SWIGTCL) + Tcl_SetObjResult(interp, $1.data ? Tcl_NewByteArrayObj($1.data, $1.len) : NULL); +#else + $result = SWIG_FromCharPtrAndSize($1.data, $1.len); +#if defined(SWIGPERL) + argvi++; +#endif +#endif +} + +/** + ** Queue handling + **/ + +%typemap(arginit) Queue { + queue_init(&$1); +} +%typemap(freearg) Queue { + queue_free(&$1); +} + +#if defined(SWIGPYTHON) + +%typemap(out) Queue { + int i; + PyObject *o = PyList_New($1.count); + for (i = 0; i < $1.count; i++) + PyList_SetItem(o, i, SWIG_From_int($1.elements[i])); + queue_free(&$1); + $result = o; +} + +%define Queue2Array(type, step, con) %{ { + int i; + int cnt = $1.count / step; + Id *idp = $1.elements; + PyObject *o = PyList_New(cnt); + for (i = 0; i < cnt; i++, idp += step) + { + Id id = *idp; +#define result resultx + type result = con; + $typemap(out, type) + PyList_SetItem(o, i, $result); +#undef result + } + queue_free(&$1); + $result = o; +} +%} +%enddef + +%define Array2Queue(asval_meth,typestr) %{ { + 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); + int v; + 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++; + */ +%typemap(out) Queue { + int i; + if (argvi + $1.count + 1 >= items) { + EXTEND(sp, (argvi + $1.count + 1) - items + 1); + } + for (i = 0; i < $1.count; i++) + ST(argvi++) = SvREFCNT_inc(SWIG_From_int($1.elements[i])); + queue_free(&$1); + $result = 0; +} + +%define Queue2Array(type, step, con) %{ { + int i; + int cnt = $1.count / step; + Id *idp = $1.elements; + if (argvi + cnt + 1 >= items) { + EXTEND(sp, (argvi + cnt + 1) - items + 1); + } + for (i = 0; i < cnt; i++, idp += step) + { + Id id = *idp; +#define result resultx + type result = con; + $typemap(out, type) + SvREFCNT_inc(ST(argvi - 1)); +#undef result + } + queue_free(&$1); + $result = 0; +} +%} +%enddef + +%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 = asval_meth(*sv, &v); + if (!SWIG_IsOK(e)) + 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); + for (i = 0; i < $1.count; i++) + rb_ary_store(o, i, SWIG_From_int($1.elements[i])); + queue_free(&$1); + $result = o; +} + +%define Queue2Array(type, step, con) %{ { + int i; + int cnt = $1.count / step; + Id *idp = $1.elements; + VALUE o = rb_ary_new2(cnt); + for (i = 0; i < cnt; i++, idp += step) + { + Id id = *idp; +#define result resultx + type result = con; + $typemap(out, type) + rb_ary_store(o, i, $result); +#undef result + } + queue_free(&$1); + $result = o; +} +%} +%enddef + +%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_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; + + for (i = 0; i < $1.count; i++) { + objvx[i] = SWIG_From_int($1.elements[i]); + } + Tcl_SetObjResult(interp, Tcl_NewListObj($1.count, objvx)); + queue_free(&$1); +} + +%define Queue2Array(type, step, con) %{ + { /* scope is needed to make the goto of SWIG_exception_fail work */ + int i; + int cnt = $1.count / step; + Id *idp = $1.elements; + Tcl_Obj *objvx[cnt]; + + for (i = 0; i < cnt; i++, idp += step) { + Id id = *idp; +#define result resultx +#define Tcl_SetObjResult(i, x) resultobj = x + type result = con; + Tcl_Obj *resultobj; + $typemap(out, type) + objvx[i] = resultobj; +#undef Tcl_SetObjResult +#undef result + } + queue_free(&$1); + Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx)); + } +%} +%enddef + +%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 $argnum is not a list"); + for (i = 0; i < size; i++) { + Tcl_Obj *o = NULL; + 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, (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 /* SWIGTCL */ + +%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers") +%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what)) +%typemap(in) Queue solvables ObjArray2Queue(XSolvable *, queue_push(&$1, obj->id)) + + + +#if defined(SWIGPERL) + +/* work around a swig bug for swig versions < 2.0.5 */ +#if SWIG_VERSION < 0x020005 +%{ +#undef SWIG_CALLXS +#ifdef PERL_OBJECT +# define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv,pPerl) +#else +# ifndef MULTIPLICITY +# define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv) +# else +# define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(PERL_GET_THX, cv) +# endif +#endif +%} +#endif + + +%define perliter(class) + %perlcode { + sub class##::FETCH { + my $i = ${##class##::ITERATORS}{$_[0]}; + if ($i) { + $_[1] == $i->[0] - 1 ? $i->[1] : undef; + } else { + $_[0]->__getitem__($_[1]); + } + } + sub class##::FETCHSIZE { + my $i = ${##class##::ITERATORS}{$_[0]}; + if ($i) { + ($i->[1] = $_[0]->__next__()) ? ++$i->[0] : 0; + } else { + $_[0]->__len__(); + } + } + } +%enddef + +%{ + +#define SWIG_PERL_ITERATOR 0x80 + +SWIGRUNTIMEINLINE SV * +SWIG_Perl_NewArrayObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) { + SV *result = sv_newmortal(); + if (ptr && (flags & (SWIG_SHADOW | SWIG_POINTER_OWN))) { + SV *self; + SV *obj=newSV(0); + AV *array=newAV(); + HV *stash; + sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr); + stash=SvSTASH(SvRV(obj)); + if (flags & SWIG_POINTER_OWN) { + HV *hv; + GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE); + if (!isGV(gv)) + gv_init(gv, stash, "OWNER", 5, FALSE); + hv=GvHVn(gv); + hv_store_ent(hv, obj, newSViv(1), 0); + } + if (flags & SWIG_PERL_ITERATOR) { + HV *hv; + GV *gv=*(GV**)hv_fetch(stash, "ITERATORS", 9, TRUE); + AV *av=newAV(); + if (!isGV(gv)) + gv_init(gv, stash, "ITERATORS", 9, FALSE); + hv=GvHVn(gv); + hv_store_ent(hv, obj, newRV_inc((SV *)av), 0); + } + sv_magic((SV *)array, (SV *)obj, 'P', Nullch, 0); + SvREFCNT_dec(obj); + self=newRV_noinc((SV *)array); + sv_setsv(result, self); + SvREFCNT_dec((SV *)self); + sv_bless(result, stash); + } else { + sv_setref_pv(result, (char *) SWIG_Perl_TypeProxyName(t), ptr); + } + return result; +} + +%} + +%typemap(out) Perlarray { + ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow); argvi++; +} +%typemap(out) Perliterator { + ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow | SWIG_PERL_ITERATOR); argvi++; +} + +%typemap(out) Pool_solvable_iterator * = Perlarray; +%typemap(out) Pool_solvable_iterator * solvables_iter = Perliterator; +%typemap(out) Pool_repo_iterator * = Perlarray; +%typemap(out) Pool_repo_iterator * repos_iter = Perliterator; +%typemap(out) Repo_solvable_iterator * = Perlarray; +%typemap(out) Repo_solvable_iterator * solvables_iter = Perliterator; +%typemap(out) Dataiterator * = Perliterator; + +#endif /* SWIGPERL */ + + +/** + ** appdata handling + **/ + +#if defined(SWIGPYTHON) +typedef PyObject *AppObjectPtr; +%typemap(in) AppObjectPtr { + if ($input) + Py_INCREF($input); + $1 = $input; +} +%typemap(out) AppObjectPtr { + $result = $1 ? $1 : Py_None; + Py_INCREF($result); +} +#elif defined(SWIGPERL) +typedef SV *AppObjectPtr; +%typemap(in) AppObjectPtr { + if ($input) { + $1 = newSV(0); + sv_setsv((SV *)$1, $input); + } else + $1 = (void *)0; +} +%typemap(out) AppObjectPtr { + $result = sv_2mortal($1 ? SvREFCNT_inc($1) : newSV(0)); + argvi++; +} +#elif defined(SWIGRUBY) +typedef VALUE AppObjectPtr; +%typemap(in) AppObjectPtr { + $1 = (void *)$input; +} +%typemap(out) AppObjectPtr { + $result = (VALUE)$1; +} +#elif defined(SWIGTCL) +typedef Tcl_Obj *AppObjectPtr; +%typemap(in) AppObjectPtr { + if ($input) + Tcl_IncrRefCount($input); + $1 = (void *)$input; +} +%typemap(out) AppObjectPtr { + Tcl_SetObjResult(interp, $1 ? $1 : Tcl_NewObj()); +} +#else +#warning AppObjectPtr not defined for this language! +#endif + +/** + ** FILE handling + **/ + +#ifdef SWIGPYTHON +%include "file.i" +#else +%fragment("SWIG_AsValFilePtr","header") {} +#endif + + +%fragment("SWIG_AsValSolvFpPtr","header", fragment="SWIG_AsValFilePtr") { + +SWIGINTERN int +#ifdef SWIGRUBY +SWIG_AsValSolvFpPtr(VALUE obj, FILE **val) { +#elif defined(SWIGTCL) +SWIG_AsValSolvFpPtr SWIG_TCL_DECL_ARGS_2(void *obj, FILE **val) { +#else +SWIG_AsValSolvFpPtr(void *obj, FILE **val) { +#endif + static swig_type_info* desc = 0; + void *vptr = 0; + int ecode; + + if (!desc) desc = SWIG_TypeQuery("SolvFp *"); + if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) { + if (val) + *val = vptr ? ((SolvFp *)vptr)->fp : 0; + return SWIG_OK; + } +#ifdef SWIGPYTHON + ecode = SWIG_AsValFilePtr(obj, val); + if (ecode == SWIG_OK) + return ecode; +#endif + return SWIG_TypeError; +} + +#if defined(SWIGTCL) +#define SWIG_AsValSolvFpPtr(x, y) SWIG_AsValSolvFpPtr SWIG_TCL_CALL_ARGS_2(x, y) +#endif + +} + + +/** + ** DepId handling + **/ + +%fragment("SWIG_AsValDepId","header") { + +SWIGINTERN int +#ifdef SWIGRUBY +SWIG_AsValDepId(VALUE obj, int *val) { +#elif defined(SWIGTCL) +SWIG_AsValDepId SWIG_TCL_DECL_ARGS_2(void *obj, int *val) { +#else +SWIG_AsValDepId(void *obj, int *val) { +#endif + static swig_type_info* desc = 0; + void *vptr = 0; + int ecode; + if (!desc) desc = SWIG_TypeQuery("Dep *"); +#ifdef SWIGTCL + ecode = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(obj, val); +#else + ecode = SWIG_AsVal_int(obj, val); +#endif + if (SWIG_IsOK(ecode)) + return ecode; + if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) { + if (val) + *val = vptr ? ((Dep *)vptr)->id : 0; + return SWIG_OK; + } + return SWIG_TypeError; +} + +#ifdef SWIGTCL +#define SWIG_AsValDepId(x, y) SWIG_AsValDepId SWIG_TCL_CALL_ARGS_2(x, y) +#endif +} + +/** + ** Pool disown helper + **/ + +%typemap(out) disown_helper { +#if defined(SWIGRUBY) + SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0 ); +#elif defined(SWIGPYTHON) + SWIG_ConvertPtr($self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0 ); +#elif defined(SWIGPERL) + SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0 ); +#elif defined(SWIGTCL) + SWIG_ConvertPtr(objv[1], &argp1, SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0); +#else +#warning disown_helper not implemented for this language, this is likely going to leak memory +#endif + +#ifdef SWIGTCL + Tcl_SetObjResult(interp, SWIG_From_int((int)(0))); +#else + $result = SWIG_From_int((int)(0)); +#endif +} + + +/** + ** return $self + **/ + +%define returnself(func) +#if defined(SWIGPYTHON) +%typemap(out) void func { + $result = $self; + Py_INCREF($result); +} +#elif defined(SWIGPERL) +%typemap(out) void func { + $result = sv_2mortal(SvREFCNT_inc(ST(0)));argvi++; +} +#elif defined(SWIGRUBY) +%typemap(ret) void func { + return self; +} +#elif defined(SWIGTCL) +%typemap(out) void func { + Tcl_IncrRefCount(objv[1]); + Tcl_SetObjResult(interp, objv[1]); +} +#endif +%enddef + + +/** + ** misc stuff + **/ + +%include "typemaps.i" + +%typemap(in,numinputs=0,noblock=1) XRule **OUTPUT ($*1_ltype temp) { + $1 = &temp; +} +%typemap(argout,noblock=1) XRule **OUTPUT { + %append_output(SWIG_NewPointerObj((void*)(*$1), SWIGTYPE_p_XRule, SWIG_POINTER_OWN | %newpointer_flags)); +} + +%typemaps_asval(%checkcode(POINTER), SWIG_AsValSolvFpPtr, "SWIG_AsValSolvFpPtr", FILE*); +%typemaps_asval(%checkcode(INT32), SWIG_AsValDepId, "SWIG_AsValDepId", DepId); + + +/** + ** the C declarations + **/ + +%{ +#include +#include +#include +#include +#include +#include +#include + +/* argh, swig undefs bool for perl */ +#ifndef bool +typedef int bool; +#endif + +#include "pool.h" +#include "poolarch.h" +#include "evr.h" +#include "solver.h" +#include "policy.h" +#include "solverdebug.h" +#include "repo_solv.h" +#include "chksum.h" +#include "selection.h" + +#include "repo_write.h" +#if defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG) +#include "repo_rpmdb.h" +#endif +#ifdef ENABLE_PUBKEY +#include "repo_pubkey.h" +#endif +#ifdef ENABLE_DEBIAN +#include "repo_deb.h" +#endif +#ifdef ENABLE_RPMMD +#include "repo_rpmmd.h" +#include "repo_updateinfoxml.h" +#include "repo_deltainfoxml.h" +#include "repo_repomdxml.h" +#endif +#ifdef ENABLE_SUSEREPO +#include "repo_products.h" +#include "repo_susetags.h" +#include "repo_content.h" +#endif +#ifdef ENABLE_MDKREPO +#include "repo_mdk.h" +#endif +#ifdef ENABLE_ARCHREPO +#include "repo_arch.h" +#endif +#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" + +/* for old ruby versions */ +#ifndef RARRAY_PTR +#define RARRAY_PTR(ary) (RARRAY(ary)->ptr) +#endif +#ifndef RARRAY_LEN +#define RARRAY_LEN(ary) (RARRAY(ary)->len) +#endif + +#define SOLVER_SOLUTION_ERASE -100 +#define SOLVER_SOLUTION_REPLACE -101 +#define SOLVER_SOLUTION_REPLACE_DOWNGRADE -102 +#define SOLVER_SOLUTION_REPLACE_ARCHCHANGE -103 +#define SOLVER_SOLUTION_REPLACE_VENDORCHANGE -104 +#define SOLVER_SOLUTION_REPLACE_NAMECHANGE -105 + +typedef void *AppObjectPtr; +typedef Id DepId; + +typedef struct { + Pool *pool; + Id id; +} Dep; + +typedef struct { + Pool *pool; + Id id; +} XSolvable; + +typedef struct { + Solver *solv; + Id id; +} XRule; + +typedef struct { + Repo *repo; + Id id; +} XRepodata; + +typedef struct { + Pool *pool; + Id id; +} Pool_solvable_iterator; + +typedef struct { + Pool *pool; + Id id; +} Pool_repo_iterator; + +typedef struct { + Repo *repo; + Id id; +} Repo_solvable_iterator; + +typedef struct { + Pool *pool; + int how; + Id what; +} Job; + +typedef struct { + Solver *solv; + Id id; +} Problem; + +typedef struct { + Solver *solv; + Id problemid; + Id id; +} Solution; + +typedef struct { + Solver *solv; + Id problemid; + Id solutionid; + Id id; + + Id type; + Id p; + Id rp; +} Solutionelement; + +typedef struct { + Solver *solv; + Id rid; + Id type; + Id source; + Id target; + Id dep_id; +} Ruleinfo; + +typedef struct { + Solver *solv; + Id type; + Id rid; + Id from_id; + Id dep_id; + Id chosen_id; + Queue choices; + int level; +} Alternative; + +typedef struct { + Transaction *transaction; + int mode; + Id type; + int count; + Id fromid; + Id toid; +} TransactionClass; + +typedef struct { + Pool *pool; + Queue q; + int flags; +} Selection; + +typedef struct { + FILE *fp; +} SolvFp; + +typedef Dataiterator Datamatch; + +typedef int disown_helper; + +struct myappdata { + void *appdata; + int disowned; +}; + + +%} + +/** + ** appdata helpers + **/ + +#ifdef SWIGRUBY + +%{ +SWIGINTERN void appdata_disown_helper(void *appdata) { +} +SWIGINTERN void appdata_clr_helper(void **appdatap) { + *appdatap = 0; +} +SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) { + *appdatap = appdata; +} +SWIGINTERN void *appdata_get_helper(void *appdata) { + return appdata; +} +%} + +#elif defined(SWIGTCL) + +%{ +SWIGINTERN void appdata_disown_helper(void *appdata) { +} +SWIGINTERN void appdata_clr_helper(void **appdatap) { + if (*appdatap) + Tcl_DecrRefCount((Tcl_Obj *)(*appdatap)); + *appdatap = 0; +} +SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) { + appdata_clr_helper(appdatap); + *appdatap = appdata; +} +SWIGINTERN void *appdata_get_helper(void *appdata) { + return appdata; +} +%} + +#elif defined(SWIGPYTHON) + +%{ +SWIGINTERN void appdata_disown_helper(void *appdata) { + struct myappdata *myappdata = appdata; + if (!myappdata || !myappdata->appdata || myappdata->disowned) + return; + myappdata->disowned = 1; + Py_DECREF((PyObject *)myappdata->appdata); +} +SWIGINTERN void appdata_clr_helper(void **appdatap) { + struct myappdata *myappdata = *(struct myappdata **)appdatap; + if (myappdata && myappdata->appdata && !myappdata->disowned) { + Py_DECREF((PyObject *)myappdata->appdata); + } + *appdatap = solv_free(myappdata); +} +SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) { + appdata_clr_helper(appdatap); + if (appdata) { + struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1); + myappdata->appdata = appdata; + } +} +SWIGINTERN void *appdata_get_helper(void *appdata) { + return appdata ? ((struct myappdata *)appdata)->appdata : 0; +} + +%} + +#elif defined(SWIGPERL) + +%{ +SWIGINTERN void appdata_disown_helper(void *appdata) { + struct myappdata *myappdata = appdata; + SV *rsv; + if (!myappdata || !myappdata->appdata || myappdata->disowned) + return; + rsv = myappdata->appdata; + if (!SvROK(rsv)) + return; + myappdata->appdata = SvRV(rsv); + myappdata->disowned = 1; + SvREFCNT_dec(rsv); +} +SWIGINTERN void appdata_clr_helper(void **appdatap) { + struct myappdata *myappdata = *(struct myappdata **)appdatap; + if (myappdata && myappdata->appdata && !myappdata->disowned) { + SvREFCNT_dec((SV *)myappdata->appdata); + } + *appdatap = solv_free(myappdata); +} +SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) { + appdata_clr_helper(appdatap); + if (appdata) { + struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1); + myappdata->appdata = appdata; + } +} +SWIGINTERN void *appdata_get_helper(void *appdata) { + struct myappdata *myappdata = appdata; + if (!myappdata || !myappdata->appdata) + return 0; + return myappdata->disowned ? newRV_noinc((SV *)myappdata->appdata) : myappdata->appdata; +} + +%} + +#else +#warning appdata helpers not implemented for this language +#endif + + +/** + ** the SWIG declarations defining the API + **/ + +#ifdef SWIGRUBY +%mixin Dataiterator "Enumerable"; +%mixin Pool_solvable_iterator "Enumerable"; +%mixin Pool_repo_iterator "Enumerable"; +%mixin Repo_solvable_iterator "Enumerable"; +#endif + +typedef int Id; + +%include "knownid.h" + +/* from repodata.h */ +%constant Id SOLVID_META; +%constant Id SOLVID_POS; + +%constant int REL_EQ; +%constant int REL_GT; +%constant int REL_LT; +%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; +%constant int REL_CONDA; + +typedef struct { + Pool* const pool; + int const flags; +} Selection; + +typedef struct { + Pool* const pool; + Id const id; +} Dep; + +/* put before pool/repo so we can access the constructor */ +%nodefaultdtor Dataiterator; +typedef struct {} Dataiterator; + +typedef struct { + Pool* const pool; + Id const id; +} XSolvable; + +typedef struct { + Solver* const solv; + Id const type; + Id const dep_id; +} Ruleinfo; + +typedef struct { + Solver* const solv; + Id const id; +} XRule; + +typedef struct { + Repo* const repo; + Id const id; +} XRepodata; + +typedef struct {} Pool_solvable_iterator; +typedef struct {} Pool_repo_iterator; +typedef struct {} Repo_solvable_iterator; + +%nodefaultctor Datamatch; +%nodefaultdtor Datamatch; +typedef struct { + Pool * const pool; + Repo * const repo; + Id const solvid; +} Datamatch; + +%nodefaultctor Datapos; +typedef struct { + Repo * const repo; +} Datapos; + +typedef struct { + Pool * const pool; + int how; + Id what; +} Job; + +%nodefaultctor Pool; +%nodefaultdtor Pool; +typedef struct { +} Pool; + +%nodefaultctor Repo; +%nodefaultdtor Repo; +typedef struct { + Pool * const pool; + const char * const name; + int priority; + int subpriority; + int const nsolvables; +} Repo; + +%nodefaultctor Solver; +%nodefaultdtor Solver; +typedef struct { + Pool * const pool; +} Solver; + +typedef struct { +} Chksum; + +#ifdef ENABLE_PUBKEY +typedef struct { + Id const htype; + unsigned int const created; + unsigned int const expires; + const char * const keyid; +} Solvsig; +#endif + +%rename(xfopen) solvfp_xfopen; +%rename(xfopen_fd) solvfp_xfopen_fd; + +%nodefaultctor SolvFp; +typedef struct { +} SolvFp; + +%newobject solvfp_xfopen; +%newobject solvfp_xfopen_fd; + +SolvFp *solvfp_xfopen(const char *fn, const char *mode = 0); +SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode = 0); + +%{ + SWIGINTERN SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode) { + SolvFp *sfp; + FILE *fp; + fd = dup(fd); + if (fd == -1) + return 0; + solv_setcloexec(fd, 1); + fp = solv_xfopen_fd(fn, fd, mode); + if (!fp) { + close(fd); + return 0; + } + sfp = solv_calloc(1, sizeof(SolvFp)); + sfp->fp = fp; + return sfp; + } + SWIGINTERN SolvFp *solvfp_xfopen(const char *fn, const char *mode) { + SolvFp *sfp; + FILE *fp; + fp = solv_xfopen(fn, mode); + if (!fp) + return 0; + if (fileno(fp) != -1) + solv_setcloexec(fileno(fp), 1); + sfp = solv_calloc(1, sizeof(SolvFp)); + sfp->fp = fp; + return sfp; + } +%} + +typedef struct { + Solver * const solv; + Id const id; +} Problem; + +typedef struct { + Solver * const solv; + Id const problemid; + Id const id; +} Solution; + +typedef struct { + Solver *const solv; + Id const problemid; + Id const solutionid; + Id const id; + Id const type; +} Solutionelement; + +%nodefaultctor Alternative; +typedef struct { + Solver *const solv; + Id const type; + Id const rid; + Id const from_id; + Id const dep_id; + Id const chosen_id; + int level; +} Alternative; + +%nodefaultctor Transaction; +%nodefaultdtor Transaction; +typedef struct { + Pool * const pool; +} Transaction; + +typedef struct { + Transaction * const transaction; + Id const type; + Id const fromid; + Id const toid; + int const count; +} TransactionClass; + +%extend SolvFp { + ~SolvFp() { + if ($self->fp) + fclose($self->fp); + free($self); + } + int fileno() { + return $self->fp ? fileno($self->fp) : -1; + } + int dup() { + return $self->fp ? dup(fileno($self->fp)) : -1; + } + bool write(const unsigned char *str, size_t len) { + return fwrite(str, len, 1, $self->fp) == 1; + } + bool flush() { + if (!$self->fp) + return 1; + return fflush($self->fp) == 0; + } + bool close() { + bool ret; + if (!$self->fp) + return 1; + ret = fclose($self->fp) == 0; + $self->fp = 0; + return ret; + } + void cloexec(bool state) { + if (!$self->fp || fileno($self->fp) == -1) + return; + solv_setcloexec(fileno($self->fp), state); + } +} + +%extend Job { + static const Id SOLVER_SOLVABLE = SOLVER_SOLVABLE; + static const Id SOLVER_SOLVABLE_NAME = SOLVER_SOLVABLE_NAME; + static const Id SOLVER_SOLVABLE_PROVIDES = SOLVER_SOLVABLE_PROVIDES; + static const Id SOLVER_SOLVABLE_ONE_OF = SOLVER_SOLVABLE_ONE_OF; + static const Id SOLVER_SOLVABLE_REPO = SOLVER_SOLVABLE_REPO; + static const Id SOLVER_SOLVABLE_ALL = SOLVER_SOLVABLE_ALL; + static const Id SOLVER_SELECTMASK = SOLVER_SELECTMASK; + static const Id SOLVER_NOOP = SOLVER_NOOP; + static const Id SOLVER_INSTALL = SOLVER_INSTALL; + static const Id SOLVER_ERASE = SOLVER_ERASE; + static const Id SOLVER_UPDATE = SOLVER_UPDATE; + static const Id SOLVER_WEAKENDEPS = SOLVER_WEAKENDEPS; + static const Id SOLVER_MULTIVERSION = SOLVER_MULTIVERSION; + static const Id SOLVER_LOCK = SOLVER_LOCK; + static const Id SOLVER_DISTUPGRADE = SOLVER_DISTUPGRADE; + static const Id SOLVER_VERIFY = SOLVER_VERIFY; + 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; + static const Id SOLVER_CLEANDEPS = SOLVER_CLEANDEPS; + static const Id SOLVER_FORCEBEST = SOLVER_FORCEBEST; + static const Id SOLVER_TARGETED = SOLVER_TARGETED; + static const Id SOLVER_NOTBYUSER = SOLVER_NOTBYUSER; + static const Id SOLVER_SETEV = SOLVER_SETEV; + static const Id SOLVER_SETEVR = SOLVER_SETEVR; + static const Id SOLVER_SETARCH = SOLVER_SETARCH; + static const Id SOLVER_SETVENDOR = SOLVER_SETVENDOR; + static const Id SOLVER_SETREPO = SOLVER_SETREPO; + static const Id SOLVER_SETNAME = SOLVER_SETNAME; + static const Id SOLVER_NOAUTOSET = SOLVER_NOAUTOSET; + static const Id SOLVER_SETMASK = SOLVER_SETMASK; + + Job(Pool *pool, int how, Id what) { + Job *job = solv_calloc(1, sizeof(*job)); + job->pool = pool; + job->how = how; + job->what = what; + return job; + } + + %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject solvables; + Queue solvables() { + Queue q; + queue_init(&q); + pool_job2solvables($self->pool, &q, $self->how, $self->what); + return q; + } +#ifdef SWIGRUBY + %rename("isemptyupdate?") isemptyupdate; +#endif + bool isemptyupdate() { + return pool_isemptyupdatejob($self->pool, $self->how, $self->what); + } + +#if defined(SWIGTCL) + %rename("==") __eq__; +#endif + bool __eq__(Job *j) { + return $self->pool == j->pool && $self->how == j->how && $self->what == j->what; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + bool __ne__(Job *j) { + return !Job___eq__($self, j); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("str") __str__; +#endif + const char *__str__() { + return pool_job2str($self->pool, $self->how, $self->what, 0); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + const char *__repr__() { + const char *str = pool_job2str($self->pool, $self->how, $self->what, ~0); + return pool_tmpjoin($self->pool, ""); + } +} + +%extend Selection { + static const Id SELECTION_NAME = SELECTION_NAME; + static const Id SELECTION_PROVIDES = SELECTION_PROVIDES; + static const Id SELECTION_FILELIST = SELECTION_FILELIST; + static const Id SELECTION_CANON = SELECTION_CANON; + static const Id SELECTION_DOTARCH = SELECTION_DOTARCH; + static const Id SELECTION_REL = SELECTION_REL; + static const Id SELECTION_INSTALLED_ONLY = SELECTION_INSTALLED_ONLY; + 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; + s = solv_calloc(1, sizeof(*s)); + s->pool = pool; + return s; + } + + ~Selection() { + queue_free(&$self->q); + solv_free($self); + } +#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; + } +returnself(filter) + void filter(Selection *lsel) { + if ($self->pool != lsel->pool) + queue_empty(&$self->q); + else + selection_filter($self->pool, &$self->q, &lsel->q); + } +returnself(add) + void add(Selection *lsel) { + if ($self->pool == lsel->pool) + { + selection_add($self->pool, &$self->q, &lsel->q); + $self->flags |= lsel->flags; + } + } +returnself(add_raw) + void add_raw(Id how, Id what) { + queue_push2(&$self->q, how, what); + } +returnself(subtract) + void subtract(Selection *lsel) { + if ($self->pool == lsel->pool) + selection_subtract($self->pool, &$self->q, &lsel->q); + } + +returnself(select) + 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); + } +returnself(matchdeps) + 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); + } +returnself(matchdepid) + 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); + } +returnself(matchsolvable) + void matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) { + if ((flags & SELECTION_MODEBITS) == 0) + flags |= SELECTION_FILTER | SELECTION_WITH_ALL; + $self->flags = selection_make_matchsolvable($self->pool, &$self->q, solvable->id, flags, keyname, marker); + } + + %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1])); + %newobject jobs; + Queue jobs(int flags) { + Queue q; + int i; + queue_init_clone(&q, &$self->q); + for (i = 0; i < q.count; i += 2) + q.elements[i] |= flags; + return q; + } + + %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject solvables; + Queue solvables() { + Queue q; + queue_init(&q); + selection_solvables($self->pool, &$self->q, &q); + return q; + } + +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("str") __str__; +#endif + const char *__str__() { + return pool_selection2str($self->pool, &$self->q, 0); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + const char *__repr__() { + const char *str = pool_selection2str($self->pool, &$self->q, ~0); + return pool_tmpjoin($self->pool, ""); + } +} + +%extend Chksum { + Chksum(Id type) { + return solv_chksum_create(type); + } + Chksum(Id type, const char *hex) { + unsigned char buf[64]; + int l = solv_chksum_len(type); + if (!l) + return 0; + if (solv_hex2bin(&hex, buf, sizeof(buf)) != l || hex[0]) + return 0; + return solv_chksum_create_from_bin(type, buf); + } + %newobject from_bin; + static Chksum *from_bin(Id type, const unsigned char *str, size_t len) { + return len == solv_chksum_len(type) ? solv_chksum_create_from_bin(type, str) : 0; + } +#if defined(SWIGPERL) + %perlcode { + undef *solv::Chksum::from_bin; + *solv::Chksum::from_bin = sub { + my $pkg = shift; + my $self = solvc::Chksum_from_bin(@_); + bless $self, $pkg if defined $self; + }; + } +#endif + ~Chksum() { + solv_chksum_free($self, 0); + } + Id const type; + %{ + SWIGINTERN Id Chksum_type_get(Chksum *chk) { + return solv_chksum_get_type(chk); + } + %} + void add(const unsigned char *str, size_t len) { + solv_chksum_add($self, str, (int)len); + } + void add_fp(FILE *fp) { + char buf[4096]; + int l; + while ((l = fread(buf, 1, sizeof(buf), fp)) > 0) + solv_chksum_add($self, buf, l); + rewind(fp); /* convenience */ + } + void add_fd(int fd) { + char buf[4096]; + int l; + while ((l = read(fd, buf, sizeof(buf))) > 0) + solv_chksum_add($self, buf, l); + lseek(fd, 0, 0); /* convenience */ + } + void add_stat(const char *filename) { + struct stat stb; + if (stat(filename, &stb)) + memset(&stb, 0, sizeof(stb)); + solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev)); + solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino)); + solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size)); + solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime)); + } + void add_fstat(int fd) { + struct stat stb; + if (fstat(fd, &stb)) + memset(&stb, 0, sizeof(stb)); + solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev)); + solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino)); + solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size)); + solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime)); + } + BinaryBlob raw() { + BinaryBlob bl; + int l; + const unsigned char *b; + b = solv_chksum_get($self, &l); + bl.data = b; + bl.len = l; + return bl; + } + %newobject hex; + char *hex() { + int l; + const unsigned char *b; + char *ret; + + b = solv_chksum_get($self, &l); + ret = solv_malloc(2 * l + 1); + solv_bin2hex(b, l, ret); + return ret; + } + const char *typestr() { + return solv_chksum_type2str(solv_chksum_get_type($self)); + } + +#if defined(SWIGTCL) + %rename("==") __eq__; +#endif + bool __eq__(Chksum *chk) { + return solv_chksum_cmp($self, chk); + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + bool __ne__(Chksum *chk) { + return !solv_chksum_cmp($self, chk); + } +#if defined(SWIGRUBY) + %rename("to_s") __str__; +#endif +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("str") __str__; +#endif + %newobject __str__; + const char *__str__() { + const char *str; + const char *h = 0; + if (solv_chksum_isfinished($self)) + h = Chksum_hex($self); + str = solv_dupjoin(solv_chksum_type2str(solv_chksum_get_type($self)), ":", h ? h : "unfinished"); + solv_free((void *)h); + return str; + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + %newobject __repr__; + const char *__repr__() { + const char *h = Chksum___str__($self); + const char *str = solv_dupjoin(""); + solv_free((void *)h); + return str; + } +} + +%extend Pool { + static const int POOL_FLAG_PROMOTEEPOCH = POOL_FLAG_PROMOTEEPOCH; + static const int POOL_FLAG_FORBIDSELFCONFLICTS = POOL_FLAG_FORBIDSELFCONFLICTS; + static const int POOL_FLAG_OBSOLETEUSESPROVIDES = POOL_FLAG_OBSOLETEUSESPROVIDES; + static const int POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES = POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES; + static const int POOL_FLAG_OBSOLETEUSESCOLORS = POOL_FLAG_OBSOLETEUSESCOLORS; + static const int POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS = POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS; + 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); + } + int set_flag(int flag, int value) { + return pool_set_flag($self, flag, value); + } + int get_flag(int flag) { + return pool_get_flag($self, flag); + } + void set_rootdir(const char *rootdir) { + pool_set_rootdir($self, rootdir); + } + const char *get_rootdir(int flag) { + return pool_get_rootdir($self); + } +#if defined(SWIGPYTHON) + %{ + SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) { + XRepodata *xd = new_XRepodata(data->repo, data->repodataid); + PyObject *args = Py_BuildValue("(O)", SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0)); + PyObject *result = PyEval_CallObject((PyObject *)d, args); + int ecode = 0; + int vresult = 0; + Py_DECREF(args); + if (!result) + return 0; /* exception */ + ecode = SWIG_AsVal_int(result, &vresult); + Py_DECREF(result); + return SWIG_IsOK(ecode) ? vresult : 0; + } + %} + void clr_loadcallback() { + if ($self->loadcallback == loadcallback) { + PyObject *obj = $self->loadcallbackdata; + Py_DECREF(obj); + pool_setloadcallback($self, 0, 0); + } + } + void set_loadcallback(PyObject *callable) { + Pool_clr_loadcallback($self); + if (callable) { + Py_INCREF(callable); + pool_setloadcallback($self, loadcallback, callable); + } + } +#elif defined(SWIGPERL) +%{ + SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) { + int count; + int ret = 0; + dSP; + XRepodata *xd = new_XRepodata(data->repo, data->repodataid); + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_OWNER | SWIG_SHADOW)); + PUTBACK; + count = perl_call_sv((SV *)d, G_EVAL|G_SCALAR); + SPAGAIN; + if (count) + ret = POPi; + PUTBACK; + FREETMPS; + LEAVE; + return ret; + } +%} + void clr_loadcallback() { + if ($self->loadcallback == loadcallback) { + SvREFCNT_dec($self->loadcallbackdata); + pool_setloadcallback($self, 0, 0); + } + } + void set_loadcallback(SV *callable) { + Pool_clr_loadcallback($self); + if (callable) { + SvREFCNT_inc(callable); + pool_setloadcallback($self, loadcallback, callable); + } + } +#elif defined(SWIGRUBY) +%{ + SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) { + XRepodata *xd = new_XRepodata(data->repo, data->repodataid); + VALUE callable = (VALUE)d; + VALUE rd = SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0); + VALUE res = rb_funcall(callable, rb_intern("call"), 1, rd); + return res == Qtrue; + } + SWIGINTERN void mark_Pool(void *ptr) { + Pool *pool = ptr; + if (pool->loadcallback == loadcallback && pool->loadcallbackdata) { + VALUE callable = (VALUE)pool->loadcallbackdata; + rb_gc_mark(callable); + } + } +%} + void clr_loadcallback() { + pool_setloadcallback($self, 0, 0); + } + %typemap(in, numinputs=0) VALUE callable { + $1 = rb_block_given_p() ? rb_block_proc() : 0; + } + void set_loadcallback(VALUE callable) { + pool_setloadcallback($self, callable ? loadcallback : 0, (void *)callable); + } +#elif defined(SWIGTCL) + %{ + typedef struct { + Tcl_Interp *interp; + Tcl_Obj *obj; + } tcl_callback_t; + SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) { + tcl_callback_t *callback_var = (tcl_callback_t *)d; + Tcl_Interp *interp = callback_var->interp; + XRepodata *xd = new_XRepodata(data->repo, data->repodataid); + int result, ecode = 0, vresult = 0; + Tcl_Obj *objvx[2]; + objvx[0] = callback_var->obj; + objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0); + Tcl_IncrRefCount(objvx[1]); + result = Tcl_EvalObjv(interp, sizeof(objvx)/sizeof(*objvx), objvx, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(objvx[1]); + if (result != TCL_OK) + return 0; /* exception */ + ecode = SWIG_AsVal_int(interp, Tcl_GetObjResult(interp), &vresult); + return SWIG_IsOK(ecode) ? vresult : 0; + } + %} + void clr_loadcallback() { + if ($self->loadcallback == loadcallback) { + tcl_callback_t *callback_var = $self->loadcallbackdata; + Tcl_DecrRefCount(callback_var->obj); + solv_free(callback_var); + pool_setloadcallback($self, 0, 0); + } + } + void set_loadcallback(Tcl_Obj *callable, Tcl_Interp *interp) { + Pool_clr_loadcallback($self); + if (callable) { + tcl_callback_t *callback_var = solv_malloc(sizeof(tcl_callback_t)); + Tcl_IncrRefCount(callable); + callback_var->interp = interp; + callback_var->obj = callable; + pool_setloadcallback($self, loadcallback, callback_var); + } + } +#else +#warning loadcallback not implemented for this language +#endif + + ~Pool() { + Pool *pool = $self; + Id repoid; + Repo *repo; + FOR_REPOS(repoid, repo) + appdata_clr_helper(&repo->appdata); + Pool_clr_loadcallback(pool); + appdata_clr_helper(&pool->appdata); + pool_free(pool); + } + disown_helper free() { + Pool *pool = $self; + Id repoid; + Repo *repo; + FOR_REPOS(repoid, repo) + appdata_clr_helper(&repo->appdata); + Pool_clr_loadcallback(pool); + appdata_clr_helper(&pool->appdata); + pool_free(pool); + return 0; + } + disown_helper disown() { + return 0; + } + AppObjectPtr appdata; + %{ + SWIGINTERN void Pool_appdata_set(Pool *pool, AppObjectPtr appdata) { + appdata_set_helper(&pool->appdata, appdata); + } + SWIGINTERN AppObjectPtr Pool_appdata_get(Pool *pool) { + return appdata_get_helper(pool->appdata); + } + %} + void appdata_disown() { + appdata_disown_helper($self->appdata); + } + + Id str2id(const char *str, bool create=1) { + return pool_str2id($self, str, create); + } + %newobject Dep; + Dep *Dep(const char *str, bool create=1) { + 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); + } + const char *dep2str(Id id) { + return pool_dep2str($self, id); + } + Id rel2id(Id name, Id evr, int flags, bool create=1) { + return pool_rel2id($self, name, evr, flags, create); + } + Id id2langid(Id id, const char *lang, bool create=1) { + return pool_id2langid($self, id, lang, create); + } + void setarch(const char *arch = 0) { + struct utsname un; + if (!arch) { + if (uname(&un)) { + perror("uname"); + return; + } + arch = un.machine; + } + pool_setarch($self, arch); + } + Repo *add_repo(const char *name) { + return repo_create($self, name); + } + const char *lookup_str(Id entry, Id keyname) { + return pool_lookup_str($self, entry, keyname); + } + Id lookup_id(Id entry, Id keyname) { + return pool_lookup_id($self, entry, keyname); + } + unsigned long long lookup_num(Id entry, Id keyname, unsigned long long notfound = 0) { + return pool_lookup_num($self, entry, keyname, notfound); + } + bool lookup_void(Id entry, Id keyname) { + return pool_lookup_void($self, entry, keyname); + } + %newobject lookup_checksum; + Chksum *lookup_checksum(Id entry, Id keyname) { + Id type = 0; + const unsigned char *b = pool_lookup_bin_checksum($self, entry, keyname, &type); + return solv_chksum_create_from_bin(type, b); + } + + %newobject Dataiterator; + Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) { + return new_Dataiterator($self, 0, 0, key, match, flags); + } + %newobject Dataiterator_solvid; + Dataiterator *Dataiterator_solvid(Id p, Id key, const char *match = 0, int flags = 0) { + return new_Dataiterator($self, 0, p, key, match, flags); + } + const char *solvid2str(Id solvid) { + return pool_solvid2str($self, solvid); + } + void addfileprovides() { + pool_addfileprovides($self); + } + Queue addfileprovides_queue() { + Queue r; + queue_init(&r); + pool_addfileprovides_queue($self, &r, 0); + return r; + } + void createwhatprovides() { + pool_createwhatprovides($self); + } + + %newobject id2solvable; + XSolvable *id2solvable(Id id) { + return new_XSolvable($self, id); + } + %newobject solvables; + Pool_solvable_iterator * const solvables; + %{ + SWIGINTERN Pool_solvable_iterator * Pool_solvables_get(Pool *pool) { + return new_Pool_solvable_iterator(pool); + } + %} + %newobject solvables_iter; + Pool_solvable_iterator * solvables_iter() { + return new_Pool_solvable_iterator($self); + } + + Repo *id2repo(Id id) { + if (id < 1 || id >= $self->nrepos) + return 0; + return pool_id2repo($self, id); + } + + %newobject repos; + Pool_repo_iterator * const repos; + %{ + SWIGINTERN Pool_repo_iterator * Pool_repos_get(Pool *pool) { + return new_Pool_repo_iterator(pool); + } + %} + %newobject repos_iter; + Pool_repo_iterator * repos_iter() { + return new_Pool_repo_iterator($self); + } + + Repo *installed; + const char * const errstr; + %{ + SWIGINTERN void Pool_installed_set(Pool *pool, Repo *installed) { + pool_set_installed(pool, installed); + } + SWIGINTERN Repo *Pool_installed_get(Pool *pool) { + return pool->installed; + } + SWIGINTERN const char *Pool_errstr_get(Pool *pool) { + return pool_errstr(pool); + } + %} + + Queue matchprovidingids(const char *match, int flags) { + Pool *pool = $self; + Queue q; + Id id; + queue_init(&q); + if (!flags) { + for (id = 1; id < pool->ss.nstrings; id++) + if (pool->whatprovides[id]) + queue_push(&q, id); + } else { + Datamatcher ma; + if (!datamatcher_init(&ma, match, flags)) { + for (id = 1; id < pool->ss.nstrings; id++) + if (pool->whatprovides[id] && datamatcher_match(&ma, pool_id2str(pool, id))) + queue_push(&q, id); + datamatcher_free(&ma); + } + } + return q; + } + + %newobject Job; + Job *Job(int how, Id what) { + return new_Job($self, how, what); + } + + %typemap(out) Queue whatprovides Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); + %newobject whatprovides; + Queue whatprovides(DepId dep) { + Pool *pool = $self; + Queue q; + Id p, pp; + queue_init(&q); + FOR_PROVIDES(p, pp, dep) + queue_push(&q, p); + return q; + } + %typemap(out) Queue best_solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); + %newobject best_solvables; + Queue best_solvables(Queue solvables, int flags=0) { + Queue q; + queue_init_clone(&q, &solvables); + pool_best_solvables($self, &q, flags); + return q; + } + + Id towhatprovides(Queue q) { + 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 whatcontainsdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); + %newobject whatcontainsdep; + Queue whatcontainsdep(Id keyname, DepId dep, Id marker = -1) { + Queue q; + queue_init(&q); + pool_whatcontainsdep($self, keyname, dep, &q, marker); + return q; + } + + %typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); + %newobject whatmatchesdep; + Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) { + Queue q; + queue_init(&q); + pool_whatmatchesdep($self, keyname, dep, &q, marker); + return q; + } + + %typemap(out) Queue whatmatchessolvable Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id)); + %newobject whatmatchessolvable; + Queue whatmatchessolvable(Id keyname, XSolvable *pool_solvable, Id marker = -1) { + Queue q; + queue_init(&q); + pool_whatmatchessolvable($self, keyname, pool_solvable->id, &q, marker); + return q; + } + +#ifdef SWIGRUBY + %rename("isknownarch?") isknownarch; +#endif + bool isknownarch(DepId id) { + Pool *pool = $self; + if (!id || id == ID_EMPTY) + return 0; + if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) + return 1; + if (pool->id2arch && pool_arch2score(pool, id) == 0) + return 0; + return 1; + } + + %newobject Solver; + Solver *Solver() { + return solver_create($self); + } + + %newobject Selection; + Selection *Selection() { + return new_Selection($self); + } + %newobject Selection_all; + Selection *Selection_all(int setflags=0) { + Selection *sel = new_Selection($self); + queue_push2(&sel->q, SOLVER_SOLVABLE_ALL | setflags, 0); + return sel; + } + %newobject select; + Selection *select(const char *name, int flags) { + Selection *sel = new_Selection($self); + sel->flags = selection_make($self, &sel->q, name, flags); + return sel; + } + + %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; + } + + %newobject matchsolvable; + Selection *matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) { + Selection *sel = new_Selection($self); + sel->flags = selection_make_matchsolvable($self, &sel->q, solvable->id, 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 && (!$self->considered || MAPTST($self->considered, i))) + queue_push(&q, i); + } + return q; + } + + Queue get_disabled_list() { + Queue q; + queue_init(&q); + int i; + for (i = 2; i < $self->nsolvables; i++) { + if ($self->solvables[i].repo && ($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 set_disabled_list(Queue q) { + int i; + Id p; + if (!q.count) { + if ($self->considered) { + map_free($self->considered); + $self->considered = solv_free($self->considered); + } + return; + } + if (!$self->considered) { + $self->considered = solv_calloc(1, sizeof(Map)); + map_init($self->considered, $self->nsolvables); + } + map_setall($self->considered); + for (i = 0; i < q.count; i++) { + p = q.elements[i]; + if (p > 0 && p < $self->nsolvables) + MAPCLR($self->considered, p); + } + } + + void setpooljobs(Queue solvejobs) { + queue_free(&$self->pooljobs); + queue_init_clone(&$self->pooljobs, &solvejobs); + } + %typemap(out) Queue getpooljobs Queue2Array(Job *, 2, new_Job(arg1, id, idp[1])); + %newobject getpooljobs; + Queue getpooljobs() { + Queue q; + queue_init_clone(&q, &$self->pooljobs); + return q; + } + +} + +%extend Repo { + static const int REPO_REUSE_REPODATA = REPO_REUSE_REPODATA; + static const int REPO_NO_INTERNALIZE = REPO_NO_INTERNALIZE; + static const int REPO_LOCALPOOL = REPO_LOCALPOOL; + static const int REPO_USE_LOADING = REPO_USE_LOADING; + static const int REPO_EXTEND_SOLVABLES = REPO_EXTEND_SOLVABLES; + static const int REPO_USE_ROOTDIR = REPO_USE_ROOTDIR; + static const int REPO_NO_LOCATION = REPO_NO_LOCATION; + static const int SOLV_ADD_NO_STUBS = SOLV_ADD_NO_STUBS; /* repo_solv */ +#ifdef ENABLE_SUSEREPO + static const int SUSETAGS_RECORD_SHARES = SUSETAGS_RECORD_SHARES; /* repo_susetags */ +#endif + + void free(bool reuseids = 0) { + appdata_clr_helper(&$self->appdata); + repo_free($self, reuseids); + } + void empty(bool reuseids = 0) { + repo_empty($self, reuseids); + } +#ifdef SWIGRUBY + %rename("isempty?") isempty; +#endif + bool isempty() { + return !$self->nsolvables; + } + + AppObjectPtr appdata; + %{ + SWIGINTERN void Repo_appdata_set(Repo *repo, AppObjectPtr appdata) { + appdata_set_helper(&repo->appdata, appdata); + } + SWIGINTERN AppObjectPtr Repo_appdata_get(Repo *repo) { + return appdata_get_helper(repo->appdata); + } + %} + + bool add_solv(const char *name, int flags = 0) { + FILE *fp = fopen(name, "r"); + int r; + if (!fp) + return 0; + r = repo_add_solv($self, fp, flags); + fclose(fp); + return r == 0; + } + bool add_solv(FILE *fp, int flags = 0) { + return repo_add_solv($self, fp, flags) == 0; + } + + %newobject add_solvable; + XSolvable *add_solvable() { + Id solvid = repo_add_solvable($self); + return new_XSolvable($self->pool, solvid); + } + +#ifdef ENABLE_RPMDB + bool add_rpmdb(int flags = 0) { + return repo_add_rpmdb($self, 0, flags) == 0; + } + 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)); + } +#endif +#ifdef ENABLE_PUBKEY +#ifdef ENABLE_RPMDB + bool add_rpmdb_pubkeys(int flags = 0) { + return repo_add_rpmdb_pubkeys($self, flags) == 0; + } +#endif + %newobject add_pubkey; + XSolvable *add_pubkey(const char *keyfile, int flags = 0) { + return new_XSolvable($self->pool, repo_add_pubkey($self, keyfile, flags)); + } + bool add_keyring(FILE *fp, int flags = 0) { + return repo_add_keyring($self, fp, flags); + } + bool add_keydir(const char *keydir, const char *suffix, int flags = 0) { + return repo_add_keydir($self, keydir, suffix, flags); + } +#endif +#ifdef ENABLE_RPMMD + bool add_rpmmd(FILE *fp, const char *language, int flags = 0) { + return repo_add_rpmmd($self, fp, language, flags) == 0; + } + bool add_repomdxml(FILE *fp, int flags = 0) { + return repo_add_repomdxml($self, fp, flags) == 0; + } + bool add_updateinfoxml(FILE *fp, int flags = 0) { + return repo_add_updateinfoxml($self, fp, flags) == 0; + } + bool add_deltainfoxml(FILE *fp, int flags = 0) { + return repo_add_deltainfoxml($self, fp, flags) == 0; + } +#endif +#ifdef ENABLE_DEBIAN + bool add_debdb(int flags = 0) { + return repo_add_debdb($self, flags) == 0; + } + bool add_debpackages(FILE *fp, int flags = 0) { + return repo_add_debpackages($self, fp, flags) == 0; + } + %newobject add_deb; + XSolvable *add_deb(const char *name, int flags = 0) { + return new_XSolvable($self->pool, repo_add_deb($self, name, flags)); + } +#endif +#ifdef ENABLE_SUSEREPO + bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0) { + return repo_add_susetags($self, fp, defvendor, language, flags) == 0; + } + bool add_content(FILE *fp, int flags = 0) { + return repo_add_content($self, fp, flags) == 0; + } + bool add_products(const char *proddir, int flags = 0) { + return repo_add_products($self, proddir, flags) == 0; + } +#endif +#ifdef ENABLE_MDKREPO + bool add_mdk(FILE *fp, int flags = 0) { + return repo_add_mdk($self, fp, flags) == 0; + } + bool add_mdk_info(FILE *fp, int flags = 0) { + return repo_add_mdk_info($self, fp, flags) == 0; + } +#endif +#ifdef ENABLE_ARCHREPO + bool add_arch_repo(FILE *fp, int flags = 0) { + return repo_add_arch_repo($self, fp, flags) == 0; + } + bool add_arch_local(const char *dir, int flags = 0) { + return repo_add_arch_local($self, dir, flags) == 0; + } + %newobject add_arch_pkg; + XSolvable *add_arch_pkg(const char *name, int flags = 0) { + return new_XSolvable($self->pool, repo_add_arch_pkg($self, name, flags)); + } +#endif +#ifdef SUSE + bool add_autopattern(int flags = 0) { + return repo_add_autopattern($self, flags) == 0; + } +#endif + void internalize() { + repo_internalize($self); + } + bool write(FILE *fp) { + return repo_write($self, fp) == 0; + } + /* HACK, remove if no longer needed! */ + bool write_first_repodata(FILE *fp) { + int oldnrepodata = $self->nrepodata; + int res; + $self->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata; + res = repo_write($self, fp); + $self->nrepodata = oldnrepodata; + return res == 0; + } + + %newobject Dataiterator; + Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) { + return new_Dataiterator($self->pool, $self, 0, key, match, flags); + } + %newobject Dataiterator_meta; + Dataiterator *Dataiterator_meta(Id key, const char *match = 0, int flags = 0) { + return new_Dataiterator($self->pool, $self, SOLVID_META, key, match, flags); + } + + Id const id; + %{ + SWIGINTERN Id Repo_id_get(Repo *repo) { + return repo->repoid; + } + %} + %newobject solvables; + Repo_solvable_iterator * const solvables; + %{ + SWIGINTERN Repo_solvable_iterator * Repo_solvables_get(Repo *repo) { + return new_Repo_solvable_iterator(repo); + } + %} + %newobject meta; + Datapos * const meta; + %{ + SWIGINTERN Datapos * Repo_meta_get(Repo *repo) { + Datapos *pos = solv_calloc(1, sizeof(*pos)); + pos->solvid = SOLVID_META; + pos->repo = repo; + return pos; + } + %} + + %newobject solvables_iter; + Repo_solvable_iterator *solvables_iter() { + return new_Repo_solvable_iterator($self); + } + + %newobject add_repodata; + XRepodata *add_repodata(int flags = 0) { + Repodata *rd = repo_add_repodata($self, flags); + return new_XRepodata($self, rd->repodataid); + } + + void create_stubs() { + Repodata *data; + if (!$self->nrepodata) + return; + data = repo_id2repodata($self, $self->nrepodata - 1); + if (data->state != REPODATA_STUB) + (void)repodata_create_stubs(data); + } +#ifdef SWIGRUBY + %rename("iscontiguous?") iscontiguous; +#endif + bool iscontiguous() { + int i; + for (i = $self->start; i < $self->end; i++) + if ($self->pool->solvables[i].repo != $self) + return 0; + return 1; + } + %newobject first_repodata; + XRepodata *first_repodata() { + Repodata *data; + int i; + if ($self->nrepodata < 2) + return 0; + /* make sure all repodatas but the first are extensions */ + data = repo_id2repodata($self, 1); + if (data->loadcallback) + return 0; + for (i = 2; i < $self->nrepodata; i++) + { + data = repo_id2repodata($self, i); + if (!data->loadcallback) + return 0; /* oops, not an extension */ + } + return new_XRepodata($self, 1); + } + + %newobject Selection; + Selection *Selection(int setflags=0) { + Selection *sel = new_Selection($self->pool); + setflags |= SOLVER_SETREPO; + queue_push2(&sel->q, SOLVER_SOLVABLE_REPO | setflags, $self->repoid); + return sel; + } + +#ifdef ENABLE_PUBKEY + %newobject find_pubkey; + XSolvable *find_pubkey(const char *keyid) { + return new_XSolvable($self->pool, repo_find_pubkey($self, keyid)); + } +#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 + bool __eq__(Repo *repo) { + return $self == repo; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + 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 + %newobject __str__; + const char *__str__() { + char buf[20]; + if ($self->name) + return solv_strdup($self->name); + sprintf(buf, "Repo#%d", $self->repoid); + return solv_strdup(buf); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + %newobject __repr__; + const char *__repr__() { + char buf[20]; + if ($self->name) + { + sprintf(buf, "repoid); + return solv_dupjoin(buf, $self->name, ">"); + } + sprintf(buf, "", $self->repoid); + return solv_strdup(buf); + } +} + +%extend Dataiterator { + static const int SEARCH_STRING = SEARCH_STRING; + static const int SEARCH_STRINGSTART = SEARCH_STRINGSTART; + static const int SEARCH_STRINGEND = SEARCH_STRINGEND; + static const int SEARCH_SUBSTRING = SEARCH_SUBSTRING; + static const int SEARCH_GLOB = SEARCH_GLOB; + static const int SEARCH_REGEX = SEARCH_REGEX; + static const int SEARCH_NOCASE = SEARCH_NOCASE; + static const int SEARCH_FILES = SEARCH_FILES; + static const int SEARCH_COMPLETE_FILELIST = SEARCH_COMPLETE_FILELIST; + static const int SEARCH_CHECKSUMS = SEARCH_CHECKSUMS; + + Dataiterator(Pool *pool, Repo *repo, Id p, Id key, const char *match, int flags) { + Dataiterator *di = solv_calloc(1, sizeof(*di)); + dataiterator_init(di, pool, repo, p, key, match, flags); + return di; + } + ~Dataiterator() { + dataiterator_free($self); + solv_free($self); + } +#if defined(SWIGPYTHON) + %pythoncode { + def __iter__(self): return self + } +#ifndef PYTHON3 + %rename("next") __next__(); +#endif + %exception __next__ { + $action + if (!result) { + PyErr_SetString(PyExc_StopIteration,"no more matches"); + return NULL; + } + } +#endif +#ifdef SWIGPERL + perliter(solv::Dataiterator) +#endif + %newobject __next__; + Datamatch *__next__() { + Dataiterator *ndi; + if (!dataiterator_step($self)) { + return 0; + } + ndi = solv_calloc(1, sizeof(*ndi)); + dataiterator_init_clone(ndi, $self); + dataiterator_strdup(ndi); + return ndi; + } +#ifdef SWIGRUBY + void each() { + Datamatch *d; + while ((d = Dataiterator___next__($self)) != 0) { + rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(d), SWIGTYPE_p_Datamatch, SWIG_POINTER_OWN | 0)); + } + } +#endif + void prepend_keyname(Id key) { + dataiterator_prepend_keyname($self, key); + } + void skip_solvable() { + dataiterator_skip_solvable($self); + } +} + +%extend Datapos { + Id lookup_id(Id keyname) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + Id r; + pool->pos = *$self; + r = pool_lookup_id(pool, SOLVID_POS, keyname); + pool->pos = oldpos; + return r; + } + const char *lookup_str(Id keyname) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + const char *r; + pool->pos = *$self; + r = pool_lookup_str(pool, SOLVID_POS, keyname); + pool->pos = oldpos; + return r; + } + unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + unsigned long long r; + pool->pos = *$self; + r = pool_lookup_num(pool, SOLVID_POS, keyname, notfound); + pool->pos = oldpos; + return r; + } + bool lookup_void(Id keyname) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + int r; + pool->pos = *$self; + r = pool_lookup_void(pool, SOLVID_POS, keyname); + pool->pos = oldpos; + return r; + } + %newobject lookup_checksum; + Chksum *lookup_checksum(Id keyname) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + Id type = 0; + const unsigned char *b; + pool->pos = *$self; + b = pool_lookup_bin_checksum(pool, SOLVID_POS, keyname, &type); + pool->pos = oldpos; + return solv_chksum_create_from_bin(type, b); + } + const char *lookup_deltaseq() { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + const char *seq; + pool->pos = *$self; + seq = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME); + if (seq) { + seq = pool_tmpjoin(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR)); + seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM)); + } + pool->pos = oldpos; + return seq; + } + const char *lookup_deltalocation(unsigned int *OUTPUT) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + const char *loc; + pool->pos = *$self; + loc = pool_lookup_deltalocation(pool, SOLVID_POS, OUTPUT); + pool->pos = oldpos; + return loc; + } + Queue lookup_idarray(Id keyname) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + Queue r; + queue_init(&r); + pool->pos = *$self; + pool_lookup_idarray(pool, SOLVID_POS, keyname, &r); + pool->pos = oldpos; + return r; + } + %newobject Dataiterator; + Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) { + Pool *pool = $self->repo->pool; + Datapos oldpos = pool->pos; + Dataiterator *di; + pool->pos = *$self; + di = new_Dataiterator(pool, 0, SOLVID_POS, key, match, flags); + pool->pos = oldpos; + return di; + } +} + +%extend Datamatch { + ~Datamatch() { + dataiterator_free($self); + solv_free($self); + } + %newobject solvable; + XSolvable * const solvable; + Id const key_id; + const char * const key_idstr; + Id const type_id; + const char * const type_idstr; + Id const id; + const char * const idstr; + const char * const str; + BinaryBlob const binary; + unsigned long long const num; + unsigned int const num2; + %{ + SWIGINTERN XSolvable *Datamatch_solvable_get(Dataiterator *di) { + return new_XSolvable(di->pool, di->solvid); + } + SWIGINTERN Id Datamatch_key_id_get(Dataiterator *di) { + return di->key->name; + } + SWIGINTERN const char *Datamatch_key_idstr_get(Dataiterator *di) { + return pool_id2str(di->pool, di->key->name); + } + SWIGINTERN Id Datamatch_type_id_get(Dataiterator *di) { + return di->key->type; + } + SWIGINTERN const char *Datamatch_type_idstr_get(Dataiterator *di) { + return pool_id2str(di->pool, di->key->type); + } + SWIGINTERN Id Datamatch_id_get(Dataiterator *di) { + return di->kv.id; + } + SWIGINTERN const char *Datamatch_idstr_get(Dataiterator *di) { + if (di->data && (di->key->type == REPOKEY_TYPE_DIR || di->key->type == REPOKEY_TYPE_DIRSTRARRAY || di->key->type == REPOKEY_TYPE_DIRNUMNUMARRAY)) + return repodata_dir2str(di->data, di->kv.id, 0); + if (di->data && di->data->localpool) + return stringpool_id2str(&di->data->spool, di->kv.id); + return pool_id2str(di->pool, di->kv.id); + } + SWIGINTERN const char * const Datamatch_str_get(Dataiterator *di) { + return di->kv.str; + } + SWIGINTERN BinaryBlob Datamatch_binary_get(Dataiterator *di) { + BinaryBlob bl; + bl.data = 0; + bl.len = 0; + if (di->key->type == REPOKEY_TYPE_BINARY) + { + bl.data = di->kv.str; + bl.len = di->kv.num; + } + else if ((bl.len = solv_chksum_len(di->key->type)) != 0) + bl.data = di->kv.str; + return bl; + } + SWIGINTERN unsigned long long Datamatch_num_get(Dataiterator *di) { + if (di->key->type == REPOKEY_TYPE_NUM) + return SOLV_KV_NUM64(&di->kv); + return di->kv.num; + } + SWIGINTERN unsigned int Datamatch_num2_get(Dataiterator *di) { + return di->kv.num2; + } + %} + %newobject pos; + Datapos *pos() { + Pool *pool = $self->pool; + Datapos *pos, oldpos = pool->pos; + dataiterator_setpos($self); + pos = solv_calloc(1, sizeof(*pos)); + *pos = pool->pos; + pool->pos = oldpos; + return pos; + } + %newobject parentpos; + Datapos *parentpos() { + Pool *pool = $self->pool; + Datapos *pos, oldpos = pool->pos; + dataiterator_setpos_parent($self); + pos = solv_calloc(1, sizeof(*pos)); + *pos = pool->pos; + pool->pos = oldpos; + return pos; + } +#if defined(SWIGPERL) + /* cannot use str here because swig reports a bogus conflict... */ + %rename("stringify") __str__; + %perlcode { + *solv::Datamatch::str = *solvc::Datamatch_stringify; + } +#endif +#if defined(SWIGTCL) + %rename("stringify") __str__; +#endif + const char *__str__() { + KeyValue kv = $self->kv; + const char *str = repodata_stringify($self->pool, $self->data, $self->key, &kv, SEARCH_FILES | SEARCH_CHECKSUMS); + return str ? str : ""; + } +} + +%extend Pool_solvable_iterator { + Pool_solvable_iterator(Pool *pool) { + Pool_solvable_iterator *s; + s = solv_calloc(1, sizeof(*s)); + s->pool = pool; + return s; + } +#if defined(SWIGPYTHON) + %pythoncode { + def __iter__(self): return self + } +#ifndef PYTHON3 + %rename("next") __next__(); +#endif + %exception __next__ { + $action + if (!result) { + PyErr_SetString(PyExc_StopIteration,"no more matches"); + return NULL; + } + } +#endif +#ifdef SWIGPERL + perliter(solv::Pool_solvable_iterator) +#endif + %newobject __next__; + XSolvable *__next__() { + Pool *pool = $self->pool; + if ($self->id >= pool->nsolvables) + return 0; + while (++$self->id < pool->nsolvables) + if (pool->solvables[$self->id].repo) + return new_XSolvable(pool, $self->id); + return 0; + } +#ifdef SWIGRUBY + void each() { + XSolvable *n; + while ((n = Pool_solvable_iterator___next__($self)) != 0) { + rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0)); + } + } +#endif + %newobject __getitem__; + XSolvable *__getitem__(Id key) { + Pool *pool = $self->pool; + if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo) + return new_XSolvable(pool, key); + return 0; + } + int __len__() { + return $self->pool->nsolvables; + } +} + +%extend Pool_repo_iterator { + Pool_repo_iterator(Pool *pool) { + Pool_repo_iterator *s; + s = solv_calloc(1, sizeof(*s)); + s->pool = pool; + return s; + } +#if defined(SWIGPYTHON) + %pythoncode { + def __iter__(self): return self + } +#ifndef PYTHON3 + %rename("next") __next__(); +#endif + %exception __next__ { + $action + if (!result) { + PyErr_SetString(PyExc_StopIteration,"no more matches"); + return NULL; + } + } +#endif +#ifdef SWIGPERL + perliter(solv::Pool_repo_iterator) +#endif + Repo *__next__() { + Pool *pool = $self->pool; + if ($self->id >= pool->nrepos) + return 0; + while (++$self->id < pool->nrepos) { + Repo *r = pool_id2repo(pool, $self->id); + if (r) + return r; + } + return 0; + } +#ifdef SWIGRUBY + void each() { + Repo *n; + while ((n = Pool_repo_iterator___next__($self)) != 0) { + rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, 0 | 0)); + } + } +#endif + Repo *__getitem__(Id key) { + Pool *pool = $self->pool; + if (key > 0 && key < pool->nrepos) + return pool_id2repo(pool, key); + return 0; + } + int __len__() { + return $self->pool->nrepos; + } +} + +%extend Repo_solvable_iterator { + Repo_solvable_iterator(Repo *repo) { + Repo_solvable_iterator *s; + s = solv_calloc(1, sizeof(*s)); + s->repo = repo; + return s; + } +#if defined(SWIGPYTHON) + %pythoncode { + def __iter__(self): return self + } +#ifndef PYTHON3 + %rename("next") __next__(); +#endif + %exception __next__ { + $action + if (!result) { + PyErr_SetString(PyExc_StopIteration,"no more matches"); + return NULL; + } + } +#endif +#ifdef SWIGPERL + perliter(solv::Repo_solvable_iterator) +#endif + %newobject __next__; + XSolvable *__next__() { + Repo *repo = $self->repo; + Pool *pool = repo->pool; + if (repo->start > 0 && $self->id < repo->start) + $self->id = repo->start - 1; + if ($self->id >= repo->end) + return 0; + while (++$self->id < repo->end) + if (pool->solvables[$self->id].repo == repo) + return new_XSolvable(pool, $self->id); + return 0; + } +#ifdef SWIGRUBY + void each() { + XSolvable *n; + while ((n = Repo_solvable_iterator___next__($self)) != 0) { + rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0)); + } + } +#endif + %newobject __getitem__; + XSolvable *__getitem__(Id key) { + Repo *repo = $self->repo; + Pool *pool = repo->pool; + if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo == repo) + return new_XSolvable(pool, key); + return 0; + } + int __len__() { + return $self->repo->pool->nsolvables; + } +} + +%extend Dep { + Dep(Pool *pool, Id id) { + Dep *s; + if (!id) + return 0; + s = solv_calloc(1, sizeof(*s)); + s->pool = pool; + s->id = id; + return s; + } + %newobject Rel; + Dep *Rel(int flags, DepId evrid, bool create=1) { + Id id = pool_rel2id($self->pool, $self->id, evrid, flags, create); + if (!id) + return 0; + return new_Dep($self->pool, id); + } + %newobject Selection_name; + Selection *Selection_name(int setflags=0) { + Selection *sel = new_Selection($self->pool); + if (ISRELDEP($self->id)) { + Reldep *rd = GETRELDEP($self->pool, $self->id); + if (rd->flags == REL_EQ) { + setflags |= $self->pool->disttype == DISTTYPE_DEB || strchr(pool_id2str($self->pool, rd->evr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV; + if (ISRELDEP(rd->name)) + rd = GETRELDEP($self->pool, rd->name); + } + if (rd->flags == REL_ARCH) + setflags |= SOLVER_SETARCH; + } + queue_push2(&sel->q, SOLVER_SOLVABLE_NAME | setflags, $self->id); + return sel; + } + %newobject Selection_provides; + Selection *Selection_provides(int setflags=0) { + Selection *sel = new_Selection($self->pool); + if (ISRELDEP($self->id)) { + Reldep *rd = GETRELDEP($self->pool, $self->id); + if (rd->flags == REL_ARCH) + setflags |= SOLVER_SETARCH; + } + queue_push2(&sel->q, SOLVER_SOLVABLE_PROVIDES | setflags, $self->id); + return sel; + } + const char *str() { + return pool_dep2str($self->pool, $self->id); + } +#if defined(SWIGTCL) + %rename("==") __eq__; +#endif + bool __eq__(Dep *s) { + return $self->pool == s->pool && $self->id == s->id; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + 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 + const char *__str__() { + return pool_dep2str($self->pool, $self->id); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + %newobject __repr__; + const char *__repr__() { + char buf[20]; + sprintf(buf, "id); + return solv_dupjoin(buf, pool_dep2str($self->pool, $self->id), ">"); + } +} + +%extend XSolvable { + XSolvable(Pool *pool, Id id) { + XSolvable *s; + if (!id || id >= pool->nsolvables) + return 0; + s = solv_calloc(1, sizeof(*s)); + s->pool = pool; + s->id = id; + return s; + } + const char *str() { + return pool_solvid2str($self->pool, $self->id); + } + const char *lookup_str(Id keyname) { + return pool_lookup_str($self->pool, $self->id, keyname); + } + Id lookup_id(Id keyname) { + return pool_lookup_id($self->pool, $self->id, keyname); + } + unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) { + return pool_lookup_num($self->pool, $self->id, keyname, notfound); + } + bool lookup_void(Id keyname) { + return pool_lookup_void($self->pool, $self->id, keyname); + } + %newobject lookup_checksum; + Chksum *lookup_checksum(Id keyname) { + Id type = 0; + const unsigned char *b = pool_lookup_bin_checksum($self->pool, $self->id, keyname, &type); + return solv_chksum_create_from_bin(type, b); + } + Queue lookup_idarray(Id keyname, Id marker = -1) { + Solvable *s = $self->pool->solvables + $self->id; + Queue r; + queue_init(&r); + solvable_lookup_deparray(s, keyname, &r, marker); + return r; + } + %typemap(out) Queue lookup_deparray Queue2Array(Dep *, 1, new_Dep(arg1->pool, id)); + %newobject lookup_deparray; + Queue lookup_deparray(Id keyname, Id marker = -1) { + Solvable *s = $self->pool->solvables + $self->id; + Queue r; + queue_init(&r); + solvable_lookup_deparray(s, keyname, &r, marker); + return r; + } + 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); + } +#ifdef SWIGRUBY + %rename("installable?") installable; +#endif + bool installable() { + return pool_installable($self->pool, pool_id2solvable($self->pool, $self->id)); + } +#ifdef SWIGRUBY + %rename("isinstalled?") isinstalled; +#endif + bool isinstalled() { + Pool *pool = $self->pool; + return pool->installed && pool_id2solvable(pool, $self->id)->repo == pool->installed; + } + + const char *name; + %{ + SWIGINTERN void XSolvable_name_set(XSolvable *xs, const char *name) { + Pool *pool = xs->pool; + pool->solvables[xs->id].name = pool_str2id(pool, name, 1); + } + SWIGINTERN const char *XSolvable_name_get(XSolvable *xs) { + Pool *pool = xs->pool; + return pool_id2str(pool, pool->solvables[xs->id].name); + } + %} + Id nameid; + %{ + SWIGINTERN void XSolvable_nameid_set(XSolvable *xs, Id nameid) { + xs->pool->solvables[xs->id].name = nameid; + } + SWIGINTERN Id XSolvable_nameid_get(XSolvable *xs) { + return xs->pool->solvables[xs->id].name; + } + %} + const char *evr; + %{ + SWIGINTERN void XSolvable_evr_set(XSolvable *xs, const char *evr) { + Pool *pool = xs->pool; + pool->solvables[xs->id].evr = pool_str2id(pool, evr, 1); + } + SWIGINTERN const char *XSolvable_evr_get(XSolvable *xs) { + Pool *pool = xs->pool; + return pool_id2str(pool, pool->solvables[xs->id].evr); + } + %} + Id evrid; + %{ + SWIGINTERN void XSolvable_evrid_set(XSolvable *xs, Id evrid) { + xs->pool->solvables[xs->id].evr = evrid; + } + SWIGINTERN Id XSolvable_evrid_get(XSolvable *xs) { + return xs->pool->solvables[xs->id].evr; + } + %} + const char *arch; + %{ + SWIGINTERN void XSolvable_arch_set(XSolvable *xs, const char *arch) { + Pool *pool = xs->pool; + pool->solvables[xs->id].arch = pool_str2id(pool, arch, 1); + } + SWIGINTERN const char *XSolvable_arch_get(XSolvable *xs) { + Pool *pool = xs->pool; + return pool_id2str(pool, pool->solvables[xs->id].arch); + } + %} + Id archid; + %{ + SWIGINTERN void XSolvable_archid_set(XSolvable *xs, Id archid) { + xs->pool->solvables[xs->id].arch = archid; + } + SWIGINTERN Id XSolvable_archid_get(XSolvable *xs) { + return xs->pool->solvables[xs->id].arch; + } + %} + const char *vendor; + %{ + SWIGINTERN void XSolvable_vendor_set(XSolvable *xs, const char *vendor) { + Pool *pool = xs->pool; + pool->solvables[xs->id].vendor = pool_str2id(pool, vendor, 1); + } + SWIGINTERN const char *XSolvable_vendor_get(XSolvable *xs) { + Pool *pool = xs->pool; + return pool_id2str(pool, pool->solvables[xs->id].vendor); + } + %} + Id vendorid; + %{ + SWIGINTERN void XSolvable_vendorid_set(XSolvable *xs, Id vendorid) { + xs->pool->solvables[xs->id].vendor = vendorid; + } + SWIGINTERN Id XSolvable_vendorid_get(XSolvable *xs) { + return xs->pool->solvables[xs->id].vendor; + } + %} + Repo * const repo; + %{ + SWIGINTERN Repo *XSolvable_repo_get(XSolvable *xs) { + return xs->pool->solvables[xs->id].repo; + } + %} + + /* old interface, please use the generic add_deparray instead */ + void add_provides(DepId id, Id marker = -1) { + Solvable *s = $self->pool->solvables + $self->id; + marker = solv_depmarker(SOLVABLE_PROVIDES, marker); + s->provides = repo_addid_dep(s->repo, s->provides, id, marker); + } + void add_obsoletes(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->obsoletes = repo_addid_dep(s->repo, s->obsoletes, id, 0); + } + void add_conflicts(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0); + } + void add_requires(DepId id, Id marker = -1) { + Solvable *s = $self->pool->solvables + $self->id; + marker = solv_depmarker(SOLVABLE_REQUIRES, marker); + s->requires = repo_addid_dep(s->repo, s->requires, id, marker); + } + void add_recommends(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->recommends = repo_addid_dep(s->repo, s->recommends, id, 0); + } + void add_suggests(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->suggests = repo_addid_dep(s->repo, s->suggests, id, 0); + } + void add_supplements(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->supplements = repo_addid_dep(s->repo, s->supplements, id, 0); + } + void add_enhances(DepId id) { + Solvable *s = $self->pool->solvables + $self->id; + s->enhances = repo_addid_dep(s->repo, s->enhances, id, 0); + } + + void unset(Id keyname) { + Solvable *s = $self->pool->solvables + $self->id; + repo_unset(s->repo, $self->id, keyname); + } + + void add_deparray(Id keyname, DepId id, Id marker = -1) { + Solvable *s = $self->pool->solvables + $self->id; + solvable_add_deparray(s, keyname, id, marker); + } + + %newobject Selection; + Selection *Selection(int setflags=0) { + Selection *sel = new_Selection($self->pool); + queue_push2(&sel->q, SOLVER_SOLVABLE | setflags, $self->id); + return sel; + } + +#ifdef SWIGRUBY + %rename("identical?") identical; +#endif + bool identical(XSolvable *s2) { + return solvable_identical($self->pool->solvables + $self->id, s2->pool->solvables + s2->id); + } + 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__; +#endif + bool __eq__(XSolvable *s) { + return $self->pool == s->pool && $self->id == s->id; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + 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 + const char *__str__() { + return pool_solvid2str($self->pool, $self->id); + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("repr") __repr__; +#endif + %newobject __repr__; + const char *__repr__() { + char buf[20]; + sprintf(buf, "id); + return solv_dupjoin(buf, pool_solvid2str($self->pool, $self->id), ">"); + } +} + +%extend Problem { + Problem(Solver *solv, Id id) { + Problem *p; + p = solv_calloc(1, sizeof(*p)); + p->solv = solv; + p->id = id; + return p; + } + %newobject findproblemrule; + XRule *findproblemrule() { + Id r = solver_findproblemrule($self->solv, $self->id); + return new_XRule($self->solv, r); + } + %newobject findallproblemrules; + %typemap(out) Queue findallproblemrules Queue2Array(XRule *, 1, new_XRule(arg1->solv, id)); + Queue findallproblemrules(int unfiltered=0) { + Solver *solv = $self->solv; + Id probr; + int i, j; + Queue q; + queue_init(&q); + solver_findallproblemrules(solv, $self->id, &q); + if (!unfiltered) + { + for (i = j = 0; i < q.count; i++) + { + SolverRuleinfo rclass; + probr = q.elements[i]; + rclass = solver_ruleclass(solv, probr); + if (rclass == SOLVER_RULE_UPDATE || rclass == SOLVER_RULE_JOB) + continue; + q.elements[j++] = probr; + } + if (j) + queue_truncate(&q, j); + } + return q; + } + int solution_count() { + return solver_solution_count($self->solv, $self->id); + } + %typemap(out) Queue solutions Queue2Array(Solution *, 1, new_Solution(arg1, id)); + %newobject solutions; + Queue solutions() { + Queue q; + int i, cnt; + queue_init(&q); + cnt = solver_solution_count($self->solv, $self->id); + for (i = 1; i <= cnt; i++) + queue_push(&q, i); + return q; + } +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("str") __str__; +#endif + const char *__str__() { + return solver_problem2str($self->solv, $self->id); + } +} + +%extend Solution { + Solution(Problem *p, Id id) { + Solution *s; + s = solv_calloc(1, sizeof(*s)); + s->solv = p->solv; + s->problemid = p->id; + s->id = id; + return s; + } + int element_count() { + return solver_solutionelement_count($self->solv, $self->problemid, $self->id); + } + + %typemap(out) Queue elements Queue2Array(Solutionelement *, 4, new_Solutionelement(arg1->solv, arg1->problemid, arg1->id, id, idp[1], idp[2], idp[3])); + %newobject elements; + Queue elements(bool expandreplaces=0) { + Queue q; + int i, cnt; + queue_init(&q); + cnt = solver_solutionelement_count($self->solv, $self->problemid, $self->id); + for (i = 1; i <= cnt; i++) + { + Id p, rp, type; + solver_next_solutionelement($self->solv, $self->problemid, $self->id, i - 1, &p, &rp); + if (p > 0) { + type = rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE; + } else { + type = p; + p = rp; + rp = 0; + } + if (type == SOLVER_SOLUTION_REPLACE && expandreplaces) { + int illegal = policy_is_illegal(self->solv, self->solv->pool->solvables + p, self->solv->pool->solvables + rp, 0); + if (illegal) { + if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0) { + queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_DOWNGRADE); + queue_push2(&q, p, rp); + } + if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0) { + queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_ARCHCHANGE); + queue_push2(&q, p, rp); + } + if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0) { + queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_VENDORCHANGE); + queue_push2(&q, p, rp); + } + if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0) { + queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_NAMECHANGE); + queue_push2(&q, p, rp); + } + continue; + } + } + queue_push2(&q, i, type); + queue_push2(&q, p, rp); + } + return q; + } +} + +%extend Solutionelement { + Solutionelement(Solver *solv, Id problemid, Id solutionid, Id id, Id type, Id p, Id rp) { + Solutionelement *e; + e = solv_calloc(1, sizeof(*e)); + e->solv = solv; + e->problemid = problemid; + e->solutionid = id; + e->id = id; + e->type = type; + e->p = p; + e->rp = rp; + return e; + } + const char *str() { + Id p = $self->type; + Id rp = $self->p; + int illegal = 0; + if (p == SOLVER_SOLUTION_ERASE) + { + p = rp; + rp = 0; + } + else if (p == SOLVER_SOLUTION_REPLACE) + { + p = rp; + rp = $self->rp; + } + else if (p == SOLVER_SOLUTION_REPLACE_DOWNGRADE) + illegal = POLICY_ILLEGAL_DOWNGRADE; + else if (p == SOLVER_SOLUTION_REPLACE_ARCHCHANGE) + illegal = POLICY_ILLEGAL_ARCHCHANGE; + else if (p == SOLVER_SOLUTION_REPLACE_VENDORCHANGE) + illegal = POLICY_ILLEGAL_VENDORCHANGE; + else if (p == SOLVER_SOLUTION_REPLACE_NAMECHANGE) + illegal = POLICY_ILLEGAL_NAMECHANGE; + if (illegal) + return pool_tmpjoin($self->solv->pool, "allow ", policy_illegal2str($self->solv, illegal, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp), 0); + return solver_solutionelement2str($self->solv, p, rp); + } + %typemap(out) Queue replaceelements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1->solv, arg1->problemid, arg1->solutionid, arg1->id, id, arg1->p, arg1->rp)); + %newobject replaceelements; + Queue replaceelements() { + Queue q; + int illegal; + + queue_init(&q); + if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0) + illegal = 0; + else + illegal = policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0); + if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0) + queue_push(&q, SOLVER_SOLUTION_REPLACE_DOWNGRADE); + if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0) + queue_push(&q, SOLVER_SOLUTION_REPLACE_ARCHCHANGE); + if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0) + queue_push(&q, SOLVER_SOLUTION_REPLACE_VENDORCHANGE); + if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0) + queue_push(&q, SOLVER_SOLUTION_REPLACE_NAMECHANGE); + if (!q.count) + queue_push(&q, $self->type); + return q; + } + int illegalreplace() { + if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0) + return 0; + return policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0); + } + %newobject solvable; + XSolvable * const solvable; + %newobject replacement; + XSolvable * const replacement; + int const jobidx; + %{ + SWIGINTERN XSolvable *Solutionelement_solvable_get(Solutionelement *e) { + return new_XSolvable(e->solv->pool, e->p); + } + SWIGINTERN XSolvable *Solutionelement_replacement_get(Solutionelement *e) { + return new_XSolvable(e->solv->pool, e->rp); + } + SWIGINTERN int Solutionelement_jobidx_get(Solutionelement *e) { + if (e->type != SOLVER_SOLUTION_JOB && e->type != SOLVER_SOLUTION_POOLJOB) + return -1; + return (e->p - 1) / 2; + } + %} + %newobject Job; + Job *Job() { + Id extraflags = solver_solutionelement_extrajobflags($self->solv, $self->problemid, $self->solutionid); + if ($self->type == SOLVER_SOLUTION_JOB || $self->type == SOLVER_SOLUTION_POOLJOB) + return new_Job($self->solv->pool, SOLVER_NOOP, 0); + if ($self->type == SOLVER_SOLUTION_INFARCH || $self->type == SOLVER_SOLUTION_DISTUPGRADE || $self->type == SOLVER_SOLUTION_BEST) + return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->p); + if ($self->type == SOLVER_SOLUTION_REPLACE || $self->type == SOLVER_SOLUTION_REPLACE_DOWNGRADE || $self->type == SOLVER_SOLUTION_REPLACE_ARCHCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_VENDORCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_NAMECHANGE) + return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->rp); + if ($self->type == SOLVER_SOLUTION_ERASE) + return new_Job($self->solv->pool, SOLVER_ERASE|SOLVER_SOLVABLE|extraflags, $self->p); + return 0; + } +} + +%extend Solver { + static const int SOLVER_RULE_UNKNOWN = SOLVER_RULE_UNKNOWN; + static const int SOLVER_RULE_PKG = SOLVER_RULE_PKG; + static const int SOLVER_RULE_PKG_NOT_INSTALLABLE = SOLVER_RULE_PKG_NOT_INSTALLABLE; + static const int SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP = SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP; + static const int SOLVER_RULE_PKG_REQUIRES = SOLVER_RULE_PKG_REQUIRES; + static const int SOLVER_RULE_PKG_SELF_CONFLICT = SOLVER_RULE_PKG_SELF_CONFLICT; + static const int SOLVER_RULE_PKG_CONFLICTS = SOLVER_RULE_PKG_CONFLICTS; + static const int SOLVER_RULE_PKG_SAME_NAME = SOLVER_RULE_PKG_SAME_NAME; + static const int SOLVER_RULE_PKG_OBSOLETES = SOLVER_RULE_PKG_OBSOLETES; + static const int SOLVER_RULE_PKG_IMPLICIT_OBSOLETES = SOLVER_RULE_PKG_IMPLICIT_OBSOLETES; + static const int SOLVER_RULE_PKG_INSTALLED_OBSOLETES = SOLVER_RULE_PKG_INSTALLED_OBSOLETES; + static const int SOLVER_RULE_UPDATE = SOLVER_RULE_UPDATE; + static const int SOLVER_RULE_FEATURE = SOLVER_RULE_FEATURE; + static const int SOLVER_RULE_JOB = SOLVER_RULE_JOB; + static const int SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP = SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP; + static const int SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM = SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM; + static const int SOLVER_RULE_JOB_UNKNOWN_PACKAGE = SOLVER_RULE_JOB_UNKNOWN_PACKAGE; + static const int SOLVER_RULE_JOB_UNSUPPORTED = SOLVER_RULE_JOB_UNSUPPORTED; + static const int SOLVER_RULE_DISTUPGRADE = SOLVER_RULE_DISTUPGRADE; + static const int SOLVER_RULE_INFARCH = SOLVER_RULE_INFARCH; + static const int SOLVER_RULE_CHOICE = SOLVER_RULE_CHOICE; + static const int SOLVER_RULE_LEARNT = SOLVER_RULE_LEARNT; + + static const int SOLVER_SOLUTION_JOB = SOLVER_SOLUTION_JOB; + static const int SOLVER_SOLUTION_POOLJOB = SOLVER_SOLUTION_POOLJOB; + static const int SOLVER_SOLUTION_INFARCH = SOLVER_SOLUTION_INFARCH; + static const int SOLVER_SOLUTION_DISTUPGRADE = SOLVER_SOLUTION_DISTUPGRADE; + static const int SOLVER_SOLUTION_BEST = SOLVER_SOLUTION_BEST; + static const int SOLVER_SOLUTION_ERASE = SOLVER_SOLUTION_ERASE; + static const int SOLVER_SOLUTION_REPLACE = SOLVER_SOLUTION_REPLACE; + static const int SOLVER_SOLUTION_REPLACE_DOWNGRADE = SOLVER_SOLUTION_REPLACE_DOWNGRADE; + static const int SOLVER_SOLUTION_REPLACE_ARCHCHANGE = SOLVER_SOLUTION_REPLACE_ARCHCHANGE; + static const int SOLVER_SOLUTION_REPLACE_VENDORCHANGE = SOLVER_SOLUTION_REPLACE_VENDORCHANGE; + static const int SOLVER_SOLUTION_REPLACE_NAMECHANGE = SOLVER_SOLUTION_REPLACE_NAMECHANGE; + + static const int POLICY_ILLEGAL_DOWNGRADE = POLICY_ILLEGAL_DOWNGRADE; + static const int POLICY_ILLEGAL_ARCHCHANGE = POLICY_ILLEGAL_ARCHCHANGE; + static const int POLICY_ILLEGAL_VENDORCHANGE = POLICY_ILLEGAL_VENDORCHANGE; + static const int POLICY_ILLEGAL_NAMECHANGE = POLICY_ILLEGAL_NAMECHANGE; + + static const int SOLVER_FLAG_ALLOW_DOWNGRADE = SOLVER_FLAG_ALLOW_DOWNGRADE; + static const int SOLVER_FLAG_ALLOW_ARCHCHANGE = SOLVER_FLAG_ALLOW_ARCHCHANGE; + static const int SOLVER_FLAG_ALLOW_VENDORCHANGE = SOLVER_FLAG_ALLOW_VENDORCHANGE; + static const int SOLVER_FLAG_ALLOW_NAMECHANGE = SOLVER_FLAG_ALLOW_NAMECHANGE; + static const int SOLVER_FLAG_ALLOW_UNINSTALL = SOLVER_FLAG_ALLOW_UNINSTALL; + static const int SOLVER_FLAG_NO_UPDATEPROVIDE = SOLVER_FLAG_NO_UPDATEPROVIDE; + static const int SOLVER_FLAG_SPLITPROVIDES = SOLVER_FLAG_SPLITPROVIDES; + static const int SOLVER_FLAG_IGNORE_RECOMMENDED = SOLVER_FLAG_IGNORE_RECOMMENDED; + static const int SOLVER_FLAG_ADD_ALREADY_RECOMMENDED = SOLVER_FLAG_ADD_ALREADY_RECOMMENDED; + static const int SOLVER_FLAG_NO_INFARCHCHECK = SOLVER_FLAG_NO_INFARCHCHECK; + static const int SOLVER_FLAG_BEST_OBEY_POLICY = SOLVER_FLAG_BEST_OBEY_POLICY; + static const int SOLVER_FLAG_NO_AUTOTARGET = SOLVER_FLAG_NO_AUTOTARGET; + static const int SOLVER_FLAG_DUP_ALLOW_DOWNGRADE = SOLVER_FLAG_DUP_ALLOW_DOWNGRADE; + static const int SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE = SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE; + static const int SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE = SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE; + static const int SOLVER_FLAG_DUP_ALLOW_NAMECHANGE = SOLVER_FLAG_DUP_ALLOW_NAMECHANGE; + static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS; + static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS; + 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_FLAG_ONLY_NAMESPACE_RECOMMENDED = SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED; + + static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED; + static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE; + static const int SOLVER_REASON_KEEP_INSTALLED = SOLVER_REASON_KEEP_INSTALLED; + static const int SOLVER_REASON_RESOLVE_JOB = SOLVER_REASON_RESOLVE_JOB; + static const int SOLVER_REASON_UPDATE_INSTALLED = SOLVER_REASON_UPDATE_INSTALLED; + static const int SOLVER_REASON_CLEANDEPS_ERASE = SOLVER_REASON_CLEANDEPS_ERASE; + static const int SOLVER_REASON_RESOLVE = SOLVER_REASON_RESOLVE; + static const int SOLVER_REASON_WEAKDEP = SOLVER_REASON_WEAKDEP; + static const int SOLVER_REASON_RESOLVE_ORPHAN = SOLVER_REASON_RESOLVE_ORPHAN; + static const int SOLVER_REASON_RECOMMENDED = SOLVER_REASON_RECOMMENDED; + static const int SOLVER_REASON_SUPPLEMENTED = SOLVER_REASON_SUPPLEMENTED; + + /* legacy */ + static const int SOLVER_RULE_RPM = SOLVER_RULE_RPM; + + ~Solver() { + solver_free($self); + } + + int set_flag(int flag, int value) { + return solver_set_flag($self, flag, value); + } + int get_flag(int flag) { + return solver_get_flag($self, flag); + } + + %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id)); + %newobject solve; + Queue solve(Queue solvejobs) { + Queue q; + int i, cnt; + queue_init(&q); + solver_solve($self, &solvejobs); + cnt = solver_problem_count($self); + for (i = 1; i <= cnt; i++) + queue_push(&q, i); + return q; + } + + %newobject transaction; + Transaction *transaction() { + return solver_create_transaction($self); + } + + int describe_decision(XSolvable *s, XRule **OUTPUT) { + int ruleid; + int reason = solver_describe_decision($self, s->id, &ruleid); + *OUTPUT = new_XRule($self, ruleid); + return reason; + } + + %newobject describe_weakdep_decision_raw; + Queue describe_weakdep_decision_raw(XSolvable *s) { + Queue q; + queue_init(&q); + solver_describe_weakdep_decision($self, s->id, &q); + return q; + } +#if defined(SWIGPYTHON) + %pythoncode { + def describe_weakdep_decision(self, s): + d = iter(self.describe_weakdep_decision_raw(s)) + return [ (t, XSolvable(self.pool, sid), Dep(self.pool, id)) for t, sid, id in zip(d, d, d) ] + } +#endif +#if defined(SWIGPERL) + %perlcode { + sub solv::Solver::describe_weakdep_decision { + my ($self, $s) = @_; + my $pool = $self->{'pool'}; + my @res; + my @d = $self->describe_weakdep_decision_raw($s); + push @res, [ splice(@d, 0, 3) ] while @d; + return map { [ $_->[0], solv::XSolvable->new($pool, $_->[1]), solv::Dep->new($pool, $_->[2]) ] } @res; + } + } +#endif +#if defined(SWIGRUBY) +%init %{ +rb_eval_string( + "class Solv::Solver\n" + " def describe_weakdep_decision(s)\n" + " self.describe_weakdep_decision_raw(s).each_slice(3).map { |t, sid, id| [ t, Solv::XSolvable.new(self.pool, sid), Solv::Dep.new(self.pool, id)] }\n" + " end\n" + "end\n" + ); +%} +#endif + + int alternatives_count() { + return solver_alternatives_count($self); + } + + %newobject alternative; + Alternative *alternative(Id aid) { + Alternative *a = solv_calloc(1, sizeof(*a)); + a->solv = $self; + queue_init(&a->choices); + a->type = solver_get_alternative($self, aid, &a->dep_id, &a->from_id, &a->chosen_id, &a->choices, &a->level); + if (!a->type) { + queue_free(&a->choices); + solv_free(a); + return 0; + } + if (a->type == SOLVER_ALTERNATIVE_TYPE_RULE) { + a->rid = a->dep_id; + a->dep_id = 0; + } + return a; + } + + %typemap(out) Queue all_alternatives Queue2Array(Alternative *, 1, Solver_alternative(arg1, id)); + %newobject all_alternatives; + Queue all_alternatives() { + Queue q; + int i, cnt; + queue_init(&q); + cnt = solver_alternatives_count($self); + for (i = 1; i <= cnt; i++) + queue_push(&q, i); + return q; + } + + 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 { + static const int SOLVER_TRANSACTION_IGNORE = SOLVER_TRANSACTION_IGNORE; + static const int SOLVER_TRANSACTION_ERASE = SOLVER_TRANSACTION_ERASE; + static const int SOLVER_TRANSACTION_REINSTALLED = SOLVER_TRANSACTION_REINSTALLED; + static const int SOLVER_TRANSACTION_DOWNGRADED = SOLVER_TRANSACTION_DOWNGRADED; + static const int SOLVER_TRANSACTION_CHANGED = SOLVER_TRANSACTION_CHANGED; + static const int SOLVER_TRANSACTION_UPGRADED = SOLVER_TRANSACTION_UPGRADED; + static const int SOLVER_TRANSACTION_OBSOLETED = SOLVER_TRANSACTION_OBSOLETED; + static const int SOLVER_TRANSACTION_INSTALL = SOLVER_TRANSACTION_INSTALL; + static const int SOLVER_TRANSACTION_REINSTALL = SOLVER_TRANSACTION_REINSTALL; + static const int SOLVER_TRANSACTION_DOWNGRADE = SOLVER_TRANSACTION_DOWNGRADE; + static const int SOLVER_TRANSACTION_CHANGE = SOLVER_TRANSACTION_CHANGE; + static const int SOLVER_TRANSACTION_UPGRADE = SOLVER_TRANSACTION_UPGRADE; + static const int SOLVER_TRANSACTION_OBSOLETES = SOLVER_TRANSACTION_OBSOLETES; + static const int SOLVER_TRANSACTION_MULTIINSTALL = SOLVER_TRANSACTION_MULTIINSTALL; + static const int SOLVER_TRANSACTION_MULTIREINSTALL = SOLVER_TRANSACTION_MULTIREINSTALL; + static const int SOLVER_TRANSACTION_MAXTYPE = SOLVER_TRANSACTION_MAXTYPE; + static const int SOLVER_TRANSACTION_SHOW_ACTIVE = SOLVER_TRANSACTION_SHOW_ACTIVE; + static const int SOLVER_TRANSACTION_SHOW_ALL = SOLVER_TRANSACTION_SHOW_ALL; + static const int SOLVER_TRANSACTION_SHOW_OBSOLETES = SOLVER_TRANSACTION_SHOW_OBSOLETES; + static const int SOLVER_TRANSACTION_SHOW_MULTIINSTALL = SOLVER_TRANSACTION_SHOW_MULTIINSTALL; + static const int SOLVER_TRANSACTION_CHANGE_IS_REINSTALL = SOLVER_TRANSACTION_CHANGE_IS_REINSTALL; + static const int SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE = SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE; + static const int SOLVER_TRANSACTION_MERGE_VENDORCHANGES = SOLVER_TRANSACTION_MERGE_VENDORCHANGES; + static const int SOLVER_TRANSACTION_MERGE_ARCHCHANGES = SOLVER_TRANSACTION_MERGE_ARCHCHANGES; + static const int SOLVER_TRANSACTION_RPM_ONLY = SOLVER_TRANSACTION_RPM_ONLY; + static const int SOLVER_TRANSACTION_ARCHCHANGE = SOLVER_TRANSACTION_ARCHCHANGE; + static const int SOLVER_TRANSACTION_VENDORCHANGE = SOLVER_TRANSACTION_VENDORCHANGE; + static const int SOLVER_TRANSACTION_KEEP_ORDERDATA = SOLVER_TRANSACTION_KEEP_ORDERDATA; + ~Transaction() { + transaction_free($self); + } +#ifdef SWIGRUBY + %rename("isempty?") isempty; +#endif + bool isempty() { + return $self->steps.count == 0; + } + + %newobject othersolvable; + XSolvable *othersolvable(XSolvable *s) { + Id op = transaction_obs_pkg($self, s->id); + return new_XSolvable($self->pool, op); + } + + %typemap(out) Queue allothersolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject allothersolvables; + Queue allothersolvables(XSolvable *s) { + Queue q; + queue_init(&q); + transaction_all_obs_pkgs($self, s->id, &q); + return q; + } + + %typemap(out) Queue classify Queue2Array(TransactionClass *, 4, new_TransactionClass(arg1, arg2, id, idp[1], idp[2], idp[3])); + %newobject classify; + Queue classify(int mode = 0) { + Queue q; + queue_init(&q); + transaction_classify($self, mode, &q); + return q; + } + + /* deprecated, use newsolvables instead */ + %typemap(out) Queue newpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject newpackages; + Queue newpackages() { + Queue q; + int cut; + queue_init(&q); + cut = transaction_installedresult(self, &q); + queue_truncate(&q, cut); + return q; + } + + /* deprecated, use keptsolvables instead */ + %typemap(out) Queue keptpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject keptpackages; + Queue keptpackages() { + Queue q; + int cut; + queue_init(&q); + cut = transaction_installedresult(self, &q); + if (cut) + queue_deleten(&q, 0, cut); + return q; + } + + %typemap(out) Queue newsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject newsolvables; + Queue newsolvables() { + Queue q; + int cut; + queue_init(&q); + cut = transaction_installedresult(self, &q); + queue_truncate(&q, cut); + return q; + } + + %typemap(out) Queue keptsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject keptsolvables; + Queue keptsolvables() { + Queue q; + int cut; + queue_init(&q); + cut = transaction_installedresult(self, &q); + if (cut) + queue_deleten(&q, 0, cut); + return q; + } + + %typemap(out) Queue steps Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id)); + %newobject steps; + Queue steps() { + Queue q; + queue_init_clone(&q, &$self->steps); + return q; + } + + int steptype(XSolvable *s, int mode) { + return transaction_type($self, s->id, mode); + } + long long calc_installsizechange() { + return transaction_calc_installsizechange($self); + } + void order(int flags=0) { + transaction_order($self, flags); + } +} + +%extend TransactionClass { + TransactionClass(Transaction *trans, int mode, Id type, int count, Id fromid, Id toid) { + TransactionClass *cl = solv_calloc(1, sizeof(*cl)); + cl->transaction = trans; + cl->mode = mode; + cl->type = type; + cl->count = count; + cl->fromid = fromid; + cl->toid = toid; + return cl; + } + %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->transaction->pool, id)); + %newobject solvables; + Queue solvables() { + Queue q; + queue_init(&q); + transaction_classify_pkgs($self->transaction, $self->mode, $self->type, $self->fromid, $self->toid, &q); + return q; + } + const char * const fromstr; + const char * const tostr; + %{ + SWIGINTERN const char *TransactionClass_fromstr_get(TransactionClass *cl) { + return pool_id2str(cl->transaction->pool, cl->fromid); + } + SWIGINTERN const char *TransactionClass_tostr_get(TransactionClass *cl) { + return pool_id2str(cl->transaction->pool, cl->toid); + } + %} +} + +%extend XRule { + XRule(Solver *solv, Id id) { + if (!id) + return 0; + XRule *xr = solv_calloc(1, sizeof(*xr)); + xr->solv = solv; + xr->id = id; + return xr; + } + int const type; + %{ + SWIGINTERN int XRule_type_get(XRule *xr) { + return solver_ruleclass(xr->solv, xr->id); + } + %} + %newobject info; + Ruleinfo *info() { + Id type, source, target, dep; + type = solver_ruleinfo($self->solv, $self->id, &source, &target, &dep); + return new_Ruleinfo($self, type, source, target, dep); + } + %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1, id, idp[1], idp[2], idp[3])); + %newobject allinfos; + Queue allinfos() { + Queue q; + queue_init(&q); + solver_allruleinfos($self->solv, $self->id, &q); + return q; + } + +#if defined(SWIGTCL) + %rename("==") __eq__; +#endif + bool __eq__(XRule *xr) { + return $self->solv == xr->solv && $self->id == xr->id; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + 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 + %newobject __repr__; + const char *__repr__() { + char buf[20]; + sprintf(buf, "", $self->id); + return solv_strdup(buf); + } +} + +%extend Ruleinfo { + Ruleinfo(XRule *r, Id type, Id source, Id target, Id dep_id) { + Ruleinfo *ri = solv_calloc(1, sizeof(*ri)); + ri->solv = r->solv; + ri->rid = r->id; + ri->type = type; + ri->source = source; + ri->target = target; + ri->dep_id = dep_id; + return ri; + } + %newobject solvable; + XSolvable * const solvable; + %newobject othersolvable; + XSolvable * const othersolvable; + %newobject dep; + Dep * const dep; + %{ + SWIGINTERN XSolvable *Ruleinfo_solvable_get(Ruleinfo *ri) { + return new_XSolvable(ri->solv->pool, ri->source); + } + SWIGINTERN XSolvable *Ruleinfo_othersolvable_get(Ruleinfo *ri) { + return new_XSolvable(ri->solv->pool, ri->target); + } + SWIGINTERN Dep *Ruleinfo_dep_get(Ruleinfo *ri) { + return new_Dep(ri->solv->pool, ri->dep_id); + } + %} + const char *problemstr() { + return solver_problemruleinfo2str($self->solv, $self->type, $self->source, $self->target, $self->dep_id); + } +} + +%extend XRepodata { + XRepodata(Repo *repo, Id id) { + XRepodata *xr = solv_calloc(1, sizeof(*xr)); + xr->repo = repo; + xr->id = id; + return xr; + } + Id new_handle() { + return repodata_new_handle(repo_id2repodata($self->repo, $self->id)); + } + 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); + } + void add_idarray(Id solvid, Id keyname, DepId id) { + repodata_add_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, id); + } + void add_flexarray(Id solvid, Id keyname, Id handle) { + repodata_add_flexarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, handle); + } + void set_checksum(Id solvid, Id keyname, Chksum *chksum) { + const unsigned char *buf = solv_chksum_get(chksum, 0); + 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); + repodata_lookup_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, &r); + return r; + } + %newobject lookup_checksum; + Chksum *lookup_checksum(Id solvid, Id keyname) { + Id type = 0; + const unsigned char *b = repodata_lookup_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, &type); + return solv_chksum_create_from_bin(type, b); + } + void internalize() { + repodata_internalize(repo_id2repodata($self->repo, $self->id)); + } + void create_stubs() { + Repodata *data = repo_id2repodata($self->repo, $self->id); + data = repodata_create_stubs(data); + $self->id = data->repodataid; + } + 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; + data->state = REPODATA_LOADING; + r = repo_add_solv(data->repo, fp, flags | REPO_USE_LOADING); + if (r || data->state == REPODATA_LOADING) + data->state = oldstate; + return r; + } + void extend_to_repo() { + Repodata *data = repo_id2repodata($self->repo, $self->id); + repodata_extend_block(data, data->repo->start, data->repo->end - data->repo->start); + } +#if defined(SWIGTCL) + %rename("==") __eq__; +#endif + bool __eq__(XRepodata *xr) { + return $self->repo == xr->repo && $self->id == xr->id; + } +#if defined(SWIGTCL) + %rename("!=") __ne__; +#endif + 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 + %newobject __repr__; + const char *__repr__() { + char buf[20]; + sprintf(buf, "", $self->id); + return solv_strdup(buf); + } +} + +#ifdef ENABLE_PUBKEY +%extend Solvsig { + Solvsig(FILE *fp) { + return solvsig_create(fp); + } + ~Solvsig() { + solvsig_free($self); + } + %newobject Chksum; + Chksum *Chksum() { + return $self->htype ? (Chksum *)solv_chksum_create($self->htype) : 0; + } +#ifdef ENABLE_PGPVRFY + %newobject verify; + XSolvable *verify(Repo *repo, Chksum *chksum) { + Id p = solvsig_verify($self, repo, chksum); + return new_XSolvable(repo->pool, p); + } +#endif +} +#endif + +%extend Alternative { + static const int SOLVER_ALTERNATIVE_TYPE_RULE = SOLVER_ALTERNATIVE_TYPE_RULE; + static const int SOLVER_ALTERNATIVE_TYPE_RECOMMENDS = SOLVER_ALTERNATIVE_TYPE_RECOMMENDS; + static const int SOLVER_ALTERNATIVE_TYPE_SUGGESTS = SOLVER_ALTERNATIVE_TYPE_SUGGESTS; + + ~Alternative() { + queue_free(&$self->choices); + solv_free($self); + } + %newobject chosen; + XSolvable * const chosen; + %newobject rule; + XRule * const rule; + %newobject depsolvable; + XSolvable * const depsolvable; + %newobject dep; + Dep * const dep; + %{ + SWIGINTERN XSolvable *Alternative_chosen_get(Alternative *a) { + return new_XSolvable(a->solv->pool, a->chosen_id); + } + SWIGINTERN XRule *Alternative_rule_get(Alternative *a) { + return new_XRule(a->solv, a->rid); + } + SWIGINTERN XSolvable *Alternative_depsolvable_get(Alternative *a) { + return new_XSolvable(a->solv->pool, a->from_id); + } + SWIGINTERN Dep *Alternative_dep_get(Alternative *a) { + return new_Dep(a->solv->pool, a->dep_id); + } + %} + + Queue choices_raw() { + Queue r; + queue_init_clone(&r, &$self->choices); + return r; + } + + %typemap(out) Queue choices Queue2Array(XSolvable *, 1, new_XSolvable(arg1->solv->pool, id)); + Queue choices() { + int i; + Queue r; + queue_init_clone(&r, &$self->choices); + for (i = 0; i < r.count; i++) + if (r.elements[i] < 0) + r.elements[i] = -r.elements[i]; + return r; + } + +#if defined(SWIGPERL) || defined(SWIGTCL) + %rename("str") __str__; +#endif + const char *__str__() { + return solver_alternative2str($self->solv, $self->type, $self->type == SOLVER_ALTERNATIVE_TYPE_RULE ? $self->rid : $self->dep_id, $self->from_id); + } +} + +#if defined(SWIGTCL) +%init %{ + Tcl_Eval(interp, +"proc solv::iter {varname iter body} {\n"\ +" while 1 {\n"\ +" set value [$iter __next__]\n"\ +" if {$value eq \"NULL\"} { break }\n"\ +" uplevel [list set $varname $value]\n"\ +" set code [catch {uplevel $body} result]\n"\ +" switch -exact -- $code {\n"\ +" 0 {}\n"\ +" 3 { return }\n"\ +" 4 {}\n"\ +" default { return -code $code $result }\n"\ +" }\n"\ +" }\n"\ +"}\n" + ); +%} +#endif + diff --git a/bindings/tcl/CMakeLists.txt b/bindings/tcl/CMakeLists.txt new file mode 100644 index 0000000..f78de9f --- /dev/null +++ b/bindings/tcl/CMakeLists.txt @@ -0,0 +1,38 @@ +FIND_PACKAGE (TCL) + +SET (SWIG_TCL_FLAGS -namespace -pkgversion ${VERSION}) + +EXECUTE_PROCESS ( + COMMAND echo "puts -nonewline [lindex [::tcl::tm::list] end]" + COMMAND ${TCL_TCLSH} + OUTPUT_VARIABLE TCL_INSTALL_DIR +) + +MESSAGE (STATUS "Tclsh executable: ${TCL_TCLSH}") +MESSAGE (STATUS "Tcl installation dir: ${TCL_INSTALL_DIR}") + +ADD_CUSTOM_COMMAND ( + OUTPUT solv_tcl.c + COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -tcl ${SWIG_TCL_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_tcl.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 (${TCL_INCLUDE_PATH}) + +ADD_LIBRARY (bindings_tcl SHARED solv_tcl.c) +SET_TARGET_PROPERTIES (bindings_tcl PROPERTIES PREFIX "" OUTPUT_NAME "solv-${VERSION}" INSTALL_NAME_DIR "${TCL_INSTALL_DIR}") +TARGET_LINK_LIBRARIES (bindings_tcl libsolvext libsolv ${TCL_LIBRARY} ${SYSTEM_LIBRARIES}) +INSTALL (TARGETS bindings_tcl LIBRARY DESTINATION ${TCL_INSTALL_DIR}) + +ADD_CUSTOM_COMMAND ( + OUTPUT solv.tm + COMMAND sed -e "s/__VERSION__/${VERSION}/" ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in >${CMAKE_CURRENT_BINARY_DIR}/solv.tm + DEPENDS ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in + COMMENT "Creating Tcl module to load libsolv" +) +ADD_CUSTOM_TARGET (solv_tm ALL DEPENDS solv.tm) +SET_SOURCE_FILES_PROPERTIES (solv.tm PROPERTIES GENERATED TRUE) + +INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.tm DESTINATION ${TCL_INSTALL_DIR} RENAME solv-${VERSION}.tm) diff --git a/bindings/tcl/solv.tm.in b/bindings/tcl/solv.tm.in new file mode 100644 index 0000000..3b94771 --- /dev/null +++ b/bindings/tcl/solv.tm.in @@ -0,0 +1,4 @@ +package require Tcl + +#package provide solv __VERSION__ +load [::file join [::file dirname [::info script]] "solv-__VERSION__[::info sharedlibextension]"] diff --git a/cmake/modules/FindCheck.cmake b/cmake/modules/FindCheck.cmake new file mode 100644 index 0000000..8ed3739 --- /dev/null +++ b/cmake/modules/FindCheck.cmake @@ -0,0 +1,27 @@ + +IF (CHECK_INCLUDE_DIR) + # Already in cache, be silent + SET(CHECK_FIND_QUIETLY TRUE) +ENDIF (CHECK_INCLUDE_DIR) + +FIND_PATH(CHECK_INCLUDE_DIR NAMES check.h) + +# Look for the library. +FIND_LIBRARY(CHECK_LIBRARY NAMES check) + +IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4) + # handle the QUIETLY and REQUIRED arguments and set CHECK_FOUND to TRUE if + # all listed variables are TRUE + INCLUDE(FindPackageHandleStandardArgs) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Check "Please install 'check' and 'check-devel' packages" CHECK_LIBRARY CHECK_INCLUDE_DIR) +ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4) + +IF(CHECK_FOUND) + SET( CHECK_LIBRARIES ${CHECK_LIBRARY} ) +ELSE(CHECK_FOUND) + SET( CHECK_LIBRARIES ) +ENDIF(CHECK_FOUND) + +MARK_AS_ADVANCED(CHECK_INCLUDE_DIR) +MARK_AS_ADVANCED(CHECK_LIBRARY) diff --git a/cmake/modules/FindEXPAT.cmake b/cmake/modules/FindEXPAT.cmake new file mode 100644 index 0000000..d48eef3 --- /dev/null +++ b/cmake/modules/FindEXPAT.cmake @@ -0,0 +1,38 @@ +# - Find expat +# Find the native EXPAT headers and libraries. +# +# EXPAT_INCLUDE_DIRS - where to find expat.h, etc. +# EXPAT_LIBRARIES - List of libraries when using expat. +# EXPAT_FOUND - True if expat found. + +# Look for the header file. +FIND_PATH(EXPAT_INCLUDE_DIR NAMES expat.h) +MARK_AS_ADVANCED(EXPAT_INCLUDE_DIR) + +# Look for the library. +FIND_LIBRARY(EXPAT_LIBRARY NAMES expat) +MARK_AS_ADVANCED(EXPAT_LIBRARY) + +# Copy the results to the output variables. +IF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY) + SET(EXPAT_FOUND 1) + SET(EXPAT_LIBRARIES ${EXPAT_LIBRARY}) + SET(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR}) +ELSE(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY) + SET(EXPAT_FOUND 0) + SET(EXPAT_LIBRARIES) + SET(EXPAT_INCLUDE_DIRS) +ENDIF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY) + +# Report the results. +IF(NOT EXPAT_FOUND) + SET(EXPAT_DIR_MESSAGE + "EXPAT was not found. Make sure EXPAT_LIBRARY and EXPAT_INCLUDE_DIR are set.") + IF(NOT EXPAT_FIND_QUIETLY) + MESSAGE(STATUS "${EXPAT_DIR_MESSAGE}") + ELSE(NOT EXPAT_FIND_QUIETLY) + IF(EXPAT_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "${EXPAT_DIR_MESSAGE}") + ENDIF(EXPAT_FIND_REQUIRED) + ENDIF(NOT EXPAT_FIND_QUIETLY) +ENDIF(NOT EXPAT_FOUND) diff --git a/cmake/modules/FindLZMA.cmake b/cmake/modules/FindLZMA.cmake new file mode 100644 index 0000000..eb112df --- /dev/null +++ b/cmake/modules/FindLZMA.cmake @@ -0,0 +1,25 @@ +# - Find lzma +# Find the native LZMA headers and library +# +# LZMA_INCLUDE_DIR - where to find lzma.h, etc. +# LZMA_LIBRARIES - List of libraries when using liblzma. +# LZMA_FOUND - True if liblzma found. + +IF (LZMA_INCLUDE_DIR) + # Already in cache, be silent + SET(LZMA_FIND_QUIETLY TRUE) +ENDIF (LZMA_INCLUDE_DIR) + +FIND_PATH(LZMA_INCLUDE_DIR lzma.h) +FIND_LIBRARY(LZMA_LIBRARY NAMES lzma liblzma) + +# handle the QUIETLY and REQUIRED arguments and set LZMA_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMA DEFAULT_MSG LZMA_LIBRARY LZMA_INCLUDE_DIR) + +IF(LZMA_FOUND) + SET( LZMA_LIBRARIES ${LZMA_LIBRARY} ) +ELSE(LZMA_FOUND) + SET( LZMA_LIBRARIES ) +ENDIF(LZMA_FOUND) diff --git a/cmake/modules/FindLibSolv.cmake b/cmake/modules/FindLibSolv.cmake new file mode 100644 index 0000000..166e79d --- /dev/null +++ b/cmake/modules/FindLibSolv.cmake @@ -0,0 +1,95 @@ +# FindLibSolv - Find libsolv headers and libraries. +# +# Sample: +# +# SET( LibSolv_USE_STATIC_LIBS OFF ) +# FIND_PACKAGE( LibSolv REQUIRED ext ) +# IF( LibSolv_FOUND ) +# INCLUDE_DIRECTORIES( ${LibSolv_INCLUDE_DIRS} ) +# TARGET_LINK_LIBRARIES( ... ${LibSolv_LIBRARIES} ) +# ENDIF() +# +# Variables used by this module need to be set before calling find_package +# (not that they are cmale cased like the modiulemane itself): +# +# LibSolv_USE_STATIC_LIBS Can be set to ON to force the use of the static +# libsolv libraries. Defaults to OFF. +# +# Supported components: +# +# ext Also include libsolvext +# +# Variables provided by this module: +# +# LibSolv_FOUND Include dir, libsolv and all extra libraries +# specified in the COMPONENTS list were found. +# +# LibSolv_LIBRARIES Link to these to use all the libraries you specified. +# +# LibSolv_INCLUDE_DIRS Include directories. +# +# For each component you specify in find_package(), the following (UPPER-CASE) +# variables are set to pick and choose components instead of just using LibSolv_LIBRARIES: +# +# LIBSOLV_FOUND TRUE if libsolv was found +# LIBSOLV_LIBRARY libsolv libraries +# +# LIBSOLV_${COMPONENT}_FOUND TRUE if the library component was found +# LIBSOLV_${COMPONENT}_LIBRARY The libraries for the specified component +# + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES +IF(LibSolv_USE_STATIC_LIBS) + SET( _ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ) +ENDIF() + +# Look for the header files +UNSET(LibSolv_INCLUDE_DIRS CACHE) +FIND_PATH(LibSolv_INCLUDE_DIRS NAMES solv/solvable.h) + +# Look for the core library +UNSET(LIBSOLV_LIBRARY CACHE) +FIND_LIBRARY(LIBSOLV_LIBRARY NAMES solv) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv DEFAULT_MSG LIBSOLV_LIBRARY LibSolv_INCLUDE_DIRS) +MARK_AS_ADVANCED( + LIBSOLV_FOUND + LIBSOLV_LIBRARY +) + +# Prepare return values and collectiong more components +SET(LibSolv_FOUND ${LIBSOLV_FOUND}) +SET(LibSolv_LIBRARIES ${LIBSOLV_LIBRARY}) +MARK_AS_ADVANCED( + LibSolv_FOUND + LibSolv_LIBRARIES + LibSolv_INCLUDE_DIRS +) + +# Look for components +FOREACH(COMPONENT ${LibSolv_FIND_COMPONENTS}) + STRING(TOUPPER ${COMPONENT} _UPPERCOMPONENT) + UNSET(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY CACHE) + FIND_LIBRARY(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY NAMES solv${COMPONENT}) + SET(LibSolv_${COMPONENT}_FIND_REQUIRED ${LibSolv_FIND_REQUIRED}) + SET(LibSolv_${COMPONENT}_FIND_QUIETLY ${LibSolv_FIND_QUIETLY}) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv_${COMPONENT} DEFAULT_MSG LIBSOLV_${_UPPERCOMPONENT}_LIBRARY) + MARK_AS_ADVANCED( + LIBSOLV_${_UPPERCOMPONENT}_FOUND + LIBSOLV_${_UPPERCOMPONENT}_LIBRARY + ) + IF(LIBSOLV_${_UPPERCOMPONENT}_FOUND) + SET(LibSolv_LIBRARIES ${LibSolv_LIBRARIES} ${LIBSOLV_${_UPPERCOMPONENT}_LIBRARY}) + ELSE() + SET(LibSolv_FOUND FALSE) + ENDIF() +ENDFOREACH() + +# restore CMAKE_FIND_LIBRARY_SUFFIXES +IF(Solv_USE_STATIC_LIBS) + SET(CMAKE_FIND_LIBRARY_SUFFIXES ${_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES} ) +ENDIF() + +IF(LibSolv_FOUND AND NOT LibSolv_FIND_QUIETLY) + MESSAGE(STATUS "Found LibSolv: ${LibSolv_INCLUDE_DIRS} ${LibSolv_LIBRARIES}") +ENDIF() diff --git a/cmake/modules/FindPackageHandleStandardArgs.cmake b/cmake/modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 0000000..2fa8fbc --- /dev/null +++ b/cmake/modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,316 @@ +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to FIND_PACKAGE(). +# It also sets the _FOUND variable. +# The package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both modes is +# the name of the Find-module where it is called (in original casing). +# +# The first simple mode looks like this: +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( (DEFAULT_MSG|"Custom failure message") ... ) +# If the variables to are all valid, then _FOUND +# will be set to TRUE. +# If DEFAULT_MSG is given as second argument, then the function will generate +# itself useful success and error messages. You can also supply a custom error message +# for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# As above, if through are all valid, _FOUND +# will be set to TRUE. +# After REQUIRED_VARS the variables which are required for this package are listed. +# Following VERSION_VAR the name of the variable can be specified which holds +# the version of the package which has been found. If this is done, this version +# will be checked against the (potentially) specified required version used +# in the find_package() call. The EXACT keyword is also handled. The default +# messages include information about the required version and the version +# which has been actually found, both if the version is ok or not. +# If the package supports components, use the HANDLE_COMPONENTS option to enable +# handling them. In this case, find_package_handle_standard_args() will report +# which components have been found and which are missing, and the _FOUND +# variable will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. +# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for +# a find_package(... NO_MODULE) call. In this case VERSION_VAR will be set +# to _VERSION and the macro will automatically check whether the +# Config module was found. +# Via FAIL_MESSAGE a custom failure message can be specified, if this is not +# used, the default message will be displayed. +# +# Example for mode 1: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE. +# If it is not found and REQUIRED was used, it fails with FATAL_ERROR, +# independent whether QUIET was used or not. +# If it is found, success will be reported, including the content of . +# On repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON REQUIRED_VARS BISON_EXECUTABLE +# VERSION_VAR BISON_VERSION) +# In this case, BISON is considered to be found if the variable(s) listed +# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case. +# Also the version of BISON will be checked by using the version contained +# in BISON_VERSION. +# Since no FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# FIND_PACKAGE(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4 CONFIG_MODE) +# In this case, FindAutmoc4.cmake wraps a call to FIND_PACKAGE(Automoc4 NO_MODULE) +# and adds an additional search directory for automoc4. +# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +INCLUDE(FindPackageMessage) +INCLUDE(_CMakeParseArguments) + +# internal helper macro +MACRO(_FPHSA_FAILURE_MESSAGE _msg) + IF (${_NAME}_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "${_msg}") + ELSE (${_NAME}_FIND_REQUIRED) + IF (NOT ${_NAME}_FIND_QUIETLY) + MESSAGE(STATUS "${_msg}") + ENDIF (NOT ${_NAME}_FIND_QUIETLY) + ENDIF (${_NAME}_FIND_REQUIRED) +ENDMACRO(_FPHSA_FAILURE_MESSAGE _msg) + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +MACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + IF(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + ELSE(${_NAME}_CONFIG) + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + IF(${_NAME}_CONSIDERED_CONFIGS) + SET(configsText "") + LIST(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + MATH(EXPR configsCount "${configsCount} - 1") + FOREACH(currentConfigIndex RANGE ${configsCount}) + LIST(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + LIST(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + SET(configsText "${configsText} ${filename} (version ${version})\n") + ENDFOREACH(currentConfigIndex) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + ELSE(${_NAME}_CONSIDERED_CONFIGS) + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + ENDIF(${_NAME}_CONSIDERED_CONFIGS) + ENDIF(${_NAME}_CONFIG) +ENDMACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + + +FUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + SET(options CONFIG_MODE HANDLE_COMPONENTS) + SET(oneValueArgs FAIL_MESSAGE VERSION_VAR) + SET(multiValueArgs REQUIRED_VARS) + SET(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + LIST(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + IF(${INDEX} EQUAL -1) + SET(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + SET(FPHSA_REQUIRED_VARS ${ARGN}) + SET(FPHSA_VERSION_VAR) + ELSE(${INDEX} EQUAL -1) + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + IF(FPHSA_UNPARSED_ARGUMENTS) + MESSAGE(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + ENDIF(FPHSA_UNPARSED_ARGUMENTS) + + IF(NOT FPHSA_FAIL_MESSAGE) + SET(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + ENDIF(NOT FPHSA_FAIL_MESSAGE) + ENDIF(${INDEX} EQUAL -1) + +# now that we collected all arguments, process them + + IF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG") + SET(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + ENDIF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG") + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + IF(FPHSA_CONFIG_MODE) + LIST(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + LIST(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + SET(FPHSA_VERSION_VAR ${_NAME}_VERSION) + ENDIF(FPHSA_CONFIG_MODE) + + IF(NOT FPHSA_REQUIRED_VARS) + MESSAGE(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + ENDIF(NOT FPHSA_REQUIRED_VARS) + + LIST(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + STRING(TOUPPER ${_NAME} _NAME_UPPER) + STRING(TOLOWER ${_NAME} _NAME_LOWER) + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + SET(MISSING_VARS "") + SET(DETAILS "") + SET(${_NAME_UPPER}_FOUND TRUE) + # check if all passed variables are valid + FOREACH(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + IF(NOT ${_CURRENT_VAR}) + SET(${_NAME_UPPER}_FOUND FALSE) + SET(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + ELSE(NOT ${_CURRENT_VAR}) + SET(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + ENDIF(NOT ${_CURRENT_VAR}) + ENDFOREACH(_CURRENT_VAR) + + # component handling + SET(FOUND_COMPONENTS_MSG "") + SET(MISSING_COMPONENTS_MSG "") + + IF(FPHSA_HANDLE_COMPONENTS) + FOREACH(comp ${${_NAME}_FIND_COMPONENTS}) + IF(${_NAME}_${comp}_FOUND) + + IF(NOT FOUND_COMPONENTS_MSG) + SET(FOUND_COMPONENTS_MSG "found components: ") + ENDIF() + SET(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + ELSE() + + IF(NOT MISSING_COMPONENTS_MSG) + SET(MISSING_COMPONENTS_MSG "missing components: ") + ENDIF() + SET(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + IF(${_NAME}_FIND_REQUIRED_${comp}) + SET(${_NAME_UPPER}_FOUND FALSE) + SET(MISSING_VARS "${MISSING_VARS} ${comp}") + ENDIF() + + ENDIF() + ENDFOREACH(comp) + SET(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + SET(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + ENDIF(FPHSA_HANDLE_COMPONENTS) + + # version handling: + SET(VERSION_MSG "") + SET(VERSION_OK TRUE) + SET(VERSION ${${FPHSA_VERSION_VAR}} ) + IF (${_NAME}_FIND_VERSION) + + IF(VERSION) + + IF(${_NAME}_FIND_VERSION_EXACT) # exact version required + IF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + SET(VERSION_OK FALSE) + ELSE (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + SET(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + ENDIF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + + ELSE(${_NAME}_FIND_VERSION_EXACT) # minimum version specified: + IF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + SET(VERSION_OK FALSE) + ELSE ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + SET(VERSION_MSG "(found suitable version \"${VERSION}\", required is \"${${_NAME}_FIND_VERSION}\")") + ENDIF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + ENDIF(${_NAME}_FIND_VERSION_EXACT) + + ELSE(VERSION) + + # if the package was not found, but a version was given, add that to the output: + IF(${_NAME}_FIND_VERSION_EXACT) + SET(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + ELSE(${_NAME}_FIND_VERSION_EXACT) + SET(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + ENDIF(${_NAME}_FIND_VERSION_EXACT) + + ENDIF(VERSION) + ELSE (${_NAME}_FIND_VERSION) + IF(VERSION) + SET(VERSION_MSG "(found version \"${VERSION}\")") + ENDIF(VERSION) + ENDIF (${_NAME}_FIND_VERSION) + + IF(VERSION_OK) + SET(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + ELSE(VERSION_OK) + SET(${_NAME_UPPER}_FOUND FALSE) + ENDIF(VERSION_OK) + + + # print the result: + IF (${_NAME_UPPER}_FOUND) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + ELSE (${_NAME_UPPER}_FOUND) + + IF(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + ELSE(FPHSA_CONFIG_MODE) + IF(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + ELSE(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + ENDIF(NOT VERSION_OK) + ENDIF(FPHSA_CONFIG_MODE) + + ENDIF (${_NAME_UPPER}_FOUND) + + SET(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE) + +ENDFUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _FIRST_ARG) diff --git a/cmake/modules/FindRuby.cmake b/cmake/modules/FindRuby.cmake new file mode 100644 index 0000000..827a7a6 --- /dev/null +++ b/cmake/modules/FindRuby.cmake @@ -0,0 +1,262 @@ +# - Find Ruby +# This module finds if Ruby is installed and determines where the include files +# and libraries are. Ruby 1.8 and 1.9 are supported. +# +# The minimum required version of Ruby can be specified using the +# standard syntax, e.g. FIND_PACKAGE(Ruby 1.8) +# +# It also determines what the name of the library is. This +# code sets the following variables: +# +# RUBY_EXECUTABLE = full path to the ruby binary +# RUBY_INCLUDE_DIRS = include dirs to be used when using the ruby library +# RUBY_LIBRARY = full path to the ruby library +# RUBY_VERSION = the version of ruby which was found, e.g. "1.8.7" +# RUBY_FOUND = set to true if ruby ws found successfully +# +# RUBY_INCLUDE_PATH = same as RUBY_INCLUDE_DIRS, only provided for compatibility reasons, don't use it + +#============================================================================= +# Copyright 2004-2009 Kitware, Inc. +# Copyright 2008-2009 Alexander Neundorf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +# RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'` +# RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'` +# RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'` +# RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'` +# RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'` + +# uncomment the following line to get debug output for this file +# SET(_RUBY_DEBUG_OUTPUT TRUE) + +# Determine the list of possible names of the ruby executable depending +# on which version of ruby is required +SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ruby) + +# if 1.9 is required, don't look for ruby18 and ruby1.8, default to version 1.8 +IF(Ruby_FIND_VERSION_MAJOR AND Ruby_FIND_VERSION_MINOR) + SET(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${RUBY_FIND_VERSION_MINOR}") +ELSE(Ruby_FIND_VERSION_MAJOR AND Ruby_FIND_VERSION_MINOR) + SET(Ruby_FIND_VERSION_SHORT_NODOT "18") +ENDIF(Ruby_FIND_VERSION_MAJOR AND Ruby_FIND_VERSION_MINOR) + +SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.9 ruby19) + +# if we want a version below 1.9, also look for ruby 1.8 +IF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19") + SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.8 ruby18) +ENDIF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19") + +FIND_PROGRAM(RUBY_EXECUTABLE NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}) + + +IF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR) + FUNCTION(_RUBY_CONFIG_VAR RBVAR OUTVAR) + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']" + RESULT_VARIABLE _RUBY_SUCCESS + OUTPUT_VARIABLE _RUBY_OUTPUT + ERROR_QUIET) + IF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT) + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']" + RESULT_VARIABLE _RUBY_SUCCESS + OUTPUT_VARIABLE _RUBY_OUTPUT + ERROR_QUIET) + ENDIF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT) + SET(${OUTVAR} "${_RUBY_OUTPUT}" PARENT_SCOPE) + ENDFUNCTION(_RUBY_CONFIG_VAR) + + + # query the ruby version + _RUBY_CONFIG_VAR("MAJOR" RUBY_VERSION_MAJOR) + _RUBY_CONFIG_VAR("MINOR" RUBY_VERSION_MINOR) + _RUBY_CONFIG_VAR("TEENY" RUBY_VERSION_PATCH) + + # query the different directories + _RUBY_CONFIG_VAR("archdir" RUBY_ARCH_DIR) + _RUBY_CONFIG_VAR("arch" RUBY_ARCH) + _RUBY_CONFIG_VAR("rubyhdrdir" RUBY_HDR_DIR) + _RUBY_CONFIG_VAR("libdir" RUBY_POSSIBLE_LIB_DIR) + _RUBY_CONFIG_VAR("rubylibdir" RUBY_RUBY_LIB_DIR) + + # site_ruby + _RUBY_CONFIG_VAR("sitearchdir" RUBY_SITEARCH_DIR) + _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR) + + # vendor_ruby available ? + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print 'true' unless RbConfig::CONFIG['vendorarchdir'].nil?" + OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY ERROR_QUIET) + + IF(RUBY_HAS_VENDOR_RUBY) + _RUBY_CONFIG_VAR("vendorlibdir" RUBY_VENDORLIB_DIR) + _RUBY_CONFIG_VAR("vendorarchdir" RUBY_VENDORARCH_DIR) + ENDIF(RUBY_HAS_VENDOR_RUBY) + + # save the results in the cache so we don't have to run ruby the next time again + SET(RUBY_VERSION_MAJOR ${RUBY_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE) + SET(RUBY_VERSION_MINOR ${RUBY_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE) + SET(RUBY_VERSION_PATCH ${RUBY_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE) + SET(RUBY_ARCH_DIR ${RUBY_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE) + SET(RUBY_HDR_DIR ${RUBY_HDR_DIR} CACHE PATH "The Ruby header dir (1.9)" FORCE) + SET(RUBY_POSSIBLE_LIB_DIR ${RUBY_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE) + SET(RUBY_RUBY_LIB_DIR ${RUBY_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE) + SET(RUBY_SITEARCH_DIR ${RUBY_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE) + SET(RUBY_SITELIB_DIR ${RUBY_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE) + SET(RUBY_HAS_VENDOR_RUBY ${RUBY_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE) + SET(RUBY_VENDORARCH_DIR ${RUBY_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE) + SET(RUBY_VENDORLIB_DIR ${RUBY_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE) + + MARK_AS_ADVANCED( + RUBY_ARCH_DIR + RUBY_ARCH + RUBY_HDR_DIR + RUBY_POSSIBLE_LIB_DIR + RUBY_RUBY_LIB_DIR + RUBY_SITEARCH_DIR + RUBY_SITELIB_DIR + RUBY_HAS_VENDOR_RUBY + RUBY_VENDORARCH_DIR + RUBY_VENDORLIB_DIR + RUBY_VERSION_MAJOR + RUBY_VERSION_MINOR + RUBY_VERSION_PATCH + ) +ENDIF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR) + +# In case RUBY_EXECUTABLE could not be executed (e.g. cross compiling) +# try to detect which version we found. This is not too good. +IF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR) + # by default assume 1.8.0 + SET(RUBY_VERSION_MAJOR 1) + SET(RUBY_VERSION_MINOR 8) + SET(RUBY_VERSION_PATCH 0) + # check whether we found 1.9.x + IF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9" OR RUBY_HDR_DIR) + SET(RUBY_VERSION_MAJOR 1) + SET(RUBY_VERSION_MINOR 9) + ENDIF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9" OR RUBY_HDR_DIR) +ENDIF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR) + +IF(RUBY_VERSION_MAJOR) + SET(RUBY_VERSION "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}") + SET(_RUBY_VERSION_SHORT "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}") + SET(_RUBY_VERSION_SHORT_NODOT "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}") + SET(_RUBY_NODOT_VERSION "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}") +ENDIF(RUBY_VERSION_MAJOR) + +FIND_PATH(RUBY_INCLUDE_DIR + NAMES ruby.h + HINTS + ${RUBY_HDR_DIR} + ${RUBY_ARCH_DIR} + /usr/lib/ruby/${_RUBY_VERSION_SHORT}/i586-linux-gnu/ ) + +SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIR} ) + +# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir +IF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18 OR "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18 OR RUBY_HDR_DIR) + FIND_PATH(RUBY_CONFIG_INCLUDE_DIR + NAMES ruby/config.h config.h + HINTS + ${RUBY_HDR_DIR}/${RUBY_ARCH} + ${RUBY_ARCH_DIR} + ) + + SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIRS} ${RUBY_CONFIG_INCLUDE_DIR} ) +ENDIF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18 OR "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18 OR RUBY_HDR_DIR) + + +# Determine the list of possible names for the ruby library +SET(_RUBY_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_RUBY_VERSION_SHORT} ruby${_RUBY_VERSION_SHORT_NODOT} ruby-${_RUBY_VERSION_SHORT} ruby-${RUBY_VERSION}) + +IF(WIN32) + SET( _RUBY_MSVC_RUNTIME "" ) + IF( MSVC60 ) + SET( _RUBY_MSVC_RUNTIME "60" ) + ENDIF( MSVC60 ) + IF( MSVC70 ) + SET( _RUBY_MSVC_RUNTIME "70" ) + ENDIF( MSVC70 ) + IF( MSVC71 ) + SET( _RUBY_MSVC_RUNTIME "71" ) + ENDIF( MSVC71 ) + IF( MSVC80 ) + SET( _RUBY_MSVC_RUNTIME "80" ) + ENDIF( MSVC80 ) + IF( MSVC90 ) + SET( _RUBY_MSVC_RUNTIME "90" ) + ENDIF( MSVC90 ) + + LIST(APPEND _RUBY_POSSIBLE_LIB_NAMES + "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}" + "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}-static" + "msvcrt-ruby${_RUBY_NODOT_VERSION}" + "msvcrt-ruby${_RUBY_NODOT_VERSION}-static" ) +ENDIF(WIN32) + +FIND_LIBRARY(RUBY_LIBRARY NAMES ${_RUBY_POSSIBLE_LIB_NAMES} HINTS ${RUBY_POSSIBLE_LIB_DIR} ) + +INCLUDE(FindPackageHandleStandardArgs) +SET(_RUBY_REQUIRED_VARS RUBY_EXECUTABLE RUBY_INCLUDE_DIR RUBY_LIBRARY) +IF(_RUBY_VERSION_SHORT_NODOT GREATER 18) + LIST(APPEND _RUBY_REQUIRED_VARS RUBY_CONFIG_INCLUDE_DIR) +ENDIF(_RUBY_VERSION_SHORT_NODOT GREATER 18) + +IF(_RUBY_DEBUG_OUTPUT) + MESSAGE(STATUS "--------FindRuby.cmake debug------------") + MESSAGE(STATUS "_RUBY_POSSIBLE_EXECUTABLE_NAMES: ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}") + MESSAGE(STATUS "_RUBY_POSSIBLE_LIB_NAMES: ${_RUBY_POSSIBLE_LIB_NAMES}") + MESSAGE(STATUS "RUBY_ARCH_DIR: ${RUBY_ARCH_DIR}") + MESSAGE(STATUS "RUBY_HDR_DIR: ${RUBY_HDR_DIR}") + MESSAGE(STATUS "RUBY_POSSIBLE_LIB_DIR: ${RUBY_POSSIBLE_LIB_DIR}") + MESSAGE(STATUS "Found RUBY_VERSION: \"${RUBY_VERSION}\" , short: \"${_RUBY_VERSION_SHORT}\", nodot: \"${_RUBY_VERSION_SHORT_NODOT}\"") + MESSAGE(STATUS "_RUBY_REQUIRED_VARS: ${_RUBY_REQUIRED_VARS}") + MESSAGE(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}") + MESSAGE(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}") + MESSAGE(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}") + MESSAGE(STATUS "RUBY_CONFIG_INCLUDE_DIR: ${RUBY_CONFIG_INCLUDE_DIR}") + MESSAGE(STATUS "--------------------") +ENDIF(_RUBY_DEBUG_OUTPUT) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby REQUIRED_VARS ${_RUBY_REQUIRED_VARS} + VERSION_VAR RUBY_VERSION ) + +MARK_AS_ADVANCED( + RUBY_EXECUTABLE + RUBY_LIBRARY + RUBY_INCLUDE_DIR + RUBY_CONFIG_INCLUDE_DIR + ) + +# Set some variables for compatibility with previous version of this file +SET(RUBY_POSSIBLE_LIB_PATH ${RUBY_POSSIBLE_LIB_DIR}) +SET(RUBY_RUBY_LIB_PATH ${RUBY_RUBY_LIB_DIR}) +SET(RUBY_INCLUDE_PATH ${RUBY_INCLUDE_DIRS}) diff --git a/cmake/modules/_CMakeParseArguments.cmake b/cmake/modules/_CMakeParseArguments.cmake new file mode 100644 index 0000000..7122094 --- /dev/null +++ b/cmake/modules/_CMakeParseArguments.cmake @@ -0,0 +1,160 @@ +# CMAKE_PARSE_ARGUMENTS( args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for +# parsing the arguments given to that macro or function. +# It processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any value +# following, like e.g. the OPTIONAL keyword of the install() command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this macro +# which can be followed by more than one value, like e.g. the TARGETS or +# FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. +# These variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether +# your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments as the +# real install() command: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) +# ... +# +# Assume my_install() has been called like this: +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# After the cmake_parse_arguments() call the macro will have set the following +# variables: +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# You can the continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a one_value_keyword +# another recognized keyword follows, this is interpreted as the beginning of +# the new option. +# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would +# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach(arg_name) + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach(option) + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else(insideValues) + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif(insideValues) + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach(currentArg) + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach(arg_name) + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000..ed38274 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,55 @@ + +SET (libsolv_MANPAGES3 + libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 + libsolv-pool.3) + +SET (libsolv_MANPAGES1 + mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 repo2solv.1 solv.1) + +IF (ENABLE_RPMDB) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} rpmdb2solv.1 rpms2solv.1) +ENDIF (ENABLE_RPMDB) + +IF (ENABLE_RPMMD) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} repomdxml2solv.1 rpmmd2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1) +ENDIF (ENABLE_RPMMD) + +IF (ENABLE_HELIXREPO) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} helix2solv.1) +ENDIF (ENABLE_HELIXREPO) + +IF (ENABLE_SUSEREPO) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} susetags2solv.1) +ENDIF (ENABLE_SUSEREPO) + +IF (ENABLE_COMPS) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} comps2solv.1) +ENDIF (ENABLE_COMPS) + +IF (ENABLE_DEBIAN) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} deb2solv.1) +ENDIF (ENABLE_DEBIAN) + +IF (ENABLE_MDKREPO) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} mdk2solv.1) +ENDIF (ENABLE_MDKREPO) + +IF (ENABLE_ARCHREPO) +SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} archpkgs2solv.1 archrepo2solv.1) +ENDIF (ENABLE_ARCHREPO) + +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 "${CMAKE_INSTALL_MANDIR}/man3") + +INSTALL(FILES + ${libsolv_MANPAGES1} + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") diff --git a/doc/Makefile.gen b/doc/Makefile.gen new file mode 100644 index 0000000..e9f1b69 --- /dev/null +++ b/doc/Makefile.gen @@ -0,0 +1,24 @@ + +VPATH = gen + +man: man3 man1 + +man3: libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libsolv-pool.3 + +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 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 -D gen $< + +.txt.3: + a2x -f manpage -D gen $< + +.txt.html: + a2x -f xhtml -D gen $< diff --git a/doc/appdata2solv.txt b/doc/appdata2solv.txt new file mode 100644 index 0000000..c31311a --- /dev/null +++ b/doc/appdata2solv.txt @@ -0,0 +1,43 @@ +appdata2solv(1) +=============== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +appdata2solv - convert application meta data into a solv file + +Synopsis +-------- +*appdata2solv* ['OPTIONS'] + +Description +----------- +The appdata format contains metadata about application. It can +be available both in repositories (for available applications) +and in the installed system (for installed applications). +The appdata2solv tool reads the metadata from stdin and +writes the parsed data as solv file to standard output. The +parser will create *application:* pseudo packages for each entry. + +*-d* 'APPDATADIR':: +Do not read from standard input, instead scan the specified +directory for appdata entries. 'APPDATADIR' is normally +set to */usr/share/appdata*. + +*-r* 'ROOTDIR':: +Use 'ROOTDIR' as root directory. + + +See Also +-------- +mergesolv(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/archpkgs2solv.txt b/doc/archpkgs2solv.txt new file mode 100644 index 0000000..4ce3155 --- /dev/null +++ b/doc/archpkgs2solv.txt @@ -0,0 +1,39 @@ +archpkgs2solv(1) +================ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +archpkgs2solv - convert one or more Arch package files into a solv file + +Synopsis +-------- +*archpkgs2solv* ['OPTIONS'] 'PKG1.pkg.xz' ... + +Description +----------- +The archpkgs2solv tool converts the meta data from one or more +Arch Linux packages into the solv file written to standard output. + +*-m* 'MANIFESTFILE':: +Read the rpm file names from the specified 'MANIFESTFILE'. You can +use *-* to read the manifest from standard input. + +*-0*:: +Use a null byte as line terminator for manifest files instead of +a newline. This is useful if the file names can contain newlines. +See also the *-print0* option in *find*. + +See Also +-------- +pacman(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/archrepo2solv.txt b/doc/archrepo2solv.txt new file mode 100644 index 0000000..1a7791c --- /dev/null +++ b/doc/archrepo2solv.txt @@ -0,0 +1,35 @@ +archrepo2solv(1) +================ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +archrepo2solv - convert files in Arch repository format into a solv file + +Synopsis +-------- +*archrepo2solv* ['OPTIONS'] + +Description +----------- +The archrepo2solv tool reads Arch Linux repository data (*core.db*) from stdin, +and writes it as solv file to standard output. + +*-l* 'DATABASEDIR':: +Instead of reading from standard input, scan the specified directory for +package meta files. Set 'DATABASEDIR' to */var/lib/pacman/local* to +scan the installed packages. + +See Also +-------- +pacman(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/comps2solv.txt b/doc/comps2solv.txt new file mode 100644 index 0000000..8d98708 --- /dev/null +++ b/doc/comps2solv.txt @@ -0,0 +1,33 @@ +comps2solv(1) +============= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +comps2solv - convert rpm-md comps.xml file into a solv file + +Synopsis +-------- +*comps2solv* ['OPTIONS'] + +Description +----------- +The comps.xml file is Fedora's way to implement package groups. +The comps2solv tool reads the comps xml file from stdin and +writes the parsed data as solv file to standard output. The +parser will create *group:* and *category:* pseudo packages +for each comps entry. + +See Also +-------- +mergesolv(1), createrepo(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/deb2solv.txt b/doc/deb2solv.txt new file mode 100644 index 0000000..cb42ff7 --- /dev/null +++ b/doc/deb2solv.txt @@ -0,0 +1,39 @@ +deb2solv(1) +============ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +deb2solv - convert one or more Debian package files into a solv file + +Synopsis +-------- +*deb2solv* ['OPTIONS'] 'PKG1.deb' ... + +Description +----------- +The deb2solv tool converts the meta data from one or more +Debian packages into the solv file written to standard output. + +*-m* 'MANIFESTFILE':: +Read the rpm file names from the specified 'MANIFESTFILE'. You can +use *-* to read the manifest from standard input. + +*-0*:: +Use a null byte as line terminator for manifest files instead of +a newline. This is useful if the file names can contain newlines. +See also the *-print0* option in *find*. + +See Also +-------- +deb(5), dpkg-deb(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/deltainfoxml2solv.txt b/doc/deltainfoxml2solv.txt new file mode 100644 index 0000000..13c987d --- /dev/null +++ b/doc/deltainfoxml2solv.txt @@ -0,0 +1,33 @@ +deltainfoxml2solv(1) +==================== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +deltainfoxml2solv - convert rpm-md's deltainfo format into a solv file + +Synopsis +-------- +*deltainfoxml2solv* ['OPTIONS'] + +Description +----------- +The deltainfoxml2solv tool reads rpm-md's *deltainfo.xml* data from stdin, +and writes it as solv file to standard output. Some distributions name +the input *prestodelta.xml* instead. Each delta rpm element is converted +and added as *repository:deltainfo* element to the meta section of the +solv file. + +See Also +-------- +mergesolv(1), createrepo(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/dumpsolv.txt b/doc/dumpsolv.txt new file mode 100644 index 0000000..b09aa97 --- /dev/null +++ b/doc/dumpsolv.txt @@ -0,0 +1,30 @@ +dumpsolv(1) +=========== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +dumpsolv - print a solv file into a human readable format + +Synopsis +-------- +*dumpsolv* ['OPTIONS'] ['FILE.solv'] + +Description +----------- +The dumpsolv tool reads a solv files and writes its contents +to standard output. If no input file is given, it reads the +solv file from standard input. + +*-j*:: +Write the contents in JSON format. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/filters/xcode.conf b/doc/filters/xcode.conf new file mode 100644 index 0000000..294f908 --- /dev/null +++ b/doc/filters/xcode.conf @@ -0,0 +1,12 @@ +[blockdef-listing] +xcode-style=template="verseblock",presubs=(),postsubs=("callouts",),filter="filters/xcode.pl {basebackend}" + +[paradef-xcode] +delimiter=(?s)^(?P\s+.*) +template=verseblock +subs=verbatim +filter=filters/xcode.pl {basebackend} + +[paradef-literal] +delimiter=(?s)^(?P\s{1,7}\S.*) + diff --git a/doc/filters/xcode.pl b/doc/filters/xcode.pl new file mode 100755 index 0000000..407641f --- /dev/null +++ b/doc/filters/xcode.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +die("I only understand docbook\n") unless @ARGV && $ARGV[0] eq 'docbook'; + +#my $ii = '//'; +#my $io = '//'; + +#my $si = '**'; +#my $so = '**'; + +my $ii = ''; +my $io = ''; + +my $si = ''; +my $so = ''; + +while() { + chomp; + my $in = ''; + my $out = ''; + s/^\s+//; + s/\s+$//; + if (/^(.*)(\s*\/\*.*?\*\/\s*?)$/) { + $out = $2; + $_ = $1; + } + if (/^(my\s+)(.*?)$/) { + $in = $1; + $_ = $2; + } + if (/(?$1<-I>/g; + } else { + s/(?<=[^a-zA-Z_\&:\.\'\";])(?!solv\W|Solv\W|Pool\W)([\$\@a-zA-Z_][a-zA-Z0-9_]*)(?=[^a-zA-Z0-9_\(;\[])(?!::)(?! [^=])/<-S>$1<-I>/g; + } + # fixup for perl bare words + s/{<-S>([a-zA-Z_][a-zA-Z0-9]*)<-I>}/{$1}/g; + # fixup for callbackfunctions + s/\\(&[a-zA-Z_]+)/\\<-S>$1<-I>/; + # fixup for stringification + s/\$<-S>/<-S>\$/g; + # fixup for %d + s/%<-S>d<-I>\"/%d\"/; + s/%<-S>d<-I>\\<-S>n<-I>/%d\\n/; + # iterators + s/^ //; + s/ $//; + s/^(for (?:my )?)(\S+) /$1<-S>$2<-I> /; + } + $_ = "$_<-S>"; + s/(\s*)<-S>/$1/g; + s/<-S>(\s*)/$1/g; + s/(\s*)<-I>/$1/g; + s/<-I>(\s*)/$1/g; + s/(\s+)/$1/g; + s/(\s+)<-S>/<-S>$1/g; + s/(\s+)/$1/g; + s/(\s+)<-I>/<-I>$1/g; + s//$si/g; + s/<-S>/$so/g; + s//$ii/g; + s/<-I>/$io/g; + print "$in$_$out\n"; +} diff --git a/doc/gen/appdata2solv.1 b/doc/gen/appdata2solv.1 new file mode 100644 index 0000000..4fe217d --- /dev/null +++ b/doc/gen/appdata2solv.1 @@ -0,0 +1,58 @@ +'\" t +.\" Title: appdata2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "APPDATA2SOLV" "1" "07/25/2017" "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" +appdata2solv \- convert application meta data into a solv file +.SH "SYNOPSIS" +.sp +\fBappdata2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The appdata format contains metadata about application\&. It can be available both in repositories (for available applications) and in the installed system (for installed applications)\&. The appdata2solv tool reads the metadata from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBapplication:\fR pseudo packages for each entry\&. +.PP +\fB\-d\fR \fIAPPDATADIR\fR +.RS 4 +Do not read from standard input, instead scan the specified directory for appdata entries\&. +\fIAPPDATADIR\fR +is normally set to +\fB/usr/share/appdata\fR\&. +.RE +.PP +\fB\-r\fR \fIROOTDIR\fR +.RS 4 +Use +\fIROOTDIR\fR +as root directory\&. +.RE +.SH "SEE ALSO" +.sp +mergesolv(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/archpkgs2solv.1 b/doc/gen/archpkgs2solv.1 new file mode 100644 index 0000000..bb47364 --- /dev/null +++ b/doc/gen/archpkgs2solv.1 @@ -0,0 +1,59 @@ +'\" t +.\" Title: archpkgs2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "ARCHPKGS2SOLV" "1" "07/25/2017" "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" +archpkgs2solv \- convert one or more Arch package files into a solv file +.SH "SYNOPSIS" +.sp +\fBarchpkgs2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.pkg\&.xz\fR \&... +.SH "DESCRIPTION" +.sp +The archpkgs2solv tool converts the meta data from one or more Arch Linux packages into the solv file written to standard output\&. +.PP +\fB\-m\fR \fIMANIFESTFILE\fR +.RS 4 +Read the rpm file names from the specified +\fIMANIFESTFILE\fR\&. You can use +\fB\-\fR +to read the manifest from standard input\&. +.RE +.PP +\fB\-0\fR +.RS 4 +Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the +\fB\-print0\fR +option in +\fBfind\fR\&. +.RE +.SH "SEE ALSO" +.sp +pacman(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/archrepo2solv.1 b/doc/gen/archrepo2solv.1 new file mode 100644 index 0000000..9d7c868 --- /dev/null +++ b/doc/gen/archrepo2solv.1 @@ -0,0 +1,52 @@ +'\" t +.\" Title: archrepo2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "ARCHREPO2SOLV" "1" "07/25/2017" "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" +archrepo2solv \- convert files in Arch repository format into a solv file +.SH "SYNOPSIS" +.sp +\fBarchrepo2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The archrepo2solv tool reads Arch Linux repository data (\fBcore\&.db\fR) from stdin, and writes it as solv file to standard output\&. +.PP +\fB\-l\fR \fIDATABASEDIR\fR +.RS 4 +Instead of reading from standard input, scan the specified directory for package meta files\&. Set +\fIDATABASEDIR\fR +to +\fB/var/lib/pacman/local\fR +to scan the installed packages\&. +.RE +.SH "SEE ALSO" +.sp +pacman(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/comps2solv.1 b/doc/gen/comps2solv.1 new file mode 100644 index 0000000..2be0bc9 --- /dev/null +++ b/doc/gen/comps2solv.1 @@ -0,0 +1,43 @@ +'\" t +.\" Title: comps2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "COMPS2SOLV" "1" "07/25/2017" "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" +comps2solv \- convert rpm\-md comps\&.xml file into a solv file +.SH "SYNOPSIS" +.sp +\fBcomps2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The comps\&.xml file is Fedora\(cqs way to implement package groups\&. The comps2solv tool reads the comps xml file from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBgroup:\fR and \fBcategory:\fR pseudo packages for each comps entry\&. +.SH "SEE ALSO" +.sp +mergesolv(1), createrepo(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/deb2solv.1 b/doc/gen/deb2solv.1 new file mode 100644 index 0000000..7da3828 --- /dev/null +++ b/doc/gen/deb2solv.1 @@ -0,0 +1,59 @@ +'\" t +.\" Title: deb2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "DEB2SOLV" "1" "07/25/2017" "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" +deb2solv \- convert one or more Debian package files into a solv file +.SH "SYNOPSIS" +.sp +\fBdeb2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.deb\fR \&... +.SH "DESCRIPTION" +.sp +The deb2solv tool converts the meta data from one or more Debian packages into the solv file written to standard output\&. +.PP +\fB\-m\fR \fIMANIFESTFILE\fR +.RS 4 +Read the rpm file names from the specified +\fIMANIFESTFILE\fR\&. You can use +\fB\-\fR +to read the manifest from standard input\&. +.RE +.PP +\fB\-0\fR +.RS 4 +Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the +\fB\-print0\fR +option in +\fBfind\fR\&. +.RE +.SH "SEE ALSO" +.sp +deb(5), dpkg\-deb(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/deltainfoxml2solv.1 b/doc/gen/deltainfoxml2solv.1 new file mode 100644 index 0000000..0ef0bb4 --- /dev/null +++ b/doc/gen/deltainfoxml2solv.1 @@ -0,0 +1,43 @@ +'\" t +.\" Title: deltainfoxml2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "DELTAINFOXML2SOLV" "1" "07/25/2017" "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" +deltainfoxml2solv \- convert rpm\-md\*(Aqs deltainfo format into a solv file +.SH "SYNOPSIS" +.sp +\fBdeltainfoxml2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The deltainfoxml2solv tool reads rpm\-md\(cqs \fBdeltainfo\&.xml\fR data from stdin, and writes it as solv file to standard output\&. Some distributions name the input \fBprestodelta\&.xml\fR instead\&. Each delta rpm element is converted and added as \fBrepository:deltainfo\fR element to the meta section of the solv file\&. +.SH "SEE ALSO" +.sp +mergesolv(1), createrepo(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/dumpsolv.1 b/doc/gen/dumpsolv.1 new file mode 100644 index 0000000..eed45fe --- /dev/null +++ b/doc/gen/dumpsolv.1 @@ -0,0 +1,45 @@ +'\" t +.\" Title: dumpsolv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 07/25/2017 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "DUMPSOLV" "1" "07/25/2017" "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" +dumpsolv \- print a solv file into a human readable format +.SH "SYNOPSIS" +.sp +\fBdumpsolv\fR [\fIOPTIONS\fR] [\fIFILE\&.solv\fR] +.SH "DESCRIPTION" +.sp +The dumpsolv tool reads a solv files and writes its contents to standard output\&. If no input file is given, it reads the solv file from standard input\&. +.PP +\fB\-j\fR +.RS 4 +Write the contents in JSON format\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/helix2solv.1 b/doc/gen/helix2solv.1 new file mode 100644 index 0000000..1f37339 --- /dev/null +++ b/doc/gen/helix2solv.1 @@ -0,0 +1,40 @@ +'\" t +.\" Title: helix2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "HELIX2SOLV" "1" "09/14/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" +helix2solv \- convert legacy helixcode format into a solv file +.SH "SYNOPSIS" +.sp +\fBhelix2solv\fR +.SH "DESCRIPTION" +.sp +The helix format was a metadata format used in the RedCarpet package manager\&. It\(cqs still used in libzypp testcases\&. The helix2solv tool reads data in helix format from standard input and writes it in solv file format to standard output\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/installcheck.1 b/doc/gen/installcheck.1 new file mode 100644 index 0000000..492bd80 --- /dev/null +++ b/doc/gen/installcheck.1 @@ -0,0 +1,42 @@ +'\" t +.\" Title: installcheck +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "INSTALLCHECK" "1" "09/14/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" +installcheck \- find out which packages cannot be installed +.SH "SYNOPSIS" +.sp +\fBinstallcheck\fR \fIARCH\fR \fIREPO1\fR \fIREPO2\fR\&... \fB\-\-nocheck\fR \fINREPO1\fR \fINREPO2\fR\&... +.SH "DESCRIPTION" +.sp +The installcheck tool checks if all packages in \fIREPO1\fR\&...\fIREPON\fR are installable\&. A package is installable if there is a set of packages from the repositories that satisfies its dependencies\&. The repositories after the \fB\-\-nocheck\fR option are only used for dependency resolving, but the tool does not check if the packages in them are installable\&. +.sp +A Repository can be a solv file, a rpmmd \fBprimary\&.xml\&.gz\fR file, a SUSE \fBpackages\fR or \fBpackages\&.gz\fR file, or a Debian \fBPackages\fR or \fBPackages\&.gz\fR file\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/libsolv-bindings.3 b/doc/gen/libsolv-bindings.3 new file mode 100644 index 0000000..8e6417e --- /dev/null +++ b/doc/gen/libsolv-bindings.3 @@ -0,0 +1,6284 @@ +'\" t +.\" Title: Libsolv-Bindings +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 01/21/2020 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "LIBSOLV\-BINDINGS" "3" "01/21/2020" "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" +libsolv-bindings \- access libsolv from perl/python/ruby +.SH "DESCRIPTION" +.sp +Libsolv\(cqs language bindings offer an abstract, object orientated interface to the library\&. The supported languages are currently perl, python, and ruby\&. All example code (except in the specifics sections, of course) lists first the \(lqC\-ish\(rq interface, then the syntax for perl, python, and ruby (in that order)\&. +.SH "PERL SPECIFICS" +.sp +Libsolv\(cqs perl bindings can be loaded with the following statement: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBuse solv\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Objects are either created by calling the new() method on a class or they are returned by calling methods on other objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +my \fI$pool\fR \fB= solv::Pool\->new()\fR; +my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo("my_first_repo")\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Swig encapsulates all objects as tied hashes, thus the attributes can be accessed by treating the object as standard hash reference: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fI$pool\fR\fB\->{appdata} = 42\fR; +\fBprintf "appdata is %d\en",\fR \fI$pool\fR\fB\->{appdata}\fR; +.fi +.if n \{\ +.RE +.\} +.sp +A special exception to this are iterator objects, they are encapsulated as tied arrays so that it is possible to iterate with a for() statement: +.sp +.if n \{\ +.RS 4 +.\} +.nf +my \fI$iter\fR \fB=\fR \fI$pool\fR\fB\->solvables_iter()\fR; +\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@$iter\fR\fB) { \&.\&.\&. }\fR; +.fi +.if n \{\ +.RE +.\} +.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 perl stack: +.sp +.if n \{\ +.RS 4 +.\} +.nf +my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Due to a bug in swig, stringification does not work for libsolv\(cqs objects\&. Instead, you have to call the object\(cqs str() method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBprint\fR \fI$dep\fR\fB\->str() \&. "\e\fR\fIn\fR\fB"\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Swig implements all constants as numeric variables (instead of the more natural constant subs), so don\(cqt forget the leading \(lq$\(rq when accessing a constant\&. Also do not forget to prepend the namespace of the constant: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fI$pool\fR\fB\->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR; +.fi +.if n \{\ +.RE +.\} +.SH "PYTHON SPECIFICS" +.sp +The python bindings can be loaded with: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBimport solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Objects are either created by calling the constructor method for a class or they are returned by calling methods on other objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR \fB= solv\&.Pool()\fR +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR +.fi +.if n \{\ +.RE +.\} +.sp +Attributes can be accessed as usual: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR\fB\&.appdata = 42\fR +\fBprint "appdata is %d" % (\fR\fIpool\fR\fB\&.appdata)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterators also work as expected: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR +.fi +.if n \{\ +.RE +.\} +.sp +Arrays are passed and returned as list objects: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIjobs\fR \fB= []\fR +\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +The bindings define stringification for many classes, some also have a \fIrepr\fR method to ease debugging\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBprint\fR \fIdep\fR +\fBprint repr(\fR\fIrepo\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Constants are attributes of the corresponding classes: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR\fB\&.set_flag(solv\&.Pool\&.POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR; +.fi +.if n \{\ +.RE +.\} +.SH "RUBY SPECIFICS" +.sp +The ruby bindings can be loaded with: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBrequire \*(Aqsolv\*(Aq\fR +.fi +.if n \{\ +.RE +.\} +.sp +Objects are either created by calling the new method on a class or they are returned by calling methods on other objects\&. Note that all classes start with an uppercase letter in ruby, so the class is called \(lqSolv\(rq\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR \fB= Solv::Pool\&.new\fR +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR +.fi +.if n \{\ +.RE +.\} +.sp +Attributes can be accessed as usual: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR\fB\&.appdata = 42\fR +\fBputs "appdata is #{\fR\fIpool\fR\fB\&.appdata}"\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterators also work as expected: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter() do \&.\&.\&.\fR +.fi +.if n \{\ +.RE +.\} +.sp +Arrays are passed and returned as array objects: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIjobs\fR \fB= []\fR +\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Most classes define a to_s method, so objects can be easily stringified\&. Many also define an inspect() method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBputs\fR \fIdep\fR +\fBputs\fR \fIrepo\fR\fB\&.inspect\fR +.fi +.if n \{\ +.RE +.\} +.sp +Constants live in the namespace of the class they belong to: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fIpool\fR\fB\&.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Note that boolean methods have an added trailing \(lq?\(rq, to be consistent with other ruby modules: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBputs "empty" if\fR \fIrepo\fR\fB\&.isempty?\fR +.fi +.if n \{\ +.RE +.\} +.SH "TCL SPECIFICS" +.sp +Libsolv\(cqs tcl bindings can be loaded with the following statement: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBpackage require solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Objects are either created by calling class name prefixed with \(lqnew_\(rq, or they are returned by calling methods on other objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBset pool [solv::new_Pool]\fR +\fBset repo [\fR\fI$pool\fR \fBadd_repo "my_first_repo"]\fR +.fi +.if n \{\ +.RE +.\} +.sp +Swig provides a \(lqcget\(rq method to read object attributes, and a \(lqconfigure\(rq method to write them: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fI$pool\fR \fBconfigure \-appdata 42\fR +\fBputs "appdata is [\fR\fI$pool\fR \fBcget \-appdata]"\fR +.fi +.if n \{\ +.RE +.\} +.sp +The tcl bindings provide a little helper to work with iterators in a foreach style: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBset iter [\fR\fI$pool\fR \fBsolvables_iter]\fR +\fBsolv::iter s\fR \fI$iter\fR \fB{ \&.\&.\&. }\fR +.fi +.if n \{\ +.RE +.\} +.sp +libsolv\(cqs arrays are mapped to tcl\(cqs lists: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBset jobs [list\fR \fI$job1 $job2\fR\fB]\fR +\fBset problems [\fR\fI$solver\fR \fBsolve\fR \fI$jobs\fR\fB]\fR +\fBputs "We have [llength\fR \fI$problems\fR\fB] problems\&.\&.\&."\fR +.fi +.if n \{\ +.RE +.\} +.sp +Stringification is done by calling the object\(cqs \(lqstr\(rq method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBputs [\fR\fI$dep\fR \fBstr]\fR +.fi +.if n \{\ +.RE +.\} +.sp +There is one exception: you have to use \(lqstringify\(rq for Datamatch objects, as swig reports a clash with the \(lqstr\(rq attribute\&. Some objects also support a \(lq==\(rq method for equality tests, and a \(lq!=\(rq method\&. +.sp +Swig implements all constants as numeric variables, constants belonging to a libsolv class are prefixed with the class name: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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 \{\ +.RE +.\} +.SH "THE SOLV CLASS" +.sp +This is the main namespace of the library, you cannot create objects of this type but it contains some useful constants\&. +.SS "CONSTANTS" +.sp +Relational flag constants, the first three can be or\-ed together +.PP +\fBREL_LT\fR +.RS 4 +the \(lqless than\(rq bit +.RE +.PP +\fBREL_EQ\fR +.RS 4 +the \(lqequals to\(rq bit +.RE +.PP +\fBREL_GT\fR +.RS 4 +the \(lqgreater than\(rq bit +.RE +.PP +\fBREL_ARCH\fR +.RS 4 +used for relations that describe an extra architecture filter, the version part of the relation is interpreted as architecture\&. +.RE +.sp +Special Solvable Ids +.PP +\fBSOLVID_META\fR +.RS 4 +Access the meta section of a repository or repodata area\&. This is like an extra Solvable that has the Id SOLVID_META\&. +.RE +.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 most likely do not need this constant\&. +.RE +.sp +Constant string Ids +.PP +\fBID_NULL\fR +.RS 4 +Always zero +.RE +.PP +\fBID_EMPTY\fR +.RS 4 +Always one, describes the empty string +.RE +.PP +\fBSOLVABLE_NAME\fR +.RS 4 +The keyname Id of the name of the solvable\&. +.RE +.PP +\fB\&...\fR +.RS 4 +see the libsolv\-constantids manpage for a list of fixed Ids\&. +.RE +.SH "THE POOL CLASS" +.sp +The pool is libsolv\(cqs central resource manager\&. A pool consists of Solvables, Repositories, Dependencies, each indexed by Ids\&. +.SS "CLASS METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *Pool()\fR +my \fI$pool\fR \fB= solv::Pool\->new()\fR; +\fIpool\fR \fB= solv\&.Pool()\fR +\fIpool\fR \fB= Solv::Pool\&.new()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a new pool instance\&. In most cases you just need one pool\&. Note that the returned object "owns" the pool, i\&.e\&. if the object is freed, the pool is also freed\&. You can use the disown method to break this ownership relation\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid *appdata;\fR /* read/write */ +\fI$pool\fR\fB\->{appdata}\fR +\fIpool\fR\fB\&.appdata\fR +\fIpool\fR\fB\&.appdata\fR +.fi +.if n \{\ +.RE +.\} +.sp +Application specific data that may be used in any way by the code using the pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable solvables[];\fR /* read only */ +my \fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->{solvables}\->[\fR\fI$solvid\fR\fB]\fR; +\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR +\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR +.fi +.if n \{\ +.RE +.\} +.sp +Look up a Solvable by its id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo repos[];\fR /* read only */ +my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->{repos}\->[\fR\fI$repoid\fR\fB]\fR; +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR +.fi +.if n \{\ +.RE +.\} +.sp +Look up a Repository by its id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo *installed;\fR /* read/write */ +\fI$pool\fR\fB\->{installed} =\fR \fI$repo\fR; +\fIpool\fR\fB\&.installed =\fR \fIrepo\fR +\fIpool\fR\fB\&.installed =\fR \fIrepo\fR +.fi +.if n \{\ +.RE +.\} +.sp +Define which repository contains all the installed packages\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *errstr;\fR /* read only */ +my \fI$err\fR \fB=\fR \fI$pool\fR\fB\->{errstr}\fR; +\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR +\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the last error string that was stored in the pool\&. +.SS "CONSTANTS" +.PP +\fBPOOL_FLAG_PROMOTEEPOCH\fR +.RS 4 +Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&. +.RE +.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 since rpm\-4\&.9\&.0\&. +.RE +.PP +\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR +.RS 4 +Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&. +.RE +.PP +\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR +.RS 4 +An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&. +.RE +.PP +\fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR +.RS 4 +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 +.RS 4 +Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&. +.RE +.PP +\fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR +.RS 4 +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 +.RS 4 +Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&. +.RE +.PP +\fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR +.RS 4 +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 +.RS 4 +Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&. +.RE +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid free()\fR +\fI$pool\fR\fB\->free()\fR; +\fIpool\fR\fB\&.free()\fR +\fIpool\fR\fB\&.free()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Force a free of the pool\&. After this call, you must not access any object that still references the pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid disown()\fR +\fI$pool\fR\fB\->disown()\fR; +\fIpool\fR\fB\&.disown()\fR +\fIpool\fR\fB\&.disown()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Break the ownership relation between the binding object and the pool\&. After this call, the pool will not get freed even if the object goes out of scope\&. This also means that you must manually call the free method to free the pool data\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid setdebuglevel(int\fR \fIlevel\fR\fB)\fR +\fI$pool\fR\fB\->setdebuglevel(\fR\fI$level\fR\fB)\fR; +\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR +\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set the debug level\&. A value of zero means no debug output, the higher the value, the more output is generated\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR +my \fI$oldvalue\fR \fB=\fR \fI$pool\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR; +\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR +\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint get_flag(int\fR \fIflag\fR\fB)\fR +my \fI$value\fR \fB=\fR \fI$pool\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR; +\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR +\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR +.fi +.if n \{\ +.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 solve package dependencies for some other system\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_rootdir(const char *\fR\fIrootdir\fR\fB)\fR +\fI$pool\fR\fB\->set_rootdir(\fR\fIrootdir\fR\fB)\fR; +\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR +\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *get_rootdir()\fR +my \fI$rootdir\fR \fB=\fR \fI$pool\fR\fB\->get_rootdir()\fR; +\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR +\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set/get the rootdir to use\&. This is useful if you want package management to work only in some directory, for example if you want to setup a chroot jail\&. Note that the rootdir will only be prepended to file paths if the \fBREPO_USE_ROOTDIR\fR flag is used\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid setarch(const char *\fR\fIarch\fR \fB= 0)\fR +\fI$pool\fR\fB\->setarch()\fR; +\fIpool\fR\fB\&.setarch()\fR +\fIpool\fR\fB\&.setarch()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set the architecture for your system\&. The architecture is used to determine which packages are installable\&. It defaults to the result of \(lquname \-m\(rq\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo add_repo(const char *\fR\fIname\fR\fB)\fR +\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo(\fR\fI$name\fR\fB)\fR; +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a Repository with the specified name to the pool\&. The repository is empty on creation, use the repository methods to populate it with packages\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepoiterator repos_iter()\fR +\fBfor my\fR \fI$repo\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->repos_iter()})\fR +\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter():\fR +\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the existing repositories\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvableiterator solvables_iter()\fR +\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->solvables_iter()})\fR +\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR +\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the existing solvables\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDep Dep(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$dep\fR \fB=\fR \fI$pool\fR\fB\->Dep(\fR\fI$string\fR\fB)\fR; +\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR +\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create an object describing a string or dependency\&. If the string is currently not in the pool and \fIcreate\fR is false, \fBundef\fR/\fBNone\fR/\fBnil\fR is returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid addfileprovides()\fR +\fI$pool\fR\fB\->addfileprovides()\fR; +\fIpool\fR\fB\&.addfileprovides()\fR +\fIpool\fR\fB\&.addfileprovides()\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *addfileprovides_queue()\fR +my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->addfileprovides_queue()\fR; +\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR +\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&. The addfileprovides_queue variant works the same way but returns an array containing all file dependencies\&. 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\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid createwhatprovides()\fR +\fI$pool\fR\fB\->createwhatprovides()\fR; +\fIpool\fR\fB\&.createwhatprovides()\fR +\fIpool\fR\fB\&.createwhatprovides()\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fBSolvable *whatprovides(DepId\fR \fIdep\fR\fB)\fR +my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatprovides(\fR\fI$dep\fR\fB)\fR; +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that provide the specified dependency\&. You can use either a Dep object or a simple Id as argument\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *best_solvables(Solvable *\fR\fIsolvables\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->best_solvables(\fR\fI$solvables\fR\fB)\fR; +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Filter list of solvables by repo priority, architecture and version\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *whatcontainsdep(Id\fR \fIkeyname\fR\fB, DepId\fR \fIdep\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatcontainsdep(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatcontainsdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatcontainsdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables for which keyname contains the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *whatmatchesdep(Id\fR \fIkeyname\fR\fB, DepId\fR \fIdep\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatmatchesdep(\fR\fI$keyname\fR\fB,\fR \fI$sdep\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchesdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchesdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that have dependencies in keyname that match the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *whatmatchessolvable(Id\fR \fIkeyname\fR\fB, Solvable\fR \fIsolvable\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatmatchessolvable(\fR\fI$keyname\fR\fB,\fR \fI$solvable\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR +\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that match package dependencies against solvable\(cqs provides\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *matchprovidingids(const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR +my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->matchprovidingids(\fR\fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Search the names of all provides and return the ones matching the specified string\&. See the Dataiterator class for the allowed flags\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId towhatprovides(Id *\fR\fIids\fR\fB)\fR +my \fI$offset\fR \fB=\fR \fI$pool\fR\fB\->towhatprovides(\e\fR\fI@ids\fR\fB)\fR; +\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR +\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +\(lqInternalize\(rq an array containing Ids\&. The returned value can be used to create solver jobs working on a specific set of packages\&. See the Solver class for more information\&. +.sp +.if n \{\ +.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 +\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch?(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the specified Id describes a known architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver Solver()\fR +my \fI$solver\fR \fB=\fR \fI$pool\fR\fB\->Solver()\fR; +\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR +\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a new solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBJob Job(int\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR +my \fI$job\fR \fB=\fR \fI$pool\fR\fB\->Job(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR; +\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR +\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fBSelection Selection()\fR +my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection()\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create an empty selection\&. Useful as a starting point for merging other selections\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSelection Selection_all()\fR +my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection_all()\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a selection containing all packages\&. Useful as starting point for intersecting other selections or for update/distupgrade jobs\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSelection select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR +my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +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\&. +.sp +.if n \{\ +.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\fI$dep\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 +\fBSelection matchsolvable(Solvable\fR \fIsolvable\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\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\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 solvable\(cqs provides\&. +.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 +\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBJob *getpooljobs()\fR +\fI@jobs\fR \fB=\fR \fI$pool\fR\fB\->getpooljobs()\fR; +\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR +\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR +.fi +.if n \{\ +.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 which packages must not be erased\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_loadcallback(Callable *\fR\fIcallback\fR\fB)\fR +\fI$pool\fR\fB\->setloadcallback(\e\fR\fI&callbackfunction\fR\fB)\fR; +\fIpool\fR\fB\&.setloadcallback(\fR\fIcallbackfunction\fR\fB)\fR +\fIpool\fR\fB\&.setloadcallback { |\fR\fIrepodata\fR\fB| \&.\&.\&. }\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set the callback function called when repository metadata needs to be loaded on demand\&. To make use of this feature, you need to create repodata stubs that tell the library which data is available but not loaded\&. If later on the data needs to be accessed, the callback function is called with a repodata argument\&. You can then load the data (maybe fetching it first from a remote server)\&. The callback should return true if the data has been made available\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +/* bindings only */ +\fI$pool\fR\fB\->appdata_disown()\fR +\fIpool\fR\fB\&.appdata_disown()\fR +\fIpool\fR\fB\&.appdata_disown()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Decrement the reference count of the appdata object\&. This can be used to break circular references (e\&.g\&. if the pool\(cqs appdata value points to some meta data structure that contains a pool handle)\&. If used incorrectly, this method can lead to application crashes, so beware\&. (This method is a no\-op for ruby and tcl\&.) +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *get_considered_list()\fR +my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->get_considered_list()\fR; +\fIids\fR \fB=\fR \fIpool\fR\fB\&.get_considered_list()\fR +\fIids\fR \fB=\fR \fIpool\fR\fB\&.get_considered_list()\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_considered_list(Id *\fR\fIids\fR\fB)\fR +\fI$pool\fR\fB\->set_considered_list(\e\fR\fI@ids\fR\fB)\fR; +\fIpool\fR\fB\&.set_considered_list(\fR\fIids\fR\fB)\fR +\fIpool\fR\fB\&.set_considered_list(\fR\fIids\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Get/set the list of solvables that are eligible for installation\&. Note that you need to recreate the whatprovides hash after changing the list\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *get_disabled_list()\fR +my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->get_disabled_list()\fR; +\fIids\fR \fB=\fR \fIpool\fR\fB\&.get_disabled_list()\fR +\fIids\fR \fB=\fR \fIpool\fR\fB\&.get_disabled_list()\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_disabled_list(Id *\fR\fIids\fR\fB)\fR +\fI$pool\fR\fB\->set_disabled_list(\e\fR\fI@ids\fR\fB)\fR; +\fIpool\fR\fB\&.set_disabled_list(\fR\fIids\fR\fB)\fR +\fIpool\fR\fB\&.set_disabled_list(\fR\fIids\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Get/set the list of solvables that are not eligible for installation\&. This is basically the inverse of the \(lqconsidered\(rq methods above, i\&.e\&. calling \(lqset_disabled_list()\(rq with an empty list will make all solvables eligible for installation\&. Note you need to recreate the whatprovides hash after changing the list\&. +.SS "DATA RETRIEVAL METHODS" +.sp +In the following functions, the \fIkeyname\fR argument describes what to retrieve\&. For the standard cases you can use the available Id constants\&. For example, +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB$solv::SOLVABLE_SUMMARY\fR +\fBsolv\&.SOLVABLE_SUMMARY\fR +\fBSolv::SOLVABLE_SUMMARY\fR +.fi +.if n \{\ +.RE +.\} +.sp +selects the \(lqSummary\(rq entry of a solvable\&. The \fIsolvid\fR argument selects the desired solvable by Id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$string\fR \fB=\fR \fI$pool\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIid\fR \fB=\fR \fIpool\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIid\fR \fB=\fR \fIpool\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$pool\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fInum\fR \fB=\fR \fIpool\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fInum\fR \fB=\fR \fIpool\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$pool\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIbool\fR \fB=\fR \fIpool\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIbool\fR \fB=\fR \fIpool\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$pool\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$chksum\fR \fB=\fR \fI$pool\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Lookup functions\&. Return the data element stored in the specified solvable\&. You should probably use the methods of the Solvable class instead\&. +.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$pool\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDataiterator Dataiterator_solvid(Id\fR \fIsolvid\fR\fB, 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$pool\fR\fB\->Dataiterator(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the matching data elements\&. See the Dataiterator class for more information\&. The Dataiterator method iterates over all solvables in the pool, whereas the Dataiterator_solvid only iterates over the specified solvable\&. +.SS "ID METHODS" +.sp +The following methods deal with Ids, i\&.e\&. integers representing objects in the pool\&. They are considered \(lqlow level\(rq, in most cases you would not use them but instead the object orientated methods\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo id2repo(Id\fR \fIid\fR\fB)\fR +\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->id2repo(\fR\fI$id\fR\fB)\fR; +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR +\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Lookup an existing Repository by id\&. You can also do this by using the \fBrepos\fR attribute\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable id2solvable(Id\fR \fIid\fR\fB)\fR +\fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->id2solvable(\fR\fI$id\fR\fB)\fR; +\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR +\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Lookup an existing Repository by id\&. You can also do this by using the \fBsolvables\fR attribute\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *solvid2str(Id\fR \fIid\fR\fB)\fR +my \fI$str\fR \fB=\fR \fI$pool\fR\fB\->solvid2str(\fR\fI$id\fR\fB)\fR; +\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR +\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the Solvable with the specified id\&. The string consists of the name, version, and architecture of the Solvable\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId str2id(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$id\fR \fB=\fR \fIpool\fR\fB\->str2id(\fR\fI$string\fR\fB)\fR; +\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR +\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *id2str(Id\fR \fIid\fR\fB)\fR +\fI$string\fR \fB=\fR \fIpool\fR\fB\->id2str(\fR\fI$id\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convert a string 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 +\fBId rel2id(Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$id\fR \fB=\fR \fIpool\fR\fB\->rel2id(\fR\fI$nameid\fR\fB,\fR \fI$evrid\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR +\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fB$solv::REL_EQ | $solv::REL_GT | $solv::REL_LT\fR +\fBsolv\&.REL_EQ | solv\&.REL_GT | solv\&.REL_LT\fR +\fBSolv::REL_EQ | Solv::REL_GT | Solv::REL_LT\fR +.fi +.if n \{\ +.RE +.\} +.sp +Thus, if you want a \(lq<=\(rq relation, you would use \fBREL_LT | REL_EQ\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id2langid(Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->id2langid(\fR\fI$id\fR\fB,\fR \fI$language\fR\fB)\fR; +\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR +\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a language specific Id from some other id\&. This function simply converts the id into a string, appends a dot and the specified language to the string and converts the result back into an Id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *dep2str(Id\fR \fIid\fR\fB)\fR +\fI$string\fR \fB=\fR \fIpool\fR\fB\->dep2str(\fR\fI$id\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR +\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convert a dependency id into a string\&. If the id is just a string, this function has the same effect as id2str()\&. For relational dependencies, the result is the correct \(lqname relation evr\(rq string\&. +.SH "THE DEPENDENCY CLASS" +.sp +The dependency class is an object orientated way to work with strings and dependencies\&. Internally, dependencies are represented as Ids, i\&.e\&. simple numbers\&. Dependency objects can be constructed by using the Pool\(cqs Dep() method\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$dep\fR\fB\->{pool}\fR +\fIdep\fR\fB\&.pool\fR +\fIdep\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back reference to the pool this dependency belongs to\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$dep\fR\fB\->{id}\fR +\fIdep\fR\fB\&.id\fR +\fIdep\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of this dependency\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDep Rel(int\fR \fIflags\fR\fB, DepId\fR \fIevrid\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR +my \fI$reldep\fR \fB=\fR \fI$dep\fR\fB\->Rel(\fR\fI$flags\fR\fB,\fR \fI$evrdep\fR\fB)\fR; +\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR +\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fBSelection Selection_name(int\fR \fIsetflags\fR \fB= 0)\fR +my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_name()\fR; +\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR +\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a Selection from a dependency\&. The selection consists of all packages that have a name equal to the dependency\&. If the dependency is of a relational type, the packages version must also fulfill the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSelection Selection_provides(int\fR \fIsetflags\fR \fB= 0)\fR +my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_provides()\fR; +\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR +\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a Selection from a dependency\&. The selection consists of all packages that have at least one provides matching the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *str()\fR +my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str()\fR; +\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR +\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIdep\fR\fB)\fR +\fIstr\fR \fB=\fR \fIdep\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Same as calling the str() method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$dep1\fR \fB==\fR \fI$dep2\fR\fB)\fR +\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR\fB:\fR +\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR +.fi +.if n \{\ +.RE +.\} +.sp +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\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$repo\fR\fB\->{pool}\fR +\fIrepo\fR\fB\&.pool\fR +\fIrepo\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back reference to the pool this dependency belongs to\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$repo\fR\fB\->{id}\fR +\fIrepo\fR\fB\&.id\fR +\fIrepo\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *name;\fR /* read/write */ +\fI$repo\fR\fB\->{name}\fR +\fIrepo\fR\fB\&.name\fR +\fIrepo\fR\fB\&.name\fR +.fi +.if n \{\ +.RE +.\} +.sp +The repositories name\&. To libsolv, the name is just a string with no specific meaning\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint priority;\fR /* read/write */ +\fI$repo\fR\fB\->{priority}\fR +\fIrepo\fR\fB\&.priority\fR +\fIrepo\fR\fB\&.priority\fR +.fi +.if n \{\ +.RE +.\} +.sp +The priority of the repository\&. A higher number means that packages of this repository will be chosen over other repositories, even if they have a greater package version\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint subpriority;\fR /* read/write */ +\fI$repo\fR\fB\->{subpriority}\fR +\fIrepo\fR\fB\&.subpriority\fR +\fIrepo\fR\fB\&.subpriority\fR +.fi +.if n \{\ +.RE +.\} +.sp +The sub\-priority of the repository\&. This value is compared when the priorities of two repositories are the same\&. It is useful to make the library prefer on\-disk repositories to remote ones\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint nsolvables;\fR /* read only */ +\fI$repo\fR\fB\->{nsolvables}\fR +\fIrepo\fR\fB\&.nsolvables\fR +\fIrepo\fR\fB\&.nsolvables\fR +.fi +.if n \{\ +.RE +.\} +.sp +The number of solvables in this repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid *appdata;\fR /* read/write */ +\fI$repo\fR\fB\->{appdata}\fR +\fIrepo\fR\fB\&.appdata\fR +\fIrepo\fR\fB\&.appdata\fR +.fi +.if n \{\ +.RE +.\} +.sp +Application specific data that may be used in any way by the code using the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDatapos *meta;\fR /* read only */ +\fI$repo\fR\fB\->{meta}\fR +\fIrepo\fR\fB\&.meta\fR +\fIrepo\fR\fB\&.meta\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a Datapos object of the repodata\(cqs metadata\&. You can use the lookup methods of the Datapos class to lookup metadata attributes, like the repository timestamp\&. +.SS "CONSTANTS" +.PP +\fBREPO_REUSE_REPODATA\fR +.RS 4 +Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new area\&. +.RE +.PP +\fBREPO_NO_INTERNALIZE\fR +.RS 4 +Do not internalize the added repository data\&. This is useful if you plan to add more data because internalization is a costly operation\&. +.RE +.PP +\fBREPO_LOCALPOOL\fR +.RS 4 +Use the repodata\(cqs pool for Id storage instead of the global pool\&. Useful if you don\(cqt want to pollute the global pool with many unneeded ids, like when storing the filelist\&. +.RE +.PP +\fBREPO_USE_LOADING\fR +.RS 4 +Use the repodata that is currently being loaded instead of creating a new one\&. This only makes sense if used in a load callback\&. +.RE +.PP +\fBREPO_EXTEND_SOLVABLES\fR +.RS 4 +Do not create new solvables for the new data, but match existing solvables and add the data to them\&. Repository metadata is often split into multiple parts, with one primary file describing all packages and other parts holding information that is normally not needed, like the changelog\&. +.RE +.PP +\fBREPO_USE_ROOTDIR\fR +.RS 4 +Prepend the pool\(cqs rootdir to the path when doing file operations\&. +.RE +.PP +\fBREPO_NO_LOCATION\fR +.RS 4 +Do not add a location element to the solvables\&. Useful if the solvables are not in the final position, so you can add the correct location later in your code\&. +.RE +.PP +\fBSOLV_ADD_NO_STUBS\fR +.RS 4 +Do not create stubs for repository parts that can be downloaded on demand\&. +.RE +.PP +\fBSUSETAGS_RECORD_SHARES\fR +.RS 4 +This is specific to the add_susetags() method\&. Susetags allows one to refer to already read packages to save disk space\&. If this data sharing needs to work over multiple calls to add_susetags, you need to specify this flag so that the share information is made available to subsequent calls\&. +.RE +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid free(bool\fR \fIreuseids\fR \fB= 0)\fR +\fI$repo\fR\fB\->free()\fR; +\fIrepo\fR\fB\&.free()\fR +\fIrepo\fR\fB\&.free()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Free the repository and all solvables it contains\&. If \fIreuseids\fR is set to true, the solvable ids and the repository id may be reused by the library when added new solvables\&. Thus you should leave it false if you are not sure that somebody holds a reference\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid empty(bool\fR \fIreuseids\fR \fB= 0)\fR +\fI$repo\fR\fB\->empty()\fR; +\fIrepo\fR\fB\&.empty()\fR +\fIrepo\fR\fB\&.empty()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Free all the solvables in a repository\&. The repository will be empty after this call\&. See the free() method for the meaning of \fIreuseids\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool isempty()\fR +\fI$repo\fR\fB\->isempty()\fR +\fIrepo\fR\fB\&.empty()\fR +\fIrepo\fR\fB\&.empty?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if there are no solvables in this repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid internalize()\fR +\fI$repo\fR\fB\->internalize()\fR; +\fIrepo\fR\fB\&.internalize()\fR +\fIrepo\fR\fB\&.internalize()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Internalize added data\&. Data must be internalized before it is available to the lookup and data iterator functions\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool write(FILE *\fR\fIfp\fR\fB)\fR +\fI$repo\fR\fB\->write(\fR\fI$fp\fR\fB)\fR +\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Write a repo as a \(lqsolv\(rq file\&. These files can be read very fast and thus are a good way to cache repository data\&. Returns false if there was some error writing the file\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvableiterator solvables_iter()\fR +\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$repo\fR\fB\->solvables_iter()})\fR +\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter():\fR +\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over all solvables in a repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepodata add_repodata(int\fR \fIflags\fR \fB= 0)\fR +my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->add_repodata()\fR; +\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR +\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a new repodata area to the repository\&. This is normally automatically done by the repo_add methods, so you need this method only in very rare circumstances\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid create_stubs()\fR +\fI$repo\fR\fB\->create_stubs()\fR; +\fIrepo\fR\fB\&.create_stubs()\fR +\fIrepo\fR\fB\&.create_stubs()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Calls the create_stubs() repodata method for the last repodata of the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool iscontiguous()\fR +\fI$repo\fR\fB\->iscontiguous()\fR +\fIrepo\fR\fB\&.iscontiguous()\fR +\fIrepo\fR\fB\&.iscontiguous?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the solvables of this repository are all in a single block with no holes, i\&.e\&. they have consecutive ids\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepodata first_repodata()\fR +my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->first_repodata()\fR; +\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR +\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Checks if all repodatas but the first repodata are extensions, and return the first repodata if this is the case\&. Useful if you want to do a store/retrieve sequence on the repository to reduce the memory using and enable paging, as this does not work if the repository contains multiple non\-extension repodata areas\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR +my \fI$sel\fR \fB=\fR \fI$repo\fR\fB\->Selection()\fR; +\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR +\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a Selection consisting of all packages in the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDataiterator Dataiterator(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR +my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDataiterator Dataiterator_meta(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR +my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator_meta(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the matching data elements in this repository\&. See the Dataiterator class for more information\&. The Dataiterator() method iterates over all solvables in a repository, whereas the Dataiterator_meta method only iterates over the repository\(cqs meta data\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$repo\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIrepo\fR\fB)\fR +\fIstr\fR \fB=\fR \fIrepo\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the name of the repository, or "Repo#" if no name is set\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$repo1\fR \fB==\fR \fI$repo2\fR\fB)\fR +\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR\fB:\fR +\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Two repositories are equal if they belong to the same pool and have the same id\&. +.SS "DATA ADD METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable add_solvable()\fR +\fI$repo\fR\fB\->add_solvable()\fR; +\fIrepo\fR\fB\&.add_solvable()\fR +\fIrepo\fR\fB\&.add_solvable()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a single empty solvable to the repository\&. Returns a Solvable object, see the Solvable class for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_solv(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_solv(\fR\fI$name\fR\fB)\fR; +\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR +\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Read a \(lqsolv\(rq file and add its contents to the repository\&. These files can be written with the write() method and are normally used as fast cache for repository metadata\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_rpmdb(int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_rpmdb()\fR; +\fIrepo\fR\fB\&.add_rpmdb()\fR +\fIrepo\fR\fB\&.add_rpmdb()\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_rpmdb_reffp(FILE *\fR\fIreffp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_rpmdb_reffp(\fR\fI$reffp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR +\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the rpm database to the repository\&. If a solv file containing an old version of the database is available, it can be passed as reffp to speed up reading\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable add_rpm(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_rpm(\fR\fI$filename\fR\fB)\fR; +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the metadata of a single rpm package to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_rpmdb_pubkeys(int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_rpmdb_pubkeys()\fR; +\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR +\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add all pubkeys contained in the rpm database to the repository\&. Note that newer rpm versions also allow to store the pubkeys in some directory instead of the rpm database\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable add_pubkey(const char *\fR\fIkeyfile\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_pubkey(\fR\fI$keyfile\fR\fB)\fR; +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a pubkey from a file to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_rpmmd(FILE *\fR\fIfp\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_rpmmd(\fR\fI$fp\fR\fB,\fR \fIundef\fR\fB)\fR; +\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fINone\fR\fB)\fR +\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fInil\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add metadata stored in the "rpm\-md" format (i\&.e\&. from files in the \(lqrepodata\(rq directory) to a repository\&. Supported files are "primary", "filelists", "other", "suseinfo"\&. Do not forget to specify the \fBREPO_EXTEND_SOLVABLES\fR for extension files like "filelists" and "other"\&. Use the \fIlanguage\fR parameter if you have language extension files, otherwise simply use a \fBundef\fR/\fBNone\fR/\fBnil\fR parameter\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_repomdxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_repomdxml(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the repomd\&.xml meta description from the "rpm\-md" format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_updateinfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_updateinfoxml(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the updateinfo\&.xml file containing available maintenance updates to the repository\&. All updates are created as special packages that have a "patch:" prefix in their name\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_deltainfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_deltainfoxml(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the deltainfo\&.xml file (also called prestodelta\&.xml) containing available delta\-rpms to the repository\&. The data is added to the "meta" section, i\&.e\&. no package gets created\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_debdb(int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_debdb()\fR; +\fIrepo\fR\fB\&.add_debdb()\fR +\fIrepo\fR\fB\&.add_debdb()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the debian installed package database to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_debpackages(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_debpackages(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR +\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the debian repository metadata (the "packages" file) to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable add_deb(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_deb(\fR\fI$filename\fR\fB)\fR; +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR +\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the metadata of a single deb package to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_mdk(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 +.if n \{\ +.RE +.\} +.sp +Add the contents of the mageia/mandriva repository metadata (the "synthesis\&.hdlist" file) to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_mdk_info(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\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 +.\} +.sp +Extend the packages from the synthesis file with the info\&.xml and files\&.xml data\&. Do not forget to specify \fBREPO_EXTEND_SOLVABLES\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_arch_repo(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_arch_repo(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the archlinux repository metadata (the "\&.db\&.tar" file) to the repository\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_arch_local(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_arch_local(\fR\fI$dir\fR\fB)\fR; +\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR +\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the archlinux installed package database to the repository\&. The \fIdir\fR parameter is usually set to "/var/lib/pacman/local"\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_content(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_content(\fR\fI$fp\fR\fB)\fR; +\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR +\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the \(lqcontent\(rq meta description from the susetags format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_susetags(FILE *\fR\fIfp\fR\fB, Id\fR \fIdefvendor\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_susetags(\fR\fI$fp\fR\fB,\fR \fI$defvendor\fR\fB,\fR \fI$language\fR\fB)\fR; +\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR +\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add repository metadata in the susetags format to the repository\&. Like with add_rpmmd, you can specify a language if you have language extension files\&. The \fIdefvendor\fR parameter provides a default vendor for packages with missing vendors, it is usually provided in the content file\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool add_products(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR +\fI$repo\fR\fB\->add_products(\fR\fI$dir\fR\fB)\fR; +\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR +\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the installed SUSE products database to the repository\&. The \fIdir\fR parameter is usually "/etc/products\&.d"\&. +.SH "THE SOLVABLE CLASS" +.sp +A solvable describes all the information of one package\&. Each solvable belongs to one repository, it can be added and filled manually but in most cases solvables will get created by the repo_add methods\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo *repo;\fR /* read only */ +\fI$solvable\fR\fB\->{repo}\fR +\fIsolvable\fR\fB\&.repo\fR +\fIsolvable\fR\fB\&.repo\fR +.fi +.if n \{\ +.RE +.\} +.sp +The repository this solvable belongs to\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$solvable\fR\fB\->{pool}\fR +\fIsolvable\fR\fB\&.pool\fR +\fIsolvable\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +The pool this solvable belongs to, same as the pool of the repo\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$solvable\fR\fB\->{id}\fR +\fIsolvable\fR\fB\&.id\fR +\fIsolvable\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The specific id of the solvable\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *name;\fR /* read/write */ +\fI$solvable\fR\fB\->{name}\fR +\fIsolvable\fR\fB\&.name\fR +\fIsolvable\fR\fB\&.name\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *evr;\fR /* read/write */ +\fI$solvable\fR\fB\->{evr}\fR +\fIsolvable\fR\fB\&.evr\fR +\fIsolvable\fR\fB\&.evr\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *arch;\fR /* read/write */ +\fI$solvable\fR\fB\->{arch}\fR +\fIsolvable\fR\fB\&.arch\fR +\fIsolvable\fR\fB\&.arch\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *vendor;\fR /* read/write */ +\fI$solvable\fR\fB\->{vendor}\fR +\fIsolvable\fR\fB\&.vendor\fR +\fIsolvable\fR\fB\&.vendor\fR +.fi +.if n \{\ +.RE +.\} +.sp +Easy access to often used attributes of solvables\&. They are internally stored as Ids\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId nameid;\fR /* read/write */ +\fI$solvable\fR\fB\->{nameid}\fR +\fIsolvable\fR\fB\&.nameid\fR +\fIsolvable\fR\fB\&.nameid\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId evrid;\fR /* read/write */ +\fI$solvable\fR\fB\->{evrid}\fR +\fIsolvable\fR\fB\&.evrid\fR +\fIsolvable\fR\fB\&.evrid\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId archid;\fR /* read/write */ +\fI$solvable\fR\fB\->{archid}\fR +\fIsolvable\fR\fB\&.archid\fR +\fIsolvable\fR\fB\&.archid\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId vendorid;\fR /* read/write */ +\fI$solvable\fR\fB\->{vendorid}\fR +\fIsolvable\fR\fB\&.vendorid\fR +\fIsolvable\fR\fB\&.vendorid\fR +.fi +.if n \{\ +.RE +.\} +.sp +Raw interface to the ids\&. Useful if you want to search for a specific id and want to avoid the string compare overhead\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR +my \fI$string\fR \fB=\fR \fI$solvable\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR +\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.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\fIkeyname\fR\fB)\fR +\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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 +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR +my \fI$bool\fR \fB=\fR \fI$solvable\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR; +\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR +\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR +my \fI$chksum\fR \fB=\fR \fI$solvable\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR; +\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR +\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI@ids\fR \fB=\fR \fI$solvable\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR; +\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR +\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDep *lookup_deparray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +my \fI@deps\fR \fB=\fR \fI$solvable\fR\fB\->lookup_deparray(\fR\fI$keyname\fR\fB)\fR; +\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR +\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Generic lookup methods\&. Retrieve data stored for the specific keyname\&. The lookup_idarray() method will return an array of Ids, use lookup_deparray if you want an array of Dependency objects instead\&. Some Id arrays contain two parts of data divided by a specific marker, for example the provides array uses the SOLVABLE_FILEMARKER id to store both the ids provided by the package and the ids added by the addfileprovides method\&. The default, \-1, translates to the correct marker for the keyname and returns the first part of the array, use 1 to select the second part or 0 to retrieve all ids including the marker\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_location(unsigned int *\fR\fIOUTPUT\fR\fB)\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 +.\} +.sp +Return a tuple containing the on\-media location and an optional media number for multi\-part repositories (e\&.g\&. repositories spawning multiple DVDs)\&. +.sp +.if n \{\ +.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 +\fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the matching data elements\&. See the Dataiterator class for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_deparray(Id\fR \fIkeyname\fR\fB, DepId\fR \fIdep\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR; +\fI$solvable\fR\fB\->add_deparray(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR; +\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a new dependency to the attributes stored in keyname\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid unset(Id\fR \fIkeyname\fR\fB)\fR; +\fI$solvable\fR\fB\->unset(\fR\fI$keyname\fR\fB)\fR; +\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR +\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Delete data stored for the specific keyname\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool installable()\fR; +\fI$solvable\fR\fB\->installable()\fR +\fIsolvable\fR\fB\&.installable()\fR +\fIsolvable\fR\fB\&.installable?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the solvable is installable on the system\&. Solvables are not installable if the system does not support their architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool isinstalled()\fR; +\fI$solvable\fR\fB\->isinstalled()\fR +\fIsolvable\fR\fB\&.isinstalled()\fR +\fIsolvable\fR\fB\&.isinstalled?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the solvable is installed on the system\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool identical(Solvable *\fR\fIother\fR\fB)\fR +\fI$solvable\fR\fB\->identical(\fR\fI$other\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 +.\} +.sp +Return true if the two solvables are identical\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint evrcmp(Solvable *\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 +.\} +.sp +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\&. +.sp +.if n \{\ +.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 +\fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a Selection containing just the single solvable\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *str()\fR +my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str()\fR; +\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR +\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the solvable\&. The string consists of the name, version, and architecture of the Solvable\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIsolvable\fR\fB)\fR +\fIstr\fR \fB=\fR \fIsolvable\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Same as calling the str() method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$solvable1\fR \fB==\fR \fI$solvable2\fR\fB)\fR +\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR\fB:\fR +\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Two solvables are equal if they are part of the same pool and have the same ids\&. +.SH "THE DATAITERATOR CLASS" +.sp +Dataiterators can be used to do complex string searches or to iterate over arrays\&. They can be created via the constructors in the Pool, Repo, and Solvable classes\&. The Repo and Solvable constructors will limit the search to the repository or the specific package\&. +.SS "CONSTANTS" +.PP +\fBSEARCH_STRING\fR +.RS 4 +Return a match if the search string matches the value\&. +.RE +.PP +\fBSEARCH_STRINGSTART\fR +.RS 4 +Return a match if the value starts with the search string\&. +.RE +.PP +\fBSEARCH_STRINGEND\fR +.RS 4 +Return a match if the value ends with the search string\&. +.RE +.PP +\fBSEARCH_SUBSTRING\fR +.RS 4 +Return a match if the search string can be matched somewhere in the value\&. +.RE +.PP +\fBSEARCH_GLOB\fR +.RS 4 +Do a glob match of the search string against the value\&. +.RE +.PP +\fBSEARCH_REGEX\fR +.RS 4 +Do a regular expression match of the search string against the value\&. +.RE +.PP +\fBSEARCH_NOCASE\fR +.RS 4 +Ignore case when matching strings\&. Works for all the above match types\&. +.RE +.PP +\fBSEARCH_FILES\fR +.RS 4 +Match the complete filenames of the file list, not just the base name\&. +.RE +.PP +\fBSEARCH_COMPLETE_FILELIST\fR +.RS 4 +When matching the file list, check every file of the package not just the subset from the primary metadata\&. +.RE +.PP +\fBSEARCH_CHECKSUMS\fR +.RS 4 +Allow the matching of checksum entries\&. +.RE +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid prepend_keyname(Id\fR \fIkeyname\fR\fB)\fR; +\fI$di\fR\fB\->prepend_keyname(\fR\fI$keyname\fR\fB)\fR; +\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR +\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Do a sub\-search in the array stored in keyname\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid skip_solvable()\fR; +\fI$di\fR\fB\->skip_solvable()\fR; +\fIdi\fR\fB\&.skip_solvable()\fR +\fIdi\fR\fB\&.skip_solvable()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Stop matching the current solvable and advance to the next one\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate through the matches\&. If there is a match, the object in d will be of type Datamatch\&. +.SH "THE DATAMATCH CLASS" +.sp +Objects of this type will be created for every value matched by a dataiterator\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$d\fR\fB\->{pool}\fR +\fId\fR\fB\&.pool\fR +\fId\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo *repo;\fR /* read only */ +\fI$d\fR\fB\->{repo}\fR +\fId\fR\fB\&.repo\fR +\fId\fR\fB\&.repo\fR +.fi +.if n \{\ +.RE +.\} +.sp +The repository containing the matched object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *solvable;\fR /* read only */ +\fI$d\fR\fB\->{solvable}\fR +\fId\fR\fB\&.solvable\fR +\fId\fR\fB\&.solvable\fR +.fi +.if n \{\ +.RE +.\} +.sp +The solvable containing the value that was matched\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId solvid;\fR /* read only */ +\fI$d\fR\fB\->{solvid}\fR +\fId\fR\fB\&.solvid\fR +\fId\fR\fB\&.solvid\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the solvable that matched\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fIkey_id\fR; +\fI$d\fR\fB\->{\fR\fIkey_id\fR\fB}\fR +\fId\fR\fB\&.key_id\fR +\fId\fR\fB\&.key_id\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *\fR\fIkey_idstr\fR; +\fI$d\fR\fB\->{\fR\fIkey_idstr\fR\fB}\fR +\fId\fR\fB\&.key_idstr\fR +\fId\fR\fB\&.key_idstr\fR +.fi +.if n \{\ +.RE +.\} +.sp +The keyname that matched, either as id or string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fItype_id\fR; +\fI$d\fR\fB\->{\fR\fItype_id\fR\fB}\fR +\fId\fR\fB\&.type_id\fR +\fId\fR\fB\&.type_id\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *\fR\fItype_idstr\fR; +\fI$d\fR\fB\->{\fR\fItype_idstr\fR\fB}\fR; +\fId\fR\fB\&.type_idstr\fR +\fId\fR\fB\&.type_idstr\fR +.fi +.if n \{\ +.RE +.\} +.sp +The key type of the value that was matched, either as id or string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fIid\fR; +\fI$d\fR\fB\->{id}\fR +\fId\fR\fB\&.id\fR +\fId\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fIidstr\fR; +\fI$d\fR\fB\->{idstr}\fR +\fId\fR\fB\&.idstr\fR +\fId\fR\fB\&.idstr\fR +.fi +.if n \{\ +.RE +.\} +.sp +The Id of the value that was matched (only valid for id types), either as id or string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *\fR\fIstr\fR; +\fI$d\fR\fB\->{str}\fR +\fId\fR\fB\&.str\fR +\fId\fR\fB\&.str\fR +.fi +.if n \{\ +.RE +.\} +.sp +The string value that was matched (only valid for string types)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned long long\fR \fInum\fR; +\fI$d\fR\fB\->{num}\fR +\fId\fR\fB\&.num\fR +\fId\fR\fB\&.num\fR +.fi +.if n \{\ +.RE +.\} +.sp +The numeric value that was matched (only valid for numeric types)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned int\fR \fInum2\fR; +\fI$d\fR\fB\->{num2}\fR +\fId\fR\fB\&.num2\fR +\fId\fR\fB\&.num2\fR +.fi +.if n \{\ +.RE +.\} +.sp +The secondary numeric value that was matched (only valid for types containing two values)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned int\fR \fIbinary\fR; +\fI$d\fR\fB\->{binary}\fR +\fId\fR\fB\&.binary\fR +\fId\fR\fB\&.binary\fR +.fi +.if n \{\ +.RE +.\} +.sp +The value in binary form, useful for checksums and other data that cannot be represented as a string\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDatapos pos()\fR; +my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->pos()\fR; +\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR +\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR +.fi +.if n \{\ +.RE +.\} +.sp +The position object of the current match\&. It can be used to do sub\-searches starting at the match (if it is of an array type)\&. See the Datapos class for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDatapos parentpos()\fR; +my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->parentpos()\fR; +\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR +\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR +.fi +.if n \{\ +.RE +.\} +.sp +The position object of the array containing the current match\&. It can be used to do sub\-searches, see the Datapos class for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$d\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fId\fR\fB)\fR +\fIstr\fR \fB=\fR \fId\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the stringification of the matched value\&. Stringification depends on the search flags, for file list entries it will return just the base name unless SEARCH_FILES is used, for checksums it will return an empty string unless SEARCH_CHECKSUMS is used\&. Numeric values are currently stringified to an empty string\&. +.SH "THE SELECTION CLASS" +.sp +Selections are a way to easily deal with sets of packages\&. There are multiple constructors to create them, the most useful is probably the select() method in the Pool class\&. +.SS "CONSTANTS" +.PP +\fBSELECTION_NAME\fR +.RS 4 +Create the selection by matching package names\&. +.RE +.PP +\fBSELECTION_PROVIDES\fR +.RS 4 +Create the selection by matching package provides\&. +.RE +.PP +\fBSELECTION_FILELIST\fR +.RS 4 +Create the selection by matching package files\&. +.RE +.PP +\fBSELECTION_CANON\fR +.RS 4 +Create the selection by matching the canonical representation of the package\&. This is normally a combination of the name, the version, and the architecture of a package\&. +.RE +.PP +\fBSELECTION_DOTARCH\fR +.RS 4 +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 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 +.RS 4 +Limit the package search to installed packages\&. +.RE +.PP +\fBSELECTION_SOURCE_ONLY\fR +.RS 4 +Limit the package search to source packages only\&. +.RE +.PP +\fBSELECTION_WITH_SOURCE\fR +.RS 4 +Extend the package search to also match source packages\&. The default is only to match binary packages\&. +.RE +.PP +\fBSELECTION_WITH_DISABLED\fR +.RS 4 +Extend the package search to also include disabled packages\&. +.RE +.PP +\fBSELECTION_WITH_BADARCH\fR +.RS 4 +Extend the package search to also include packages that are not installable on the configured architecture\&. +.RE +.PP +\fBSELECTION_WITH_ALL\fR +.RS 4 +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 +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$d\fR\fB\->{pool}\fR +\fId\fR\fB\&.pool\fR +\fId\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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 +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 +\fI$sel\fR\fB\->isempty()\fR +\fIsel\fR\fB\&.isempty()\fR +\fIsel\fR\fB\&.isempty?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return true if the selection is empty, i\&.e\&. no package could be matched\&. +.sp +.if n \{\ +.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 +\fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Intersect two selections\&. Packages will only stay in the selection if there are also included in the other selecting\&. Does an in\-place modification\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add(Selection *\fR\fIother\fR\fB)\fR +\fI$sel\fR\fB\->add(\fR\fI$other\fR\fB)\fR; +\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR +\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Build the union of two selections\&. All packages of the other selection will 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\&. +.sp +.if n \{\ +.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 +\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fBJob *jobs(int\fR \fIaction\fR\fB)\fR +my \fI@jobs\fR \fB=\fR \fI$sel\fR\fB\->jobs(\fR\fI$action\fR\fB)\fR; +\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR +\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convert a selection into an array of Job objects\&. The action parameter is or\-ed to the \(lqhow\(rq part of the job, it describes the type of job (e\&.g\&. install, erase)\&. See the Job class for the action and action modifier constants\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *solvables()\fR +my \fI@solvables\fR \fB=\fR \fI$sel\fR\fB\->solvables()\fR; +\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR +\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convert a selection into an array of Solvable objects\&. +.sp +.if n \{\ +.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 +\fBvoid matchsolvable(Solvable\fR \fIsolvable\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR +\fI$sel\fR\fB\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Do a matchsolvable 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 +\fIstr\fR \fB=\fR \fIsel\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the selection\&. +.SH "THE JOB CLASS" +.sp +Jobs are the way to specify to the dependency solver what to do\&. Most of the times jobs will get created by calling the jobs() method on a Selection object, but there is also a Job() constructor in the Pool class\&. +.SS "CONSTANTS" +.sp +Selection constants: +.PP +\fBSOLVER_SOLVABLE\fR +.RS 4 +The \(lqwhat\(rq part is the id of a solvable\&. +.RE +.PP +\fBSOLVER_SOLVABLE_NAME\fR +.RS 4 +The \(lqwhat\(rq part is the id of a package name\&. +.RE +.PP +\fBSOLVER_SOLVABLE_PROVIDES\fR +.RS 4 +The \(lqwhat\(rq part is the id of a package provides\&. +.RE +.PP +\fBSOLVER_SOLVABLE_ONE_OF\fR +.RS 4 +The \(lqwhat\(rq part is an offset into the \(lqwhatprovides\(rq data, created by calling the towhatprovides() pool method\&. +.RE +.PP +\fBSOLVER_SOLVABLE_REPO\fR +.RS 4 +The \(lqwhat\(rq part is the id of a repository\&. +.RE +.PP +\fBSOLVER_SOLVABLE_ALL\fR +.RS 4 +The \(lqwhat\(rq part is ignored, all packages are selected\&. +.RE +.PP +\fBSOLVER_SOLVABLE_SELECTMASK\fR +.RS 4 +A mask containing all the above selection bits\&. +.RE +.sp +Action constants: +.PP +\fBSOLVER_NOOP\fR +.RS 4 +Do nothing\&. +.RE +.PP +\fBSOLVER_INSTALL\fR +.RS 4 +Install a package of the specified set of packages\&. It tries to install the best matching package (i\&.e\&. the highest version of the packages from the repositories with the highest priority)\&. +.RE +.PP +\fBSOLVER_ERASE\fR +.RS 4 +Erase all of the packages from the specified set\&. If a package is not installed, erasing it will keep it from getting installed\&. +.RE +.PP +\fBSOLVER_UPDATE\fR +.RS 4 +Update the matching installed packages to their best version\&. If none of the specified packages are installed, try to update the installed packages to the specified versions\&. See the section about targeted updates about more information\&. +.RE +.PP +\fBSOLVER_WEAKENDEPS\fR +.RS 4 +Allow to break the dependencies of the matching packages\&. Handle with care\&. +.RE +.PP +\fBSOLVER_MULTIVERSION\fR +.RS 4 +Mark the matched packages for multiversion install\&. If they get to be installed because of some other job, the installation will keep the old version of the package installed (for rpm this is done by using \(lq\-i\(rq instead of \(lq\-U\(rq)\&. +.RE +.PP +\fBSOLVER_LOCK\fR +.RS 4 +Do not change the state of the matched packages, i\&.e\&. when they are installed they stay installed, if not they are not selected for installation\&. +.RE +.PP +\fBSOLVER_DISTUPGRADE\fR +.RS 4 +Update the matching installed packages to the best version included in one of the repositories\&. After this operation, all come from one of the available repositories except orphaned packages\&. Orphaned packages are packages that have no relation to the packages in the repositories, i\&.e\&. no package in the repositories have the same name or obsolete the orphaned package\&. This action brings the installed packages in sync with the ones in the repository\&. By default it also turns of arch/vendor/version locking for the affected packages to simulate a fresh installation\&. This means that distupgrade can actually downgrade packages if only lower versions of a package are available in the repositories\&. You can tweak this behavior with the SOLVER_FLAG_DUP_ solver flags\&. +.RE +.PP +\fBSOLVER_DROP_ORPHANED\fR +.RS 4 +Erase all the matching installed packages if they are orphaned\&. This only makes sense if there is a \(lqdistupgrade all packages\(rq job\&. The default is to erase orphaned packages only if they block the installation of other packages\&. +.RE +.PP +\fBSOLVER_VERIFY\fR +.RS 4 +Fix dependency problems of matching installed packages\&. The default is to ignore dependency problems for installed packages\&. +.RE +.PP +\fBSOLVER_USERINSTALLED\fR +.RS 4 +The matching installed packages are considered to be installed by a user, thus not installed to fulfill some dependency\&. This is needed input for the calculation of unneeded packages for jobs that have the SOLVER_CLEANDEPS flag set\&. +.RE +.PP +\fBSOLVER_ALLOWUNINSTALL\fR +.RS 4 +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\&. +.RE +.sp +Action modifier constants: +.PP +\fBSOLVER_WEAK\fR +.RS 4 +Makes the job a weak job\&. The solver tries to fulfill weak jobs, but does not report a problem if it is not possible to do so\&. +.RE +.PP +\fBSOLVER_ESSENTIAL\fR +.RS 4 +Makes the job an essential job\&. If there is a problem with the job, the solver will not propose to remove the job as one solution (unless all other solutions are also to remove essential jobs)\&. +.RE +.PP +\fBSOLVER_CLEANDEPS\fR +.RS 4 +The solver will try to also erase all packages dragged in through dependencies when erasing the package\&. This needs SOLVER_USERINSTALLED jobs to maximize user satisfaction\&. +.RE +.PP +\fBSOLVER_FORCEBEST\fR +.RS 4 +Insist on the best package for install, update, and distupgrade jobs\&. If this flag is not used, the solver will use the second\-best package if the best package cannot be installed for some reason\&. When this flag is used, the solver will generate a problem instead\&. +.RE +.PP +\fBSOLVER_TARGETED\fR +.RS 4 +Forces targeted operation update and distupgrade jobs\&. See the section about targeted updates about more information\&. +.RE +.sp +Set constants\&. +.PP +\fBSOLVER_SETEV\fR +.RS 4 +The job specified the exact epoch and version of the package set\&. +.RE +.PP +\fBSOLVER_SETEVR\fR +.RS 4 +The job specified the exact epoch, version, and release of the package set\&. +.RE +.PP +\fBSOLVER_SETARCH\fR +.RS 4 +The job specified the exact architecture of the packages from the set\&. +.RE +.PP +\fBSOLVER_SETVENDOR\fR +.RS 4 +The job specified the exact vendor of the packages from the set\&. +.RE +.PP +\fBSOLVER_SETREPO\fR +.RS 4 +The job specified the exact repository of the packages from the set\&. +.RE +.PP +\fBSOLVER_SETNAME\fR +.RS 4 +The job specified the exact name of the packages from the set\&. +.RE +.PP +\fBSOLVER_NOAUTOSET\fR +.RS 4 +Turn of automatic set flag generation for SOLVER_SOLVABLE jobs\&. +.RE +.PP +\fBSOLVER_SETMASK\fR +.RS 4 +A mask containing all the above set bits\&. +.RE +.sp +See the section about set bits for more information\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$job\fR\fB\->{pool}\fR +\fId\fR\fB\&.pool\fR +\fId\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId how;\fR /* read/write */ +\fI$job\fR\fB\->{how}\fR +\fId\fR\fB\&.how\fR +\fId\fR\fB\&.how\fR +.fi +.if n \{\ +.RE +.\} +.sp +Union of the selection, action, action modifier, and set flags\&. The selection part describes the semantics of the \(lqwhat\(rq Id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId what;\fR /* read/write */ +\fI$job\fR\fB\->{what}\fR +\fId\fR\fB\&.what\fR +\fId\fR\fB\&.what\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id describing the set of packages, the meaning depends on the selection part of the \(lqhow\(rq attribute\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *solvables()\fR +my \fI@solvables\fR \fB=\fR \fI$job\fR\fB\->solvables()\fR; +\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR +\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the set of solvables of the job as an array of Solvable objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool isemptyupdate()\fR; +\fI$job\fR\fB\->isemptyupdate()\fR +\fIjob\fR\fB\&.isemptyupdate()\fR +\fIjob\fR\fB\&.isemptyupdate?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Convenience function to find out if the job describes an update job with no matching packages, i\&.e\&. a job that does nothing\&. Some package managers like \(lqzypper\(rq like to turn those jobs into install jobs, i\&.e\&. an update of a not\-installed package will result into the installation of the package\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$job\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIjob\fR\fB)\fR +\fIstr\fR \fB=\fR \fIjob\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the job\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$job1\fR \fB==\fR \fI$job2\fR\fB)\fR +\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR\fB:\fR +\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Two jobs are equal if they belong to the same pool and both the \(lqhow\(rq and the \(lqwhat\(rq attributes are the same\&. +.SS "TARGETED UPDATES" +.sp +Libsolv has two modes for upgrades and distupgrade: targeted and untargeted\&. Untargeted mode means that the installed packages from the specified set will be updated to the best version\&. Targeted means that packages that can be updated to a package in the specified set will be updated to the best package of the set\&. +.sp +Here\(cqs an example to explain the subtle difference\&. Suppose that you have package A installed in version "1\&.1", "A\-1\&.2" is available in one of the repositories and there is also package "B" that obsoletes package A\&. +.sp +An untargeted update of "A" will update the installed "A\-1\&.1" to package "B", because that is the newest version (B obsoletes A and is thus newer)\&. +.sp +A targeted update of "A" will update "A\-1\&.1" to "A\-1\&.2", as the set of packages contains both "A\-1\&.1" and "A\-1\&.2", and "A\-1\&.2" is the newer one\&. +.sp +An untargeted update of "B" will do nothing, as "B" is not installed\&. +.sp +An targeted update of "B" will update "A\-1\&.1" to "B"\&. +.sp +Note that the default is to do "auto\-targeting", thus if the specified set of packages does not include an installed package, the solver will assume targeted operation even if SOLVER_TARGETED is not used\&. +.sp +This mostly matches the intent of the user, with one exception: In the example above, an update of "A\-1\&.2" will update "A\-1\&.1" to "A\-1\&.2" (targeted mode), but a second update of "A\-1\&.2" will suddenly update to "B", as untargeted mode is chosen because "A\-1\&.2" is now installed\&. +.sp +If you want to have full control over when targeting mode is chosen, turn off auto\-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option\&. In that case, all updates are considered to be untargeted unless they include the SOLVER_TARGETED flag\&. +.SS "SET BITS" +.sp +Set bits specify which parts of the specified packages where specified by the user\&. It is used by the solver when checking if an operation is allowed or not\&. For example, the solver will normally not allow the downgrade of an installed package\&. But it will not report a problem if the SOLVER_SETEVR flag is used, as it then assumes that the user specified the exact version and thus knows what he is doing\&. +.sp +So if a package "screen\-1\-1" is installed for the x86_64 architecture and version "2\-1" is only available for the i586 architecture, installing package "screen\-2\&.1" will ask the user for confirmation because of the different architecture\&. When using the Selection class to create jobs the set bits are automatically added, e\&.g\&. selecting \(lqscreen\&.i586\(rq will automatically add SOLVER_SETARCH, and thus no problem will be reported\&. +.SH "THE SOLVER CLASS" +.sp +Dependency solving is what this library is about\&. A solver object is needed for solving to store the result of the solver run\&. The solver object can be used multiple times for different jobs, reusing it allows the solver to re\-use the dependency rules it already computed\&. +.SS "CONSTANTS" +.sp +Flags to modify some of the solver\(cqs behavior: +.PP +\fBSOLVER_FLAG_ALLOW_DOWNGRADE\fR +.RS 4 +Allow the solver to downgrade packages without asking for confirmation (i\&.e\&. reporting a problem)\&. +.RE +.PP +\fBSOLVER_FLAG_ALLOW_ARCHCHANGE\fR +.RS 4 +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\&. +.RE +.PP +\fBSOLVER_FLAG_ALLOW_VENDORCHANGE\fR +.RS 4 +Allow the solver to change the vendor of an installed package without asking for confirmation\&. Each vendor is part of one or more vendor equivalence classes, normally installed packages may only change their vendor if the new vendor shares at least one equivalence class\&. +.RE +.PP +\fBSOLVER_FLAG_ALLOW_NAMECHANGE\fR +.RS 4 +Allow the solver to change the name of an installed package, i\&.e\&. install a package with a different name that obsoletes the installed package\&. This option is on by default\&. +.RE +.PP +\fBSOLVER_FLAG_ALLOW_UNINSTALL\fR +.RS 4 +Allow the solver to erase installed packages to fulfill the jobs\&. This flag also includes the above flags\&. You may want to set this flag if you only have SOLVER_ERASE jobs, as in that case it\(cqs better for the user to check the transaction overview instead of approving every single package that needs to be erased\&. +.RE +.PP +\fBSOLVER_FLAG_DUP_ALLOW_DOWNGRADE\fR +.RS 4 +Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode\&. +.RE +.PP +\fBSOLVER_FLAG_DUP_ALLOW_ARCHCHANGE\fR +.RS 4 +Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode\&. +.RE +.PP +\fBSOLVER_FLAG_DUP_ALLOW_VENDORCHANGE\fR +.RS 4 +Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode\&. +.RE +.PP +\fBSOLVER_FLAG_DUP_ALLOW_NAMECHANGE\fR +.RS 4 +Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode\&. +.RE +.PP +\fBSOLVER_FLAG_NO_UPDATEPROVIDE\fR +.RS 4 +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\&. +.RE +.PP +\fBSOLVER_FLAG_IGNORE_RECOMMENDED\fR +.RS 4 +Do not process optional (aka weak) dependencies\&. +.RE +.PP +\fBSOLVER_FLAG_ADD_ALREADY_RECOMMENDED\fR +.RS 4 +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\&. +.RE +.PP +\fBSOLVER_FLAG_NO_INFARCHCHECK\fR +.RS 4 +Turn off the inferior architecture checking that is normally done by the solver\&. Normally, the solver allows only the installation of packages from the "best" architecture if a package is available for multiple architectures\&. +.RE +.PP +\fBSOLVER_FLAG_BEST_OBEY_POLICY\fR +.RS 4 +Make the SOLVER_FORCEBEST job option consider only packages that meet the policies for installed packages, i\&.e\&. no downgrades, no architecture change, no vendor change (see the first flags of this section)\&. If the flag is not specified, the solver will enforce the installation of the best package ignoring the installed packages, which may conflict with the set policy\&. +.RE +.PP +\fBSOLVER_FLAG_NO_AUTOTARGET\fR +.RS 4 +Do not enable auto\-targeting up update and distupgrade jobs\&. See the section on targeted updates for more information\&. +.RE +.PP +\fBSOLVER_FLAG_KEEP_ORPHANS\fR +.RS 4 +Do not allow orphaned packages to be deinstalled if they get in the way of resolving other packages\&. +.RE +.PP +\fBSOLVER_FLAG_BREAK_ORPHANS\fR +.RS 4 +Ignore dependencies of orphaned packages that get in the way of resolving non\-orphaned ones\&. Setting the flag might result in no longer working packages in case they are orphaned\&. +.RE +.PP +\fBSOLVER_FLAG_FOCUS_INSTALLED\fR +.RS 4 +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: +.PP +\fBSOLVER_RULE_UNKNOWN\fR +.RS 4 +A rule of an unknown class\&. You should never encounter those\&. +.RE +.PP +\fBSOLVER_RULE_PKG\fR +.RS 4 +A package dependency rule\&. +.RE +.PP +\fBSOLVER_RULE_UPDATE\fR +.RS 4 +A rule to implement the update policy of installed packages\&. Every installed package has an update rule that consists of the packages that may replace the installed package\&. +.RE +.PP +\fBSOLVER_RULE_FEATURE\fR +.RS 4 +Feature rules are fallback rules used when an update rule is disabled\&. They include all packages that may replace the installed package ignoring the update policy, i\&.e\&. they contain downgrades, arch changes and so on\&. Without them, the solver would simply erase installed packages if their update rule gets disabled\&. +.RE +.PP +\fBSOLVER_RULE_JOB\fR +.RS 4 +Job rules implement the job given to the solver\&. +.RE +.PP +\fBSOLVER_RULE_DISTUPGRADE\fR +.RS 4 +These are simple negative assertions that make sure that only packages are kept that are also available in one of the repositories\&. +.RE +.PP +\fBSOLVER_RULE_INFARCH\fR +.RS 4 +Infarch rules are also negative assertions, they disallow the installation of packages when there are packages of the same name but with a better architecture\&. +.RE +.PP +\fBSOLVER_RULE_CHOICE\fR +.RS 4 +Choice rules are used to make sure that the solver prefers updating to installing different packages when some dependency is provided by multiple packages with different names\&. The solver may always break choice rules, so you will not see them when a problem is found\&. +.RE +.PP +\fBSOLVER_RULE_LEARNT\fR +.RS 4 +These rules are generated by the solver to keep it from running into the same problem multiple times when it has to backtrack\&. They are the main reason why a sat solver is faster than other dependency solver implementations\&. +.RE +.sp +Special dependency rule types: +.PP +\fBSOLVER_RULE_PKG_NOT_INSTALLABLE\fR +.RS 4 +This rule was added to prevent the installation of a package of an architecture that does not work on the system\&. +.RE +.PP +\fBSOLVER_RULE_PKG_NOTHING_PROVIDES_DEP\fR +.RS 4 +The package contains a required dependency which was not provided by any package\&. +.RE +.PP +\fBSOLVER_RULE_PKG_REQUIRES\fR +.RS 4 +Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case some packages provided the dependency but none of them could be installed due to other dependency issues\&. +.RE +.PP +\fBSOLVER_RULE_PKG_SELF_CONFLICT\fR +.RS 4 +The package conflicts with itself\&. This is not allowed by older rpm versions\&. +.RE +.PP +\fBSOLVER_RULE_PKG_CONFLICTS\fR +.RS 4 +To fulfill the dependencies two packages need to be installed, but one of the packages contains a conflict with the other one\&. +.RE +.PP +\fBSOLVER_RULE_PKG_SAME_NAME\fR +.RS 4 +The dependencies can only be fulfilled by multiple versions of a package, but installing multiple versions of the same package is not allowed\&. +.RE +.PP +\fBSOLVER_RULE_PKG_OBSOLETES\fR +.RS 4 +To fulfill the dependencies two packages need to be installed, but one of the packages obsoletes the other one\&. +.RE +.PP +\fBSOLVER_RULE_PKG_IMPLICIT_OBSOLETES\fR +.RS 4 +To fulfill the dependencies two packages need to be installed, but one of the packages has provides a dependency that is obsoleted by the other one\&. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES flag\&. +.RE +.PP +\fBSOLVER_RULE_PKG_INSTALLED_OBSOLETES\fR +.RS 4 +To fulfill the dependencies a package needs to be installed that is obsoleted by an installed package\&. See the POOL_FLAG_NOINSTALLEDOBSOLETES flag\&. +.RE +.PP +\fBSOLVER_RULE_JOB_NOTHING_PROVIDES_DEP\fR +.RS 4 +The user asked for installation of a package providing a specific dependency, but no available package provides it\&. +.RE +.PP +\fBSOLVER_RULE_JOB_UNKNOWN_PACKAGE\fR +.RS 4 +The user asked for installation of a package with a specific name, but no available package has that name\&. +.RE +.PP +\fBSOLVER_RULE_JOB_PROVIDED_BY_SYSTEM\fR +.RS 4 +The user asked for the erasure of a dependency that is provided by the system (i\&.e\&. for special hardware or language dependencies), this cannot be done with a job\&. +.RE +.PP +\fBSOLVER_RULE_JOB_UNSUPPORTED\fR +.RS 4 +The user asked for something that is not yet implemented, e\&.g\&. the installation of all packages at once\&. +.RE +.sp +Policy error constants +.PP +\fBPOLICY_ILLEGAL_DOWNGRADE\fR +.RS 4 +The solver ask for permission before downgrading packages\&. +.RE +.PP +\fBPOLICY_ILLEGAL_ARCHCHANGE\fR +.RS 4 +The solver ask for permission before changing the architecture of installed packages\&. +.RE +.PP +\fBPOLICY_ILLEGAL_VENDORCHANGE\fR +.RS 4 +The solver ask for permission before changing the vendor of installed packages\&. +.RE +.PP +\fBPOLICY_ILLEGAL_NAMECHANGE\fR +.RS 4 +The solver ask for permission before replacing an installed packages with a package that has a different name\&. +.RE +.sp +Solution element type constants +.PP +\fBSOLVER_SOLUTION_JOB\fR +.RS 4 +The problem can be solved by removing the specified job\&. +.RE +.PP +\fBSOLVER_SOLUTION_POOLJOB\fR +.RS 4 +The problem can be solved by removing the specified job that is defined in the pool\&. +.RE +.PP +\fBSOLVER_SOLUTION_INFARCH\fR +.RS 4 +The problem can be solved by allowing the installation of the specified package with an inferior architecture\&. +.RE +.PP +\fBSOLVER_SOLUTION_DISTUPGRADE\fR +.RS 4 +The problem can be solved by allowing to keep the specified package installed\&. +.RE +.PP +\fBSOLVER_SOLUTION_BEST\fR +.RS 4 +The problem can be solved by allowing to install the specified package that is not the best available package\&. +.RE +.PP +\fBSOLVER_SOLUTION_ERASE\fR +.RS 4 +The problem can be solved by allowing to erase the specified package\&. +.RE +.PP +\fBSOLVER_SOLUTION_REPLACE\fR +.RS 4 +The problem can be solved by allowing to replace the package with some other package\&. +.RE +.PP +\fBSOLVER_SOLUTION_REPLACE_DOWNGRADE\fR +.RS 4 +The problem can be solved by allowing to replace the package with some other package that has a lower version\&. +.RE +.PP +\fBSOLVER_SOLUTION_REPLACE_ARCHCHANGE\fR +.RS 4 +The problem can be solved by allowing to replace the package with some other package that has a different architecture\&. +.RE +.PP +\fBSOLVER_SOLUTION_REPLACE_VENDORCHANGE\fR +.RS 4 +The problem can be solved by allowing to replace the package with some other package that has a different vendor\&. +.RE +.PP +\fBSOLVER_SOLUTION_REPLACE_NAMECHANGE\fR +.RS 4 +The problem can be solved by allowing to replace the package with some other package that has a different name\&. +.RE +.sp +Reason constants +.PP +\fBSOLVER_REASON_UNRELATED\fR +.RS 4 +The package status did not change as it was not related to any job\&. +.RE +.PP +\fBSOLVER_REASON_UNIT_RULE\fR +.RS 4 +The package was installed/erased/kept because of a unit rule, i\&.e\&. a rule where all literals but one were false\&. +.RE +.PP +\fBSOLVER_REASON_KEEP_INSTALLED\fR +.RS 4 +The package was chosen when trying to keep as many packages installed as possible\&. +.RE +.PP +\fBSOLVER_REASON_RESOLVE_JOB\fR +.RS 4 +The decision happened to fulfill a job rule\&. +.RE +.PP +\fBSOLVER_REASON_UPDATE_INSTALLED\fR +.RS 4 +The decision happened to fulfill a package update request\&. +.RE +.PP +\fBSOLVER_REASON_CLEANDEPS_ERASE\fR +.RS 4 +The package was erased when cleaning up dependencies from other erased packages\&. +.RE +.PP +\fBSOLVER_REASON_RESOLVE\fR +.RS 4 +The package was installed to fulfill package dependencies\&. +.RE +.PP +\fBSOLVER_REASON_WEAKDEP\fR +.RS 4 +The package was installed because of a weak dependency (Recommends or Supplements)\&. +.RE +.PP +\fBSOLVER_REASON_RESOLVE_ORPHAN\fR +.RS 4 +The decision about the package was made when deciding the fate of orphaned packages\&. +.RE +.PP +\fBSOLVER_REASON_RECOMMENDED\fR +.RS 4 +This is a special case of SOLVER_REASON_WEAKDEP\&. +.RE +.PP +\fBSOLVER_REASON_SUPPLEMENTED\fR +.RS 4 +This is a special case of SOLVER_REASON_WEAKDEP\&. +.RE +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$job\fR\fB\->{pool}\fR +\fId\fR\fB\&.pool\fR +\fId\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to pool\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR +my \fI$oldvalue\fR \fB=\fR \fI$solver\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR; +\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR +\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint get_flag(int\fR \fIflag\fR\fB)\fR +my \fI$value\fR \fB=\fR \fI$solver\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR; +\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR +\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set/get a solver specific flag\&. The flags define the policies the solver has to obey\&. The flags are explained in the CONSTANTS section of this class\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBProblem *solve(Job *\fR\fIjobs\fR\fB)\fR +my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR; +\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR +\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Solve a problem specified in the job list (plus the jobs defined in the pool)\&. Returns an array of problems that need user interaction, or an empty array if no problems were encountered\&. See the Problem class on how to deal with problems\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBTransaction transaction()\fR +my \fI$trans\fR \fB=\fR \fI$solver\fR\fB\->transaction()\fR; +\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR +\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the transaction to implement the calculated package changes\&. A transaction is available even if problems were found, this is useful for interactive user interfaces that show both the job result and the problems\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint\fR \fIreason\fR \fB= describe_decision(Solvable *\fR\fIs\fR\fB, Rule *\fR\fIOUTPUT\fR\fB)\fR +my \fB(\fR\fI$reason\fR\fB,\fR \fI$rule\fR\fB) =\fR \fI$solver\fR\fB\->describe_decision(\fR\fI$solvable\fR\fB)\fR; +\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR +\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.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\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver *solv;\fR /* read only */ +\fI$problem\fR\fB\->{solv}\fR +\fIproblem\fR\fB\&.solv\fR +\fIproblem\fR\fB\&.solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$problem\fR\fB\->{id}\fR +\fIproblem\fR\fB\&.id\fR +\fIproblem\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the problem\&. The first problem has Id 1, they are numbered consecutively\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRule findproblemrule()\fR +my \fI$probrule\fR \fB=\fR \fI$problem\fR\fB\->findproblemrule()\fR; +\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR +\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the rule that caused the problem\&. Of course in most situations there is no single responsible rule, but many rules that interconnect with each created the problem\&. Nevertheless, the solver uses some heuristic approach to find a rule that somewhat describes the problem best to the user\&. +.sp +.if n \{\ +.RS 4 +.\} +.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\&.findallproblemrules()\fR +\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrules()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all rules responsible for the problem\&. The returned set of rules contains all the needed information why there was a problem, but it\(cqs hard to present them to the user in a sensible way\&. The default is to filter out all update and job rules (unless the returned rules only consist of those types)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolution *solutions()\fR +my \fI@solutions\fR \fB=\fR \fI$problem\fR\fB\->solutions()\fR; +\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR +\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return an array containing multiple possible solutions to fix the problem\&. See the solution class for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint solution_count()\fR +my \fI$cnt\fR \fB=\fR \fI$problem\fR\fB\->solution_count()\fR; +\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR +\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the number of solutions without creating solution objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$problem\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIproblem\fR\fB)\fR +\fIstr\fR \fB=\fR \fIproblem\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a string describing the problem\&. This is a convenience function, it is a shorthand for calling findproblemrule(), then ruleinfo() on the problem rule and problemstr() on the ruleinfo object\&. +.SH "THE RULE CLASS" +.sp +Rules are the basic block of sat solving\&. Each package dependency gets translated into one or multiple rules\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver *solv;\fR /* read only */ +\fI$rule\fR\fB\->{solv}\fR +\fIrule\fR\fB\&.solv\fR +\fIrule\fR\fB\&.solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$rule\fR\fB\->{id}\fR +\fIrule\fR\fB\&.id\fR +\fIrule\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the rule\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint type;\fR /* read only */ +\fI$rule\fR\fB\->{type}\fR +\fIrule\fR\fB\&.type\fR +\fIrule\fR\fB\&.type\fR +.fi +.if n \{\ +.RE +.\} +.sp +The basic type of the rule\&. See the constant section of the solver class for the type list\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRuleinfo info()\fR +my \fI$ruleinfo\fR \fB=\fR \fI$rule\fR\fB\->info()\fR; +\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR +\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a Ruleinfo object that contains information about why the rule was created\&. But see the allinfos() method below\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRuleinfo *allinfos()\fR +my \fI@ruleinfos\fR \fB=\fR \fI$rule\fR\fB\->allinfos()\fR; +\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR +\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR +.fi +.if n \{\ +.RE +.\} +.sp +As the same dependency rule can get created because of multiple dependencies, one Ruleinfo is not enough to describe the reason\&. Thus the allinfos() method returns an array of all infos about a rule\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$rule1\fR \fB==\fR \fI$rule2\fR\fB)\fR +\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR\fB:\fR +\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Two rules are equal if they belong to the same solver and have the same id\&. +.SH "THE RULEINFO CLASS" +.sp +A Ruleinfo describes one reason why a rule was created\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver *solv;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{solv}\fR +\fIruleinfo\fR\fB\&.solv\fR +\fIruleinfo\fR\fB\&.solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint type;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{type}\fR +\fIruleinfo\fR\fB\&.type\fR +\fIruleinfo\fR\fB\&.type\fR +.fi +.if n \{\ +.RE +.\} +.sp +The type of the ruleinfo\&. See the constant section of the solver class for the rule type list and the special type list\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDep *dep;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{dep}\fR +\fIruleinfo\fR\fB\&.dep\fR +\fIruleinfo\fR\fB\&.dep\fR +.fi +.if n \{\ +.RE +.\} +.sp +The dependency leading to the creation of the rule\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDep *dep_id;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{\*(Aqdep_id\*(Aq}\fR +\fIruleinfo\fR\fB\&.dep_id\fR +\fIruleinfo\fR\fB\&.dep_id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The Id of the dependency leading to the creation of the rule, or zero\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *solvable;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{solvable}\fR +\fIruleinfo\fR\fB\&.solvable\fR +\fIruleinfo\fR\fB\&.solvable\fR +.fi +.if n \{\ +.RE +.\} +.sp +The involved Solvable, e\&.g\&. the one containing the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *othersolvable;\fR /* read only */ +\fI$ruleinfo\fR\fB\->{othersolvable}\fR +\fIruleinfo\fR\fB\&.othersolvable\fR +\fIruleinfo\fR\fB\&.othersolvable\fR +.fi +.if n \{\ +.RE +.\} +.sp +The other involved Solvable (if any), e\&.g\&. the one containing providing the dependency for conflicts\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *problemstr()\fR; +my \fI$str\fR \fB=\fR \fI$ruleinfo\fR\fB\->problemstr()\fR; +\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR +\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR +.fi +.if n \{\ +.RE +.\} +.sp +A string describing the ruleinfo from a problem perspective\&. This probably only makes sense if the rule is part of a problem\&. +.SH "THE SOLUTION CLASS" +.sp +A solution solves one specific problem\&. It consists of multiple solution elements that all need to be executed\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver *solv;\fR /* read only */ +\fI$solution\fR\fB\->{solv}\fR +\fIsolution\fR\fB\&.solv\fR +\fIsolution\fR\fB\&.solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId problemid;\fR /* read only */ +\fI$solution\fR\fB\->{problemid}\fR +\fIsolution\fR\fB\&.problemid\fR +\fIsolution\fR\fB\&.problemid\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the problem the solution solves\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$solution\fR\fB\->{id}\fR +\fIsolution\fR\fB\&.id\fR +\fIsolution\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the solution\&. The first solution has Id 1, they are numbered consecutively\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolutionelement *elements(bool\fR \fIexpandreplaces\fR \fB= 0)\fR +my \fI@solutionelements\fR \fB=\fR \fI$solution\fR\fB\->elements()\fR; +\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR +\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return an array containing the elements describing what needs to be done to implement the specific solution\&. If expandreplaces is true, elements of type SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace elements describing the policy mismatches\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint element_count()\fR +my \fI$cnt\fR \fB=\fR \fI$solution\fR\fB\->solution_count()\fR; +\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR +\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the number of solution elements without creating objects\&. Note that the count does not match the number of objects returned by the elements() method of expandreplaces is set to true\&. +.SH "THE SOLUTIONELEMENT CLASS" +.sp +A solution element describes a single action of a solution\&. The action is always either to remove one specific job or to add a new job that installs or erases a single specific package\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolver *solv;\fR /* read only */ +\fI$solutionelement\fR\fB\->{solv}\fR +\fIsolutionelement\fR\fB\&.solv\fR +\fIsolutionelement\fR\fB\&.solv\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to solver object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId problemid;\fR /* read only */ +\fI$solutionelement\fR\fB\->{problemid}\fR +\fIsolutionelement\fR\fB\&.problemid\fR +\fIsolutionelement\fR\fB\&.problemid\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the problem the element (partly) solves\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId solutionid;\fR /* read only */ +\fI$solutionelement\fR\fB\->{solutionid}\fR +\fIsolutionelement\fR\fB\&.solutionid\fR +\fIsolutionelement\fR\fB\&.solutionid\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the solution the element is a part of\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$solutionelement\fR\fB\->{id}\fR +\fIsolutionelement\fR\fB\&.id\fR +\fIsolutionelement\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +Id of the solution element\&. The first element has Id 1, they are numbered consecutively\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId type;\fR /* read only */ +\fI$solutionelement\fR\fB\->{type}\fR +\fIsolutionelement\fR\fB\&.type\fR +\fIsolutionelement\fR\fB\&.type\fR +.fi +.if n \{\ +.RE +.\} +.sp +Type of the solution element\&. See the constant section of the solver class for the existing types\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *solvable;\fR /* read only */ +\fI$solutionelement\fR\fB\->{solvable}\fR +\fIsolutionelement\fR\fB\&.solvable\fR +\fIsolutionelement\fR\fB\&.solvable\fR +.fi +.if n \{\ +.RE +.\} +.sp +The installed solvable that needs to be replaced for replacement elements\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *replacement;\fR /* read only */ +\fI$solutionelement\fR\fB\->{replacement}\fR +\fIsolutionelement\fR\fB\&.replacement\fR +\fIsolutionelement\fR\fB\&.replacement\fR +.fi +.if n \{\ +.RE +.\} +.sp +The solvable that needs to be installed to fix the problem\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint jobidx;\fR /* read only */ +\fI$solutionelement\fR\fB\->{jobidx}\fR +\fIsolutionelement\fR\fB\&.jobidx\fR +\fIsolutionelement\fR\fB\&.jobidx\fR +.fi +.if n \{\ +.RE +.\} +.sp +The index of the job that needs to be removed to fix the problem, or \-1 if the element is of another type\&. Note that it\(cqs better to change the job to SOLVER_NOOP type so that the numbering of other elements does not get disturbed\&. This method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolutionelement *replaceelements()\fR +my \fI@solutionelements\fR \fB=\fR \fI$solutionelement\fR\fB\->replaceelements()\fR; +\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR +\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR +.fi +.if n \{\ +.RE +.\} +.sp +If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of elements describing the policy mismatches, otherwise return a copy of the element\&. See also the \(lqexpandreplaces\(rq option in the solution\(cqs elements() method\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint illegalreplace()\fR +my \fI$illegal\fR \fB=\fR \fI$solutionelement\fR\fB\->illegalreplace()\fR; +\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR +\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return an integer that contains the policy mismatch bits or\-ed together, or zero if there was no policy mismatch\&. See the policy error constants in the solver class\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBJob Job()\fR +my \fI$job\fR \fB=\fR \fI$solutionelement\fR\fB\->Job()\fR; +\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR +\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR +.fi +.if n \{\ +.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 latter two, a SOLVER_NOOB Job is created, you should replace the old job with the new one\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *str()\fR +my \fI$str\fR \fB=\fR \fI$solutionelement\fR\fB\->str()\fR; +\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR +\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR +.fi +.if n \{\ +.RE +.\} +.sp +A string describing the change the solution element consists of\&. +.SH "THE TRANSACTION CLASS" +.sp +Transactions describe the output of a solver run\&. A transaction contains a number of transaction elements, each either the installation of a new package or the removal of an already installed package\&. The Transaction class supports a classify() method that puts the elements into different groups so that a transaction can be presented to the user in a meaningful way\&. +.SS "CONSTANTS" +.sp +Transaction element types, both active and passive +.PP +\fBSOLVER_TRANSACTION_IGNORE\fR +.RS 4 +This element does nothing\&. Used to map element types that do not match the view mode\&. +.RE +.PP +\fBSOLVER_TRANSACTION_INSTALL\fR +.RS 4 +This element installs a package\&. +.RE +.PP +\fBSOLVER_TRANSACTION_ERASE\fR +.RS 4 +This element erases a package\&. +.RE +.PP +\fBSOLVER_TRANSACTION_MULTIINSTALL\fR +.RS 4 +This element installs a package with a different version keeping the other versions installed\&. +.RE +.PP +\fBSOLVER_TRANSACTION_MULTIREINSTALL\fR +.RS 4 +This element reinstalls an installed package keeping the other versions installed\&. +.RE +.sp +Transaction element types, active view +.PP +\fBSOLVER_TRANSACTION_REINSTALL\fR +.RS 4 +This element re\-installs a package, i\&.e\&. installs the same package again\&. +.RE +.PP +\fBSOLVER_TRANSACTION_CHANGE\fR +.RS 4 +This element installs a package with same name, version, architecture but different content\&. +.RE +.PP +\fBSOLVER_TRANSACTION_UPGRADE\fR +.RS 4 +This element installs a newer version of an installed package\&. +.RE +.PP +\fBSOLVER_TRANSACTION_DOWNGRADE\fR +.RS 4 +This element installs an older version of an installed package\&. +.RE +.PP +\fBSOLVER_TRANSACTION_OBSOLETES\fR +.RS 4 +This element installs a package that obsoletes an installed package\&. +.RE +.sp +Transaction element types, passive view +.PP +\fBSOLVER_TRANSACTION_REINSTALLED\fR +.RS 4 +This element re\-installs a package, i\&.e\&. installs the same package again\&. +.RE +.PP +\fBSOLVER_TRANSACTION_CHANGED\fR +.RS 4 +This element replaces an installed package with one of the same name, version, architecture but different content\&. +.RE +.PP +\fBSOLVER_TRANSACTION_UPGRADED\fR +.RS 4 +This element replaces an installed package with a new version\&. +.RE +.PP +\fBSOLVER_TRANSACTION_DOWNGRADED\fR +.RS 4 +This element replaces an installed package with an old version\&. +.RE +.PP +\fBSOLVER_TRANSACTION_OBSOLETED\fR +.RS 4 +This element replaces an installed package with a package that obsoletes it\&. +.RE +.sp +Pseudo element types for showing extra information used by classify() +.PP +\fBSOLVER_TRANSACTION_ARCHCHANGE\fR +.RS 4 +This element replaces an installed package with a package of a different architecture\&. +.RE +.PP +\fBSOLVER_TRANSACTION_VENDORCHANGE\fR +.RS 4 +This element replaces an installed package with a package of a different vendor\&. +.RE +.sp +Transaction mode flags +.PP +\fBSOLVER_TRANSACTION_SHOW_ACTIVE\fR +.RS 4 +Filter for active view types\&. The default is to return passive view type, i\&.e\&. to show how the installed packages get changed\&. +.RE +.PP +\fBSOLVER_TRANSACTION_SHOW_OBSOLETES\fR +.RS 4 +Do not map the obsolete view type into INSTALL/ERASE elements\&. +.RE +.PP +\fBSOLVER_TRANSACTION_SHOW_ALL\fR +.RS 4 +If multiple packages replace an installed package, only the best of them is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE elements\&. This is because most applications want to show just one package replacing the installed one\&. The SOLVER_TRANSACTION_SHOW_ALL makes the library keep all OBSOLETE elements\&. +.RE +.PP +\fBSOLVER_TRANSACTION_SHOW_MULTIINSTALL\fR +.RS 4 +The library maps MULTIINSTALL elements to simple INSTALL elements\&. This flag can be used to disable the mapping\&. +.RE +.PP +\fBSOLVER_TRANSACTION_CHANGE_IS_REINSTALL\fR +.RS 4 +Use this flag if you want to map CHANGE elements to the REINSTALL type\&. +.RE +.PP +\fBSOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE\fR +.RS 4 +Use this flag if you want to map OBSOLETE elements to the UPGRADE type\&. +.RE +.PP +\fBSOLVER_TRANSACTION_MERGE_ARCHCHANGES\fR +.RS 4 +Do not add extra categories for every architecture change, instead cumulate them in one category\&. +.RE +.PP +\fBSOLVER_TRANSACTION_MERGE_VENDORCHANGES\fR +.RS 4 +Do not add extra categories for every vendor change, instead cumulate them in one category\&. +.RE +.PP +\fBSOLVER_TRANSACTION_RPM_ONLY\fR +.RS 4 +Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL elements\&. Useful if you want to find out what to feed to the underlying package manager\&. +.RE +.sp +Transaction order flags +.PP +\fBSOLVER_TRANSACTION_KEEP_ORDERDATA\fR +.RS 4 +Do not throw away the dependency graph used for ordering the transaction\&. This flag is needed if you want to do manual ordering\&. +.RE +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool;\fR /* read only */ +\fI$trans\fR\fB\->{pool}\fR +\fItrans\fR\fB\&.pool\fR +\fItrans\fR\fB\&.pool\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to pool\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool isempty()\fR; +\fI$trans\fR\fB\->isempty()\fR +\fItrans\fR\fB\&.isempty()\fR +\fItrans\fR\fB\&.isempty?\fR +.fi +.if n \{\ +.RE +.\} +.sp +Returns true if the transaction does not do anything, i\&.e\&. has no elements\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *newsolvables()\fR; +my \fI@newsolvables\fR \fB=\fR \fI$trans\fR\fB\->newsolvables()\fR; +\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR +\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all packages that are to be installed by the transaction\&. These are the packages that need to be downloaded from the repositories\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *keptsolvables()\fR; +my \fI@keptsolvables\fR \fB=\fR \fI$trans\fR\fB\->keptsolvables()\fR; +\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR +\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all installed packages that the transaction will keep installed\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *steps()\fR; +my \fI@steps\fR \fB=\fR \fI$trans\fR\fB\->steps()\fR; +\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR +\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return all solvables that need to be installed (if the returned solvable is not already installed) or erased (if the returned solvable is installed)\&. A step is also called a transaction element\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint steptype(Solvable *\fR\fIsolvable\fR\fB, int\fR \fImode\fR\fB)\fR +my \fI$type\fR \fB=\fR \fI$trans\fR\fB\->steptype(\fR\fI$solvable\fR\fB,\fR \fI$mode\fR\fB)\fR; +\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR +\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the transaction type of the specified solvable\&. See the CONSTANTS sections for the mode argument flags and the list of returned types\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBTransactionClass *classify(int\fR \fImode\fR \fB= 0)\fR +my \fI@classes\fR \fB=\fR \fI$trans\fR\fB\->classify()\fR; +\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR +\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Group the transaction elements into classes so that they can be displayed in a structured way\&. You can use various mapping mode flags to tweak the result to match your preferences, see the mode argument flag in the CONSTANTS section\&. See the TransactionClass class for how to deal with the returned objects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable othersolvable(Solvable *\fR\fIsolvable\fR\fB)\fR; +my \fI$other\fR \fB=\fR \fI$trans\fR\fB\->othersolvable(\fR\fI$solvable\fR\fB)\fR; +\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR +\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the \(lqother\(rq solvable for a given solvable\&. For installed packages the other solvable is the best package with the same name that replaces the installed package, or the best package of the obsoleting packages if the package does not get replaced by one with the same name\&. +.sp +For to be installed packages, the \(lqother\(rq solvable is the best installed package with the same name that will be replaced, or the best packages of all the packages that are obsoleted if the new package does not replace a package with the same name\&. +.sp +Thus, the \(lqother\(rq solvable is normally the package that is also shown for a given package\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *allothersolvables(Solvable *\fR\fIsolvable\fR\fB)\fR; +my \fI@others\fR \fB=\fR \fI$trans\fR\fB\->allothersolvables(\fR\fI$solvable\fR\fB)\fR; +\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR +\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +For installed packages, returns all of the packages that replace us\&. For to be installed packages, returns all of the packages that the new package replaces\&. The special \(lqother\(rq solvable is always the first entry of the returned array\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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 +.fi +.if n \{\ +.RE +.\} +.sp +Return the size change of the installed system in kilobytes (kibibytes)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid order(int\fR \fIflags\fR \fB= 0)\fR; +\fI$trans\fR\fB\->order()\fR; +\fItrans\fR\fB\&.order()\fR +\fItrans\fR\fB\&.order()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Order the steps in the transactions so that dependent packages are updated before packages that depend on them\&. For rpm, you can also use rpmlib\(cqs ordering functionality, debian\(cqs dpkg does not provide a way to order a transaction\&. +.SS "ACTIVE/PASSIVE VIEW" +.sp +Active view lists what new packages get installed, while passive view shows what happens to the installed packages\&. Most often there\(cqs not much difference between the two modes, but things get interesting if multiple packages get replaced by one new package\&. Say you have installed packages A\-1\-1 and B\-1\-1, and now install A\-2\-1 which has a new dependency that obsoletes B\&. The transaction elements will be +.sp +.if n \{\ +.RS 4 +.\} +.nf +updated A\-1\-1 (other: A\-2\-1) +obsoleted B\-1\-1 (other: A\-2\-1) +.fi +.if n \{\ +.RE +.\} +.sp +in passive mode, but +.sp +.if n \{\ +.RS 4 +.\} +.nf +update A\-2\-1 (other: A\-1\-1) +erase B +.fi +.if n \{\ +.RE +.\} +.sp +in active mode\&. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the passive mode list will be unchanged but the active mode list will just contain A\-2\-1\&. +.SH "THE TRANSACTIONCLASS CLASS" +.sp +Objects of this type are returned by the classify() Transaction method\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBTransaction *transaction;\fR /* read only */ +\fI$class\fR\fB\->{transaction}\fR +\fIclass\fR\fB\&.transaction\fR +\fIclass\fR\fB\&.transaction\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to transaction object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint type;\fR /* read only */ +\fI$class\fR\fB\->{type}\fR +\fIclass\fR\fB\&.type\fR +\fIclass\fR\fB\&.type\fR +.fi +.if n \{\ +.RE +.\} +.sp +The type of the transaction elements in the class\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint count;\fR /* read only */ +\fI$class\fR\fB\->{count}\fR +\fIclass\fR\fB\&.count\fR +\fIclass\fR\fB\&.count\fR +.fi +.if n \{\ +.RE +.\} +.sp +The number of elements in the class\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *\fR\fIfromstr\fR; +\fI$class\fR\fB\->{fromstr}\fR +\fIclass\fR\fB\&.fromstr\fR +\fIclass\fR\fB\&.fromstr\fR +.fi +.if n \{\ +.RE +.\} +.sp +The old vendor or architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *\fR\fItostr\fR; +\fI$class\fR\fB\->{tostr}\fR +\fIclass\fR\fB\&.tostr\fR +\fIclass\fR\fB\&.tostr\fR +.fi +.if n \{\ +.RE +.\} +.sp +The new vendor or architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fIfromid\fR; +\fI$class\fR\fB\->{fromid}\fR +\fIclass\fR\fB\&.fromid\fR +\fIclass\fR\fB\&.fromid\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the old vendor or architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId\fR \fItoid\fR; +\fI$class\fR\fB\->{toid}\fR +\fIclass\fR\fB\&.toid\fR +\fIclass\fR\fB\&.toid\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the new vendor or architecture\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid solvables()\fR; +my \fI@solvables\fR \fB=\fR \fI$class\fR\fB\->solvables()\fR; +\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR +\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the solvables for all transaction elements in the class\&. +.SH "CHECKSUMS" +.sp +Checksums (also called hashes) are used to make sure that downloaded data is not corrupt and also as a fingerprint mechanism to check if data has changed\&. +.SS "CLASS METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum Chksum(Id\fR \fItype\fR\fB)\fR +my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB)\fR; +\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB)\fR +\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a checksum object\&. Currently the following types are supported: +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBREPOKEY_TYPE_MD5\fR +\fBREPOKEY_TYPE_SHA1\fR +\fBREPOKEY_TYPE_SHA256\fR +.fi +.if n \{\ +.RE +.\} +.sp +These keys are constants in the \fBsolv\fR class\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum Chksum(Id\fR \fItype\fR\fB, const char *\fR\fIhex\fR\fB)\fR +my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB,\fR \fI$hex\fR\fB)\fR; +\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR +\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create an already finalized checksum object from a hex string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum Chksum_from_bin(Id\fR \fItype\fR\fB, char *\fR\fIbin\fR\fB)\fR +my \fI$chksum\fR \fB= solv::Chksum\->from_bin(\fR\fI$type\fR\fB,\fR \fI$bin\fR\fB)\fR; +\fIchksum\fR \fB= solv\&.Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR +\fIchksum\fR \fB= Solv::Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create an already finalized checksum object from a binary checksum\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId type;\fR /* read only */ +\fI$chksum\fR\fB\->{type}\fR +\fIchksum\fR\fB\&.type\fR +\fIchksum\fR\fB\&.type\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the type of the checksum object\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add(const char *\fR\fIstr\fR\fB)\fR +\fI$chksum\fR\fB\->add(\fR\fI$str\fR\fB)\fR; +\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR +\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add a (binary) string to the checksum\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_fp(FILE *\fR\fIfp\fR\fB)\fR +\fI$chksum\fR\fB\->add_fp(\fR\fI$file\fR\fB)\fR; +\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR +\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of a file to the checksum\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_stat(const char *\fR\fIfilename\fR\fB)\fR +\fI$chksum\fR\fB\->add_stat(\fR\fI$filename\fR\fB)\fR; +\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR +\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Stat the file and add the dev/ino/size/mtime member to the checksum\&. If the stat fails, the members are zeroed\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_fstat(int\fR \fIfd\fR\fB)\fR +\fI$chksum\fR\fB\->add_fstat(\fR\fI$fd\fR\fB)\fR; +\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR +\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Same as add_stat, but instead of the filename a file descriptor is used\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned char *raw()\fR +my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->raw()\fR; +\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR +\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Finalize the checksum and return the result as raw bytes\&. This means that the result can contain NUL bytes or unprintable characters\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *hex()\fR +my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->hex()\fR; +\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR +\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Finalize the checksum and return the result as hex string\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *typestr()\fR +my \fI$typestr\fR \fB=\fR \fI$chksum\fR\fB\->typestr()\fR; +\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR +\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return the type of the checksum as a string, e\&.g\&. "sha256"\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +\fBif (\fR\fI$chksum1\fR \fB==\fR \fI$chksum2\fR\fB)\fR +\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR\fB:\fR +\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Checksums are equal if they are of the same type and the finalized results are the same\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fB\fR +my \fI$str\fR \fB=\fR \fI$chksum\fR\fB\->str\fR; +\fIstr\fR \fB= str(\fR\fIchksum\fR\fB)\fR +\fIstr\fR \fB=\fR \fIchksum\fR\fB\&.to_s\fR +.fi +.if n \{\ +.RE +.\} +.sp +If the checksum is finished, the checksum is returned as ":" string\&. Otherwise ":unfinished" is returned\&. +.SH "FILE MANAGEMENT" +.sp +This functions were added because libsolv uses standard \fBFILE\fR pointers to read/write files, but languages like perl have their own implementation of files\&. The libsolv functions also support decompression and compression, the algorithm is selected by looking at the file name extension\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBFILE *xfopen(char *\fR\fIfn\fR\fB, char *\fR\fImode\fR \fB= "r")\fR +my \fI$file\fR \fB= solv::xfopen(\fR\fI$path\fR\fB)\fR; +\fIfile\fR \fB= solv\&.xfopen(\fR\fIpath\fR\fB)\fR +\fIfile\fR \fB= Solv::xfopen(\fR\fIpath\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Open a file at the specified path\&. The mode argument is passed on to the stdio library\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBFILE *xfopen_fd(char *\fR\fIfn\fR\fB, int\fR \fIfileno\fR\fB)\fR +my \fI$file\fR \fB= solv::xfopen_fd(\fR\fI$path\fR\fB,\fR \fI$fileno\fR\fB)\fR; +\fIfile\fR \fB= solv\&.xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR +\fIfile\fR \fB= Solv::xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a file handle from the specified file descriptor\&. The path argument is only used to select the correct (de\-)compression algorithm, use an empty path if you want to make sure to read/write raw data\&. The file descriptor is dup()ed before the file handle is created\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint fileno()\fR +my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->fileno()\fR; +\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR +\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return file file descriptor of the file\&. If the file is not open, \-1 is returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid cloexec(bool\fR \fIstate\fR\fB)\fR +\fI$file\fR\fB\->cloexec(\fR\fI$state\fR\fB)\fR +\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR +\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Set the close\-on\-exec flag of the file descriptor\&. The xfopen function returns files with close\-on\-exec turned on, so if you want to pass a file to some other process you need to call cloexec(0) before calling exec\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint dup()\fR +my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->dup()\fR; +\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR +\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Return a copy of the descriptor of the file\&. If the file is not open, \-1 is returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool flush()\fR +\fI$file\fR\fB\->flush()\fR; +\fIfile\fR\fB\&.flush()\fR +\fIfile\fR\fB\&.flush()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Flush the file\&. Returns false if there was an error\&. Flushing a closed file always returns true\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool close()\fR +\fI$file\fR\fB\->close()\fR; +\fIfile\fR\fB\&.close()\fR +\fIfile\fR\fB\&.close()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Close the file\&. This is needed for languages like Ruby that do not destruct objects right after they are no longer referenced\&. In that case, it is good style to close open files so that the file descriptors are freed right away\&. Returns false if there was an error\&. +.SH "THE REPODATA CLASS" +.sp +The Repodata stores attributes for packages and the repository itself, each repository can have multiple repodata areas\&. You normally only need to directly access them if you implement lazy downloading of repository data\&. Repodata areas are created by calling the repository\(cqs add_repodata() method or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING flag\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo *repo;\fR /* read only */ +\fI$data\fR\fB\->{repo}\fR +\fIdata\fR\fB\&.repo\fR +\fIdata\fR\fB\&.repo\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to repository object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId id;\fR /* read only */ +\fI$data\fR\fB\->{id}\fR +\fIdata\fR\fB\&.id\fR +\fIdata\fR\fB\&.id\fR +.fi +.if n \{\ +.RE +.\} +.sp +The id of the repodata area\&. Repodata ids of different repositories overlap\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBinternalize()\fR; +\fI$data\fR\fB\->internalize()\fR; +\fIdata\fR\fB\&.internalize()\fR +\fIdata\fR\fB\&.internalize()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Internalize newly added data\&. The lookup functions will only see the new data after it has been internalized\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool write(FILE *\fR\fIfp\fR\fB)\fR; +\fI$data\fR\fB\->write(\fR\fI$fp\fR\fB)\fR; +\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR +\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Write the contents of the repodata area as solv file\&. +.sp +.if n \{\ +.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 +\fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Replace a stub repodata object with the data from a solv file\&. This method automatically adds the REPO_USE_LOADING flag\&. It should only be used from a load callback\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid create_stubs()\fR; +\fI$data\fR\fB\->create_stubs()\fR +\fIdata\fR\fB\&.create_stubs()\fR +\fIdata\fR\fB\&.create_stubs()\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create stub repodatas from the information stored in the repodata meta area\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid extend_to_repo()\fR; +\fI$data\fR\fB\->extend_to_repo()\fR; +\fIdata\fR\fB\&.extend_to_repo()\fR +\fIdata\fR\fB\&.extend_to_repo()\fR +.fi +.if n \{\ +.RE +.\} +.sp +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 +.\} +.nf +\fB\fR +\fBif (\fR\fI$data1\fR \fB==\fR \fI$data2\fR\fB)\fR +\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR\fB:\fR +\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR +.fi +.if n \{\ +.RE +.\} +.sp +Two repodata objects are equal if they belong to the same repository and have the same id\&. +.SS "DATA RETRIEVAL METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.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 +\fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$chksum\fR \fB=\fR \fI$data\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR; +\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Lookup functions\&. Return the data element stored in the specified solvable\&. The methods probably only make sense to retrieve data from the special SOLVID_META solvid that stores repodata meta information\&. +.SS "DATA STORAGE METHODS" +.sp +.if n \{\ +.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 +\fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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 +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid set_poolstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR; +\fI$data\fR\fB\->set_poolstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR; +\fIdata\fR\fB\&.set_poolstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR +\fIdata\fR\fB\&.set_poolstr(\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_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Chksum *\fR\fIchksum\fR\fB)\fR; +\fI$data\fR\fB\->set_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$chksum\fR\fB)\fR; +\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR +\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.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 +\fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId new_handle()\fR; +my \fI$handle\fR \fB=\fR \fI$data\fR\fB\->new_handle()\fR; +\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR +\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid add_flexarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIhandle\fR\fB)\fR; +\fI$data\fR\fB\->add_flexarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$handle\fR\fB)\fR; +\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR +\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR +.fi +.if n \{\ +.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 +Datapos objects describe a specific position in the repository data area\&. Thus they are only valid until the repository is modified in some way\&. Datapos objects can be created by the pos() and parentpos() methods of a Datamatch object or by accessing the \(lqmeta\(rq attribute of a repository\&. +.SS "ATTRIBUTES" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBRepo *repo;\fR /* read only */ +\fI$data\fR\fB\->{repo}\fR +\fIdata\fR\fB\&.repo\fR +\fIdata\fR\fB\&.repo\fR +.fi +.if n \{\ +.RE +.\} +.sp +Back pointer to repository object\&. +.SS "METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBDataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR +my \fI$di\fR \fB=\fR \fI$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Create a Dataiterator at the position of the datapos object\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_deltalocation(unsigned int *\fR\fIOUTPUT\fR\fB)\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 +.\} +.sp +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 structure describing a delta rpm\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_deltaseq()\fR; +my \fI$seq\fR \fB=\fR \fI$datapos\fR\fB\->lookup_deltaseq()\fR; +\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR; +\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the delta rpm sequence from the structure describing a delta rpm\&. +.SS "DATA RETRIEVAL METHODS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR +my \fI$string\fR \fB=\fR \fI$datapos\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR; +\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR +\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR +my \fI$id\fR \fB=\fR \fI$datapos\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR; +\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR +\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\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$datapos\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR; +\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR +\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR +my \fI$bool\fR \fB=\fR \fI$datapos\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR; +\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR +\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB)\fR +my \fI@ids\fR \fB=\fR \fI$datapos\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR; +\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR +\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR +my \fI$chksum\fR \fB=\fR \fI$datapos\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR; +\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR +\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +Lookup functions\&. Note that the returned Ids are always translated into the Ids of the global pool even if the repodata area contains its own pool\&. +.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$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR; +\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR +\fBfor\fR \fId\fR \fBin\fR \fIdi\fR +.fi +.if n \{\ +.RE +.\} +.sp +Iterate over the matching data elements\&. See the Dataiterator class for more information\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/libsolv-constantids.3 b/doc/gen/libsolv-constantids.3 new file mode 100644 index 0000000..228dfdd --- /dev/null +++ b/doc/gen/libsolv-constantids.3 @@ -0,0 +1,906 @@ +'\" t +.\" Title: Libsolv-Constantids +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "LIBSOLV\-CONSTANTIDS" "3" "09/14/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" +libsolv-constantids \- fixed Ids for often used strings +.SH "DESCRIPTION" +.sp +Constant Ids are Ids of strings that are often needed\&. They are defined to ease programming and reduce the number of pool_str2id calls\&. The constant Ids are part of the binary ABI of libsolv, a minor version update will only add new constants and not change existing Ids to maintain compatible\&. The on\-disk solv format works does not use the fixed Ids, but instead references the strings, so solv files can still be read when the ABI is broken\&. +.SH "SPECIAL STRINGS" +.PP +\fBID_EMPTY ""\fR +.RS 4 +The empty string\&. It will always have Id 1\&. +.RE +.PP +\fBSYSTEM_SYSTEM "system:system"\fR +.RS 4 +The name of the always installed "system" solvable\&. +.RE +.SH "SOLVABLE ATTRIBUTES" +.sp +These are Ids for keyname of attributes\&. They can be used in the lookup and storage functions to select the correct attribute in the solvable\&. The descriptions below describe the intended semantics of the values stored in the attribute with the keyname\&. +.PP +\fBSOLVABLE_NAME "solvable:name"\fR +.RS 4 +The name of the package\&. +.RE +.PP +\fBSOLVABLE_ARCH "solvable:arch"\fR +.RS 4 +The architecture of the package\&. See the Solvable Architecture section for predefined architecture Id values\&. +.RE +.PP +\fBSOLVABLE_EVR "solvable:evr"\fR +.RS 4 +The version of the package\&. It usually consists of some combination of the Epoch, the Version, and the Release of the solvable\&. +.RE +.PP +\fBSOLVABLE_VENDOR "solvable:vendor"\fR +.RS 4 +A vendor string\&. Usually the company or group that created the binary package\&. +.RE +.PP +\fBSOLVABLE_PROVIDES "solvable:provides"\fR +.RS 4 +Stores an array of dependency Ids that describe the capabilities that the package provides\&. +.RE +.PP +\fBSOLVABLE_OBSOLETES "solvable:obsoletes"\fR +.RS 4 +Stores an array of dependency Ids that describe the packages that this package replaces\&. +.RE +.PP +\fBSOLVABLE_CONFLICTS "solvable:conflicts"\fR +.RS 4 +Stores an array of dependency Ids that describe the capabilities that this package conflicts with, i\&.e\&. that can\(cqt be installed together with this package\&. +.RE +.PP +\fBSOLVABLE_REQUIRES "solvable:requires"\fR +.RS 4 +Stores an array of dependency Ids that describe the capabilities that also must be installed when this package is installed\&. +.RE +.PP +\fBSOLVABLE_RECOMMENDS "solvable:recommends"\fR +.RS 4 +Stores an array of dependency Ids that describe the capabilities that also should be installed when this package is installed\&. It\(cqs not an error if not all capabilities can be met\&. +.RE +.PP +\fBSOLVABLE_SUGGESTS "solvable:suggests"\fR +.RS 4 +Stores an array of dependency Ids that describe the capabilities that also useful to have installed when this package is installed\&. This is intended to provide a hint to the user about other packages\&. +.RE +.PP +\fBSOLVABLE_SUPPLEMENTS "solvable:supplements"\fR +.RS 4 +Stores an array of dependency Ids that define that this package should be installed if one of the capabilities is met\&. This is like the recommends attribute, but works in the reverse way\&. +.RE +.PP +\fBSOLVABLE_ENHANCES "solvable:enhances"\fR +.RS 4 +Stores an array of dependency Ids that define that this package is useful to have installed if one of the capabilities is met\&. This is like the suggests attribute, but works in the reverse way\&. +.RE +.PP +\fBSOLVABLE_SUMMARY "solvable:summary"\fR +.RS 4 +The summary should be a short string without any newlines that describes what a package does\&. +.RE +.PP +\fBSOLVABLE_DESCRIPTION "solvable:description"\fR +.RS 4 +The description should be a more verbose description about what a package does\&. It may consist of multiple lines\&. +.RE +.PP +\fBSOLVABLE_DISTRIBUTION "solvable:distribution"\fR +.RS 4 +The distribution is a short string that describes the OS and OS version this package is built for\&. +.RE +.PP +\fBSOLVABLE_AUTHORS "solvable:authors"\fR +.RS 4 +A list of authors of this package\&. This attribute was used in SUSE packages\&. +.RE +.PP +\fBSOLVABLE_PACKAGER "solvable:packager"\fR +.RS 4 +The person who created the binary package, see also the vendor attribute\&. +.RE +.PP +\fBSOLVABLE_GROUP "solvable:group"\fR +.RS 4 +The package group that this package belongs to\&. See also the keywords attribute\&. +.RE +.PP +\fBSOLVABLE_URL "solvable:url"\fR +.RS 4 +An URL that points to more information about the package\&. +.RE +.PP +\fBSOLVABLE_KEYWORDS "solvable:keywords"\fR +.RS 4 +list of keyword string IDs used for tagging this package\&. +.RE +.PP +\fBSOLVABLE_LICENSE "solvable:license"\fR +.RS 4 +The license(s) of this package\&. +.RE +.PP +\fBSOLVABLE_BUILDTIME "solvable:buildtime"\fR +.RS 4 +The seconds since the unix epoch when the binary package was created\&. +.RE +.PP +\fBSOLVABLE_BUILDHOST "solvable:buildhost"\fR +.RS 4 +The name of the host on which the binary package was created\&. +.RE +.PP +\fBSOLVABLE_EULA "solvable:eula"\fR +.RS 4 +If this attribute is present the user should be asked to accept the end user license agreement before the package gets installed\&. +.RE +.PP +\fBSOLVABLE_CPEID "solvable:cpeid"\fR +.RS 4 +A Common Platform Enumeration string describes the platform this package is intended for\&. See also the distribution attribute\&. +.RE +.PP +\fBSOLVABLE_MESSAGEINS "solvable:messageins"\fR +.RS 4 +A message that should be displayed to the user when the package gets installed\&. +.RE +.PP +\fBSOLVABLE_MESSAGEDEL "solvable:messagedel"\fR +.RS 4 +A message that should be displayed to the user when the package gets erased\&. +.RE +.PP +\fBSOLVABLE_INSTALLSIZE "solvable:installsize"\fR +.RS 4 +The disk space in bytes needed when installing the package\&. +.RE +.PP +\fBSOLVABLE_DISKUSAGE "solvable:diskusage"\fR +.RS 4 +A SUSE extension that stores for each directory the needed amount of disk space in kilobytes and inodes\&. +.RE +.PP +\fBSOLVABLE_FILELIST "solvable:filelist"\fR +.RS 4 +A list of files that the package contains\&. +.RE +.PP +\fBSOLVABLE_INSTALLTIME "solvable:installtime"\fR +.RS 4 +The seconds since the unix epoch when the binary package was installed on the system\&. +.RE +.PP +\fBSOLVABLE_MEDIADIR "solvable:mediadir"\fR +.RS 4 +The directory on the repository that contains the package\&. If this attribute is set to void, the package architecture is used as directory\&. +.RE +.PP +\fBSOLVABLE_MEDIAFILE "solvable:mediafile"\fR +.RS 4 +The filename on the repository that contains the package\&. If this attribute is set to void, the canonical file name of the package is used (i\&.e\&. a combination of the name, version, architecture)\&. +.RE +.PP +\fBSOLVABLE_MEDIANR "solvable:medianr"\fR +.RS 4 +The media number\&. This is an integer describing on which of a multi\-part media set this package is on\&. +.RE +.PP +\fBSOLVABLE_MEDIABASE "solvable:mediabase"\fR +.RS 4 +This attribute can be used to overwrite the repositories base url\&. +.RE +.PP +\fBSOLVABLE_DOWNLOADSIZE "solvable:downloadsize"\fR +.RS 4 +The size of the binary package in bytes\&. +.RE +.PP +\fBSOLVABLE_SOURCEARCH "solvable:sourcearch"\fR +.RS 4 +The architecture of the source package that this package belongs to\&. +.RE +.PP +\fBSOLVABLE_SOURCENAME "solvable:sourcename"\fR +.RS 4 +The name of the source package that this package belongs to\&. If set to void, the package name attribute is used instead\&. +.RE +.PP +\fBSOLVABLE_SOURCEEVR "solvable:sourceevr"\fR +.RS 4 +The version of the source package that this package belongs to\&. If set to void, the package version attribute is used instead\&. +.RE +.PP +\fBSOLVABLE_TRIGGERS "solvable:triggers"\fR +.RS 4 +A list of package triggers for this package\&. Used in the transaction ordering code\&. +.RE +.PP +\fBSOLVABLE_CHECKSUM "solvable:checksum"\fR +.RS 4 +The checksum of the binary package\&. See the Data Types section for a list of supported algorithms\&. +.RE +.PP +\fBSOLVABLE_PKGID "solvable:pkgid"\fR +.RS 4 +A string identifying a package\&. For rpm packages, this is the md5sum over the package header and the payload\&. +.RE +.PP +\fBSOLVABLE_HDRID "solvable:hdrid"\fR +.RS 4 +A string identifying a package\&. For rpm packages, this is the sha1sum over just the package header\&. +.RE +.PP +\fBSOLVABLE_LEADSIGID "solvable:leadsigid"\fR +.RS 4 +A string identifying the signature part of a package\&. For rpm packages, this is the md5sum from the start of the file up to the package header (i\&.e\&. it includes the lead, the signature header, and the padding)\&. +.RE +.PP +\fBSOLVABLE_HEADEREND "solvable:headerend"\fR +.RS 4 +The offset of the payload in rpm binary packages\&. You can use this information to download just the header if you want to display information not included in the repository metadata\&. +.RE +.PP +\fBSOLVABLE_CHANGELOG "solvable:changelog"\fR +.RS 4 +The array containing all the changelog structures\&. +.RE +.PP +\fBSOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"\fR +.RS 4 +The author of a changelog entry\&. +.RE +.PP +\fBSOLVABLE_CHANGELOG_TIME "solvable:changelog:time"\fR +.RS 4 +The seconds since the unix epoch when the changelog entry was written\&. +.RE +.PP +\fBSOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"\fR +.RS 4 +The text of a changelog entry\&. +.RE +.SH "SPECIAL SOLVABLE ATTRIBUTES" +.PP +\fBRPM_RPMDBID "rpm:dbid"\fR +.RS 4 +The rpm database id of this (installed) package\&. Usually a small integer number\&. +.RE +.PP +\fBSOLVABLE_PATCHCATEGORY "solvable:patchcategory"\fR +.RS 4 +The category field for patch solvables\&. Should be named \(lqupdate:category\(rq instead\&. +.RE +.PP +\fBUPDATE_REBOOT "update:reboot"\fR +.RS 4 +If this attribute is present the system should be rebooted after the update is installed\&. +.RE +.PP +\fBUPDATE_RESTART "update:restart"\fR +.RS 4 +If this attribute is present the software manager should be run again after the update is installed\&. +.RE +.PP +\fBUPDATE_RELOGIN "update:relogin"\fR +.RS 4 +If this attribute is present the user should log off and on again after the update is installed\&. +.RE +.PP +\fBUPDATE_MESSAGE "update:message"\fR +.RS 4 +A message that should be shown to the user to warn him about anything non\-standard\&. +.RE +.PP +\fBUPDATE_SEVERITY "update:severity"\fR +.RS 4 +The severity of the update\&. +.RE +.PP +\fBUPDATE_RIGHTS "update:rights"\fR +.RS 4 +Any legal or other rights of the update\&. +.RE +.PP +\fBUPDATE_COLLECTION "update:collection"\fR +.RS 4 +The array containing the package list of the update\&. +.RE +.PP +\fBUPDATE_COLLECTION_NAME "update:collection:name"\fR +.RS 4 +The name of the updated package\&. +.RE +.PP +\fBUPDATE_COLLECTION_EVR "update:collection:evr"\fR +.RS 4 +The version of the updated package\&. +.RE +.PP +\fBUPDATE_COLLECTION_ARCH "update:collection:arch"\fR +.RS 4 +The architecture of the updated package\&. +.RE +.PP +\fBUPDATE_COLLECTION_FILENAME "update:collection:filename"\fR +.RS 4 +The file name of the updated package\&. +.RE +.PP +\fBUPDATE_REFERENCE "update:reference"\fR +.RS 4 +The array containing the reference list of the update\&. +.RE +.PP +\fBUPDATE_REFERENCE_TYPE "update:reference:type"\fR +.RS 4 +The type of the reference, e\&.g\&. bugzilla\&. +.RE +.PP +\fBUPDATE_REFERENCE_HREF "update:reference:href"\fR +.RS 4 +The URL of the reference\&. +.RE +.PP +\fBUPDATE_REFERENCE_ID "update:reference:id"\fR +.RS 4 +The identification string of the reference, e\&.g\&. the bug number\&. +.RE +.PP +\fBUPDATE_REFERENCE_TITLE "update:reference:title"\fR +.RS 4 +The title of the reference, e\&.g\&. the bug summary\&. +.RE +.PP +\fBPRODUCT_REFERENCEFILE "product:referencefile"\fR +.RS 4 +The basename of the product file in the package\&. +.RE +.PP +\fBPRODUCT_SHORTLABEL "product:shortlabel"\fR +.RS 4 +An identification string of the product\&. +.RE +.PP +\fBPRODUCT_DISTPRODUCT "product:distproduct"\fR +.RS 4 +Obsolete, do not use\&. Was a SUSE Code\-10 product name\&. +.RE +.PP +\fBPRODUCT_DISTVERSION "product:distversion"\fR +.RS 4 +Obsolete, do not use\&. Was a SUSE Code\-10 product version\&. +.RE +.PP +\fBPRODUCT_TYPE "product:type"\fR +.RS 4 +The type of the product, e\&.g\&. \(lqbase\(rq\&. +.RE +.PP +\fBPRODUCT_URL "product:url"\fR +.RS 4 +An array of product URLs\&. +.RE +.PP +\fBPRODUCT_URL_TYPE "product:url:type"\fR +.RS 4 +An array of product URL types\&. +.RE +.PP +\fBPRODUCT_FLAGS "product:flags"\fR +.RS 4 +An array of product flags\&. +.RE +.PP +\fBPRODUCT_PRODUCTLINE "product:productline"\fR +.RS 4 +A product line string used for product registering\&. +.RE +.PP +\fBPRODUCT_REGISTER_TARGET "product:regtarget"\fR +.RS 4 +A target for product registering\&. +.RE +.PP +\fBPRODUCT_REGISTER_RELEASE "product:regrelease"\fR +.RS 4 +A release string for product registering\&. +.RE +.PP +\fBPUBKEY_KEYID "pubkey:keyid"\fR +.RS 4 +The keyid of a pubkey, consisting of 8 bytes in hex\&. +.RE +.PP +\fBPUBKEY_FINGERPRINT "pubkey:fingerprint"\fR +.RS 4 +The fingerprint of a pubkey, usually a sha1sum in hex\&. Old V3 RSA keys use a md5sum instead\&. +.RE +.PP +\fBPUBKEY_EXPIRES "pubkey:expires"\fR +.RS 4 +The seconds since the unix epoch when the pubkey expires\&. +.RE +.PP +\fBPUBKEY_SUBKEYOF "pubkey:subkeyof"\fR +.RS 4 +The keyid of the master pubkey for subkeys\&. +.RE +.PP +\fBPUBKEY_DATA "pubkey:data"\fR +.RS 4 +The MPI data of the pubkey\&. +.RE +.PP +\fBSOLVABLE_ISVISIBLE "solvable:isvisible"\fR +.RS 4 +An attribute describing if the package should be listed to the user or not\&. Used for SUSE patterns\&. +.RE +.PP +\fBSOLVABLE_CATEGORY "solvable:category"\fR +.RS 4 +The category of a pattern\&. +.RE +.PP +\fBSOLVABLE_INCLUDES "solvable:includes"\fR +.RS 4 +A list of other patterns that this pattern includes\&. +.RE +.PP +\fBSOLVABLE_EXTENDS "solvable:extends"\fR +.RS 4 +A list of other patterns that this pattern extends\&. +.RE +.PP +\fBSOLVABLE_ICON "solvable:icon"\fR +.RS 4 +The icon name of a pattern\&. +.RE +.PP +\fBSOLVABLE_ORDER "solvable:order"\fR +.RS 4 +An ordering clue of a pattern\&. +.RE +.PP +\fBSUSETAGS_SHARE_NAME "susetags:share:name"\fR +.RS 4 +Internal attribute to implement susetags shared records\&. Holds the name of the solvable used for sharing attributes\&. +.RE +.PP +\fBSUSETAGS_SHARE_EVR "susetags:share:evr"\fR +.RS 4 +Internal attribute to implement susetags shared records\&. Holds the version of the solvable used for sharing attributes\&. +.RE +.PP +\fBSUSETAGS_SHARE_ARCH "susetags:share:arch"\fR +.RS 4 +Internal attribute to implement susetags shared records\&. Holds the architecture of the solvable used for sharing attributes\&. +.RE +.SH "SOLVABLE ARCHITECTURES" +.sp +Predefined architecture values for commonly used architectures\&. +.PP +\fBARCH_SRC "src"\fR +.RS 4 +Used for binary packages that contain the package sources\&. +.RE +.PP +\fBARCH_NOSRC "nosrc"\fR +.RS 4 +Used for binary packages that contain some of the package sources, but not all files (because of restrictions)\&. +.RE +.PP +\fBARCH_NOARCH "noarch"\fR +.RS 4 +This package can be installed on any architecture\&. Used for rpm\&. +.RE +.PP +\fBARCH_ALL "all"\fR +.RS 4 +This package can be installed on any architecture\&. Used for Debian\&. +.RE +.PP +\fBARCH_ANY "any"\fR +.RS 4 +This package can be installed on any architecture\&. Used for Archlinux and Haiku\&. +.RE +.SH "DEPENDENCY IDS" +.sp +Namespaces are special modifiers that change the meaning of a dependency\&. Namespace dependencies are created with the REL_NAMESPACE flag\&. To make custom namespaces work you have to implement a namespace callback function\&. +.sp +The dependency markers partition the dependency array in two parts with different semantics\&. +.PP +\fBNAMESPACE_MODALIAS "namespace:modalias"\fR +.RS 4 +The dependency is a special modalias dependency that matches installed hardware\&. +.RE +.PP +\fBNAMESPACE_SPLITPROVIDES "namespace:splitprovides"\fR +.RS 4 +The dependency is a special splitprovides dependency used to implement updates that include a package split\&. A splitprovides dependency contains a filename and a package name, it is matched if a package with the provided package name is installed that contains the filename\&. This namespace is implemented in libsolv, so you do not need a callback\&. +.RE +.PP +\fBNAMESPACE_LANGUAGE "namespace:language"\fR +.RS 4 +The dependency describes a language\&. The callback should return true if the language was selected by the user\&. +.RE +.PP +\fBNAMESPACE_FILESYSTEM "namespace:filesystem"\fR +.RS 4 +The dependency describes a filesystem\&. The callback should return true if the filesystem is needed\&. +.RE +.PP +\fBNAMESPACE_OTHERPROVIDERS "namespace:otherproviders"\fR +.RS 4 +This is a hack to allow self\-conflicting packages\&. It is not needed with current rpm version, so do not use this namespace\&. +.RE +.PP +\fBSOLVABLE_PREREQMARKER "solvable:prereqmarker"\fR +.RS 4 +This marker partitions the normal require dependencies from the prerequires\&. It is not needed for dependency solving, but it is used by the transaction ordering algorithm when a dependency cycle needs to be broken (non\-prereq deps get broken first)\&. +.RE +.PP +\fBSOLVABLE_FILEMARKER "solvable:filemarker"\fR +.RS 4 +This marker partitions the package provides dependencies from the synthetic file provides dependencies added by pool_addfileprovides()\&. +.RE +.SH "DATA TYPES" +.sp +Each attribute data is stored with a type, so that the lookup functions know how to interpret the data\&. The following types are available: +.PP +\fBREPOKEY_TYPE_VOID "repokey:type:void"\fR +.RS 4 +No data is stored with this attribute\&. Thus you can only test if the attribute exists or not\&. Useful to store boolean values\&. +.RE +.PP +\fBREPOKEY_TYPE_CONSTANT "repokey:type:constant"\fR +.RS 4 +The data is a constant 32bit number\&. The number is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&. +.RE +.PP +\fBREPOKEY_TYPE_CONSTANTID "repokey:type:constantid"\fR +.RS 4 +The data is a constant Id\&. The Id is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&. +.RE +.PP +\fBREPOKEY_TYPE_ID "repokey:type:id"\fR +.RS 4 +The data is an Id\&. +.RE +.PP +\fBREPOKEY_TYPE_NUM "repokey:type:num"\fR +.RS 4 +The data is an unsigned 64bit number\&. +.RE +.PP +\fBREPOKEY_TYPE_U32 "repokey:type:num32"\fR +.RS 4 +The data is an unsigned 32bit number\&. Obsolete, do not use\&. +.RE +.PP +\fBREPOKEY_TYPE_DIR "repokey:type:dir"\fR +.RS 4 +The data is an Id of a directory\&. +.RE +.PP +\fBREPOKEY_TYPE_STR "repokey:type:str"\fR +.RS 4 +The data is a regular string\&. +.RE +.PP +\fBREPOKEY_TYPE_BINARY "repokey:type:binary"\fR +.RS 4 +The data is a binary blob\&. +.RE +.PP +\fBREPOKEY_TYPE_IDARRAY "repokey:type:idarray"\fR +.RS 4 +The data is an array of non\-zero Ids\&. +.RE +.PP +\fBREPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"\fR +.RS 4 +The data is an array of non\-zero Ids ordered so that it needs less space\&. +.RE +.PP +\fBREPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"\fR +.RS 4 +The data is a tuple consisting of a directory Id and a basename\&. Used to store file names\&. +.RE +.PP +\fBREPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"\fR +.RS 4 +The data is a triple consisting of a directory Id and two 32bit unsigned integers\&. Used to store disk usage information\&. +.RE +.PP +\fBREPOKEY_TYPE_MD5 "repokey:type:md5"\fR +.RS 4 +The data is a binary md5sum\&. +.RE +.PP +\fBREPOKEY_TYPE_SHA1 "repokey:type:sha1"\fR +.RS 4 +The data is a binary sha1sum\&. +.RE +.PP +\fBREPOKEY_TYPE_SHA256 "repokey:type:sha256"\fR +.RS 4 +The data is a binary sha256sum\&. +.RE +.PP +\fBREPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"\fR +.RS 4 +The data is an array of structures that have all the same layout (i\&.e\&. the same keynames and keytypes in the same order)\&. +.RE +.PP +\fBREPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"\fR +.RS 4 +The data is an array of structures that have a different layout\&. +.RE +.PP +\fBREPOKEY_TYPE_DELETED "repokey:type:deleted"\fR +.RS 4 +The data does not exist\&. Used to mark an attribute that was deleted\&. +.RE +.SH "REPOSITORY METADATA" +.sp +This attributes contain meta information about the repository\&. +.PP +\fBREPOSITORY_SOLVABLES "repository:solvables"\fR +.RS 4 +This attribute holds the array including all of the solvables\&. It is only used in the on\-disk solv files, internally the solvables are stored in the pool\(cqs solvable array for fast access\&. +.RE +.PP +\fBREPOSITORY_DELTAINFO "repository:deltainfo"\fR +.RS 4 +This attribute holds the array including all of the delta packages\&. +.RE +.PP +\fBREPOSITORY_EXTERNAL "repository:external"\fR +.RS 4 +This attribute holds the array including all of the data to construct stub repodata areas to support on\-demand loading of metadata\&. +.RE +.PP +\fBREPOSITORY_KEYS "repository:keys"\fR +.RS 4 +This should really be named "repository:external:keys", it contains an array if Ids that consists of (keyname, keytype) pairs that describe the keys of the stub\&. +.RE +.PP +\fBREPOSITORY_LOCATION "repository:location"\fR +.RS 4 +This is used to provide a file name in the stub\&. +.RE +.PP +\fBREPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"\fR +.RS 4 +This attribute holds an array of filename Ids, that tell the library, that all of the Ids were already added to the solvable provides\&. +.RE +.PP +\fBREPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"\fR +.RS 4 +An attribute that stores a sha256sum over the file stats of the Packages database\&. It\(cqs used to detect rebuilds of the database, as in that case the database Ids of every package are newly distributed\&. +.RE +.PP +\fBREPOSITORY_TIMESTAMP "repository:timestamp"\fR +.RS 4 +The seconds since the unix epoch when the repository was created\&. +.RE +.PP +\fBREPOSITORY_EXPIRE "repository:expire"\fR +.RS 4 +The seconds after the timestamp when the repository will expire\&. +.RE +.PP +\fBREPOSITORY_UPDATES "repository:updates"\fR +.RS 4 +An array of structures describing what this repository updates\&. +.RE +.PP +\fBREPOSITORY_DISTROS "repository:distros"\fR +.RS 4 +Also an array of structures describing what this repository updates\&. Seems to be the newer name of REPOSITORY_UPDATES\&. +.RE +.PP +\fBREPOSITORY_PRODUCT_LABEL "repository:product:label"\fR +.RS 4 +Should really be called "repository:updates:label"\&. What distribution is updated with this repository\&. +.RE +.PP +\fBREPOSITORY_PRODUCT_CPEID "repository:product:cpeid"\fR +.RS 4 +The cpeid of the platform updated by this repository\&. Is both used in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion\&. +.RE +.PP +\fBREPOSITORY_REPOID "repository:repoid"\fR +.RS 4 +An array of Id strings describing keywords/tags about the repository itself\&. +.RE +.PP +\fBREPOSITORY_KEYWORDS "repository:keywords"\fR +.RS 4 +An array of Id strings describing keywords/tags about the content of the repository\&. +.RE +.PP +\fBREPOSITORY_REVISION "repository:revision"\fR +.RS 4 +An arbitrary string describing the revision of the repository\&. +.RE +.PP +\fBREPOSITORY_TOOLVERSION "repository:toolversion"\fR +.RS 4 +Some string describing somewhat the version of libsolv used to create the solv file\&. +.RE +.SH "REPOSITORY METADATA FOR SUSETAGS REPOS" +.sp +Attributes describing repository files in a susetags repository\&. \fBSUSETAGS_DATADIR "susetags:datadir"\fR:: The directory that contains the packages\&. +.PP +\fBSUSETAGS_DESCRDIR "susetags:descrdir"\fR +.RS 4 +The directory that contains the repository file resources\&. +.RE +.PP +\fBSUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"\fR +.RS 4 +The default vendor used when a package does not specify a vendor\&. +.RE +.PP +\fBSUSETAGS_FILE "susetags:file"\fR +.RS 4 +An array of file resources of the repository\&. +.RE +.PP +\fBSUSETAGS_FILE_NAME "susetags:file:name"\fR +.RS 4 +The filename of the resource\&. +.RE +.PP +\fBSUSETAGS_FILE_TYPE "susetags:file:type"\fR +.RS 4 +The type of the resource, e\&.g\&. \(lqMETA\(rq\&. +.RE +.PP +\fBSUSETAGS_FILE_CHECKSUM "susetags:file:checksum"\fR +.RS 4 +The file checksum of the resource\&. +.RE +.SH "REPOSITORY METADATA FOR RPMMD REPOS" +.PP +\fBREPOSITORY_REPOMD "repository:repomd"\fR +.RS 4 +An array of file resources of the repository\&. +.RE +.PP +\fBREPOSITORY_REPOMD_TYPE "repository:repomd:type"\fR +.RS 4 +The type of the resource, e\&.g\&. \(lqprimary\(rq\&. +.RE +.PP +\fBREPOSITORY_REPOMD_LOCATION "repository:repomd:location"\fR +.RS 4 +The location (aka filename) of the resource +.RE +.PP +\fBREPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"\fR +.RS 4 +The seconds since the unix epoch when the resource was created\&. +.RE +.PP +\fBREPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"\fR +.RS 4 +The file checksum of the resource\&. +.RE +.PP +\fBREPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"\fR +.RS 4 +The checksum over the uncompressed contents of the resource\&. +.RE +.PP +\fBREPOSITORY_REPOMD_SIZE "repository:repomd:size"\fR +.RS 4 +The size of the resource file\&. +.RE +.SH "DELTA PACKAGE ATTRIBUTES" +.PP +\fBDELTA_PACKAGE_NAME "delta:pkgname"\fR +.RS 4 +The target package name for the delta package\&. Applying the delta will recreate the target package\&. +.RE +.PP +\fBDELTA_PACKAGE_EVR "delta:pkgevr"\fR +.RS 4 +The version of the target package\&. +.RE +.PP +\fBDELTA_PACKAGE_ARCH "delta:pkgarch"\fR +.RS 4 +The architecture of the target package\&. +.RE +.PP +\fBDELTA_LOCATION_DIR "delta:locdir"\fR +.RS 4 +The directory in the repository that contains the delta package\&. +.RE +.PP +\fBDELTA_LOCATION_NAME "delta:locname"\fR +.RS 4 +The first part of the file name of the delta package\&. +.RE +.PP +\fBDELTA_LOCATION_EVR "delta:locevr"\fR +.RS 4 +The version part of the file name of the delta package\&. +.RE +.PP +\fBDELTA_LOCATION_SUFFIX "delta:locsuffix"\fR +.RS 4 +The suffix part of the file name of the delta package\&. +.RE +.PP +\fBDELTA_LOCATION_BASE "delta:locbase"\fR +.RS 4 +This attribute can be used to overwrite the repositories base url for the delta\&. +.RE +.PP +\fBDELTA_DOWNLOADSIZE "delta:downloadsize"\fR +.RS 4 +The size of the delta rpm file\&. +.RE +.PP +\fBDELTA_CHECKSUM "delta:checksum"\fR +.RS 4 +The checksum of the delta rpm file\&. +.RE +.PP +\fBDELTA_BASE_EVR "delta:baseevr"\fR +.RS 4 +The version of the package the delta was built against\&. +.RE +.PP +\fBDELTA_SEQ_NAME "delta:seqname"\fR +.RS 4 +The first part of the delta sequence, the base package name\&. +.RE +.PP +\fBDELTA_SEQ_EVR "delta:seqevr"\fR +.RS 4 +The evr part of the delta sequence, the base package evr\&. Identical to the DELTA_BASE_EVR attribute\&. +.RE +.PP +\fBDELTA_SEQ_NUM "delta:seqnum"\fR +.RS 4 +The last part of the delta sequence, the content selection string\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/libsolv-history.3 b/doc/gen/libsolv-history.3 new file mode 100644 index 0000000..fc2d69b --- /dev/null +++ b/doc/gen/libsolv-history.3 @@ -0,0 +1,119 @@ +'\" t +.\" Title: Libsolv-History +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "LIBSOLV\-HISTORY" "3" "09/14/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" +libsolv-history \- how the libsolv library came into existence +.SH "HISTORY" +.sp +This project was started in May 2007 when the zypp folks decided to switch to a database to speed up installation\&. As I am not a big fan of databases, I (mls) wondered if there would be really some merit of using one for solving, as package dependencies of all packages have to be read in anyway\&. +.sp +Back in 2002, I researched that using a dictionary approach for storing dependencies can reduce the packages file to 1/3 of its size\&. Extending this idea a bit more, I decided to store all strings and relations as unique 32\-bit numbers\&. This has three big advantages: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +because of the unification, testing whether two strings are equal is the same as testing the equality of two numbers, thus very fast +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +much space is saved, as numbers do not take up as much space as strings the internal memory representation does not take more space on a 64\-bit system where a pointer is twice the size of a 32\-bit number +.RE +.sp +Thus, the solv format was created, which stores a repository as a string dictionary, a relation dictionary and then all packages dependencies\&. Tests showed that reading and merging multiple solv repositories takes just some milliseconds\&. +.SS "Early solver experiments" +.sp +Having a new repository format was one big step, but the other area where libzypp needed improvement was the solver\&. Libzypp\(cqs solver was a port from the Red Carpet solver, which was written to update packages in an already installed system\&. Using it for the complete installation progress brought it to its limits\&. Also, the added extensions like support for weak dependencies and patches made it fragile and unpredictable\&. +.sp +As I was not very pleased with the way the solver worked, I looked at other solver algorithms\&. I checked smart, yum and apt, but could not find a convincing algorithm\&. My own experiments also were not very convincing, they worked fine for some problems but failed miserably for other corner cases\&. +.SS "Using SAT for solving" +.sp +SUSE\(cqs hack week at the end of June 2007 turned out to be a turning point for the solver\&. Googling for solver algorithms, I stumbled over some note saying that some people are trying to use SAT algorithms to improve solving on Debian\&. Looking at the SAT entry in Wikipedia, it was easy to see that this indeed was the missing piece: SAT algorithms are well researched and there are quite some open source implementations\&. I decided to look at the minisat code, as it is one of the fastest solvers while consisting of too many lines of code\&. +.sp +Of course, directly using minisat would not work, as a package solver does not need to find just one correct solution, but it also has to optimize some metrics, i\&.e\&. keep as many packages installed as possible\&. Thus, I needed to write my own solver incorporation the ideas and algorithms used in minisat\&. This wasn\(cqt very hard, and at the end of the hack week the solver calculated the first right solutions\&. +.SS "Selling it to libzypp" +.sp +With those encouraging results, I went to Klaus Kaempf, the system management architect at SUSE\&. We spoke about how to convince the team to make libzypp switch to the new solver\&. Fortunately, libzypp comes with a plethora of solver test cases, so we decided to make the solver pass most of the test cases first\&. Klaus wrote a "deptestomatic" implementation to check the test cases\&. Together with Stephan Kulow, who is responsible for the openSUSE distribution, we tweaked and extended the solver until most of the test cases looked good\&. +.sp +Duncan Mac\-Vicar Prett, the team lead of the YaST team, also joined development by creating Ruby bindings for the solver\&. Later, Klaus improved the bindings and ported them to some other languages\&. +.SS "The attribute store" +.sp +The progress with the repository format and the solver attracted another hacker to the project: Michael Matz from the compiler team\&. He started with improving the repository parsers so that patches and content files also generate solvables\&. After that, he concentrated on storing all of the other metadata of the repositories that are not used for solving, like the package summaries and descriptions\&. At the end of October, a first version of this "attribute store" was checked in\&. Its design goals were: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +space efficient storage of attributes +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +paging/on demand loading of data +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +page compression +.RE +.sp +The first version of the attribute store used a different format for storing information, we later merged this format with the solv file format\&. +.SS "libzypp integration" +.sp +Integration of the sat\-solver into libzypp also started in October 2007 by Stefan Schubert and Michael Andres from the YaST team\&. The first versions supported both the old solver and the new one by using the old repository read functions and converting the old package data in\-memory into a sat solver pool\&. Solvers could be switched with the environment variable ZYPP_SAT_SOLVER\&. The final decision to move to the new solver was made in January of 2008, first just by making the new solver the default one, later by completely throwing out the old solver code\&. This had the advantage that the internal solvable storage could also be done by using the solver pool, something Michael Matz already played with in a proof of concept implementation showing some drastic speed gains\&. The last traces of the old database code were removed in February\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/libsolv-pool.3 b/doc/gen/libsolv-pool.3 new file mode 100644 index 0000000..6d94939 --- /dev/null +++ b/doc/gen/libsolv-pool.3 @@ -0,0 +1,1337 @@ +'\" t +.\" Title: Libsolv-Pool +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 01/21/2020 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "LIBSOLV\-POOL" "3" "01/21/2020" "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" +libsolv-pool \- Libsolv\*(Aqs pool object +.SH "PUBLIC ATTRIBUTES" +.PP +\fBvoid *appdata\fR +.RS 4 +A no\-purpose pointer free to use for the library user\&. Freeing the pool simply discards the pointer\&. +.RE +.PP +\fBStringpool ss\fR +.RS 4 +The pool of unified strings\&. +.RE +.PP +\fBReldep *rels\fR +.RS 4 +The pool of unified relation dependencies\&. +.RE +.PP +\fBint nrels\fR +.RS 4 +Number of allocated relation dependencies\&. +.RE +.PP +\fBRepo **repos\fR +.RS 4 +The array of repository pointers, indexed by repository Id\&. +.RE +.PP +\fBint nrepos\fR +.RS 4 +Number of allocated repository array elements, i\&.e\&. the size of the repos array\&. +.RE +.PP +\fBint urepos\fR +.RS 4 +Number of used (i\&.e\&. non\-zero) repository array elements\&. +.RE +.PP +\fBRepo *installed\fR +.RS 4 +Pointer to the repo holding the installed packages\&. You are free to read this attribute, but you should use pool_set_installed() if you want to change it\&. +.RE +.PP +\fBSolvable *solvables\fR +.RS 4 +The array of Solvable objects\&. +.RE +.PP +\fBint nsolvables\fR +.RS 4 +Number of Solvable objects, i\&.e\&. the size of the solvables array\&. Note that the array may contain freed solvables, in that case the repo pointer of the solvable will be zero\&. +.RE +.PP +\fBint disttype\fR +.RS 4 +The distribution type of your system, e\&.g\&. DISTTYPE_DEB\&. You are free to read this attribute, but you should use pool_setdisttype() if you want to change it\&. +.RE +.PP +\fBId *whatprovidesdata\fR +.RS 4 +Multi\-purpose Id storage holding zero terminated arrays of Ids\&. pool_whatprovides() returns an offset into this data\&. +.RE +.PP +\fBMap *considered\fR +.RS 4 +Optional bitmap that can make the library ignore solvables\&. If a bitmap is set, only solvables that have a set bit in the bitmap at their Id are considered usable\&. +.RE +.PP +\fBint debugmask\fR +.RS 4 +A mask that defines which debug events should be reported\&. pool_setdebuglevel() sets this mask\&. +.RE +.PP +\fBDatapos pos\fR +.RS 4 +An object storing some position in the repository data\&. Functions like dataiterator_set_pos() set this object, accessing data with a pseudo solvable Id of SOLVID_POS uses it\&. +.RE +.PP +\fBQueue pooljobs\fR +.RS 4 +A queue where fixed solver jobs can be stored\&. This jobs are automatically added when solver_solve() is called, they are useful to store configuration data like which packages should be multiversion installed\&. +.RE +.SH "CREATION AND DESTRUCTION" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBPool *pool_create()\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Create a new instance of a pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_free(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Free a pool and all of the data it contains, e\&.g\&. the solvables, repositories, strings\&. +.SH "DEBUGGING AND ERROR REPORTING" +.SS "Constants" +.PP +\fBSOLV_FATAL\fR +.RS 4 +Report the error and call \(lqexit(1)\(rq afterwards\&. You cannot mask this level\&. Reports to stderr instead of stdout\&. +.RE +.PP +\fBSOLV_ERROR\fR +.RS 4 +Used to report errors\&. Reports to stderr instead of stdout\&. +.RE +.PP +\fBSOLV_WARN\fR +.RS 4 +Used to report warnings\&. +.RE +.PP +\fBSOLV_DEBUG_STATS\fR +.RS 4 +Used to report statistical data\&. +.RE +.PP +\fBSOLV_DEBUG_RULE_CREATION\fR +.RS 4 +Used to report information about the solver\(cqs creation of rules\&. +.RE +.PP +\fBSOLV_DEBUG_PROPAGATE\fR +.RS 4 +Used to report information about the solver\(cqs unit rule propagation process\&. +.RE +.PP +\fBSOLV_DEBUG_ANALYZE\fR +.RS 4 +Used to report information about the solver\(cqs learnt rule generation mechanism\&. +.RE +.PP +\fBSOLV_DEBUG_UNSOLVABLE\fR +.RS 4 +Used to report information about the solver dealing with conflicting rules\&. +.RE +.PP +\fBSOLV_DEBUG_SOLUTIONS\fR +.RS 4 +Used to report information about the solver creating solutions to solve problems\&. +.RE +.PP +\fBSOLV_DEBUG_POLICY\fR +.RS 4 +Used to report information about the solver searching for an optimal solution\&. +.RE +.PP +\fBSOLV_DEBUG_RESULT\fR +.RS 4 +Used by the debug functions to output results\&. +.RE +.PP +\fBSOLV_DEBUG_JOB\fR +.RS 4 +Used to report information about the job rule generation process\&. +.RE +.PP +\fBSOLV_DEBUG_SOLVER\fR +.RS 4 +Used to report information about what the solver is currently doing\&. +.RE +.PP +\fBSOLV_DEBUG_TRANSACTION\fR +.RS 4 +Used to report information about the transaction generation and ordering process\&. +.RE +.PP +\fBSOLV_DEBUG_TO_STDERR\fR +.RS 4 +Write debug messages to stderr instead of stdout\&. +.RE +.SS "Functions" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_debug(Pool *\fR\fIpool\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Report a message of the type \fItype\fR\&. You can filter debug messages by setting a debug mask\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setdebuglevel(Pool *\fR\fIpool\fR\fB, int\fR \fIlevel\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set a predefined debug mask\&. A higher level generally means more bits in the mask are set, thus more messages are printed\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setdebugmask(Pool *\fR\fIpool\fR\fB, int\fR \fImask\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set the debug mask to filter debug messages\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_error(Pool *\fR\fIpool\fR\fB, int\fR \fIret\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set the pool\(cqs error string\&. The \fIret\fR value is simply used as a return value of the function so that you can write code like return pool_error(\&...);\&. If the debug mask contains the \fBSOLV_ERROR\fR bit, pool_debug() is also called with the message and type \fBSOLV_ERROR\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBextern char *pool_errstr(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the current error string stored in the pool\&. Like with the libc\(cqs errno value, the string is only meaningful after a function returned an error\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setdebugcallback(Pool *\fR\fIpool\fR\fB, void (*\fR\fIdebugcallback\fR\fB)(Pool *, void *\fR\fIdata\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIstr\fR\fB), void *\fR\fIdebugcallbackdata\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set a custom debug callback function\&. Instead of writing to stdout or stderr, the callback function will be called\&. +.SH "POOL CONFIGURATION" +.SS "Constants" +.PP +\fBDISTTYPE_RPM\fR +.RS 4 +Used for systems which use rpm as low level package manager\&. +.RE +.PP +\fBDISTTYPE_DEB\fR +.RS 4 +Used for systems which use dpkg as low level package manager\&. +.RE +.PP +\fBDISTTYPE_ARCH\fR +.RS 4 +Used for systems which use the arch linux package manager\&. +.RE +.PP +\fBDISTTYPE_HAIKU\fR +.RS 4 +Used for systems which use haiku packages\&. +.RE +.PP +\fBPOOL_FLAG_PROMOTEEPOCH\fR +.RS 4 +Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&. +.RE +.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\&. +.RE +.PP +\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR +.RS 4 +Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&. +.RE +.PP +\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR +.RS 4 +An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&. +.RE +.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\&. +.RE +.PP +\fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR +.RS 4 +Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&. +.RE +.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\&. +.RE +.PP +\fBPOOL_FLAG_HAVEDISTEPOCH\fR +.RS 4 +Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&. +.RE +.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\&. +.RE +.PP +\fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR +.RS 4 +Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&. +.RE +.SS "Functions" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_setdisttype(Pool *\fR\fIpool\fR\fB, int\fR \fIdisttype\fR\fB)\fR; +.fi +.if n \{\ +.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\&. 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 +.\} +.nf +\fBint pool_set_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set a flag to a new value\&. Returns the old value of the flag\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_get_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Get the value of a pool flag\&. See the constants section about the meaning of the flags\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_set_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIrootdir\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set a specific root directory\&. Some library functions support a flag that tells the function to prepend the rootdir to file and directory names\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_get_rootdir(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the current value of the root directory\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *pool_prepend_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Prepend the root directory to the \fIdir\fR argument string\&. The returned string has been newly allocated and needs to be freed after use\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *pool_prepend_rootdir_tmp(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Same as pool_prepend_rootdir, but uses the pool\(cqs temporary space for allocation\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_set_installed(Pool *\fR\fIpool\fR\fB, Repo *\fR\fIrepo\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set which repository should be treated as the \(lqinstalled\(rq repository, i\&.e\&. the one that holds information about the installed packages\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_set_languages(Pool *\fR\fIpool\fR\fB, const char **\fR\fIlanguages\fR\fB, int\fR \fInlanguages\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set the language of your system\&. The library provides lookup functions that return localized strings, for example for package descriptions\&. You can set an array of languages to provide a fallback mechanism if one language is not available\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setarch(Pool *\fR\fIpool\fR\fB, const char *\fR\fIarch\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set the architecture of your system\&. The architecture is used to determine which packages are installable and which packages cannot be installed\&. The \fIarch\fR argument is normally the \(lqmachine\(rq value of the \(lquname\(rq system call\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setarchpolicy(Pool *, const char *)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set the architecture policy for your system\&. This is the general version of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally)\&. See the section about architecture policies for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_addvendorclass(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclass\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Add a new vendor equivalence class to the system\&. A vendor equivalence class defines if an installed package of one vendor can be replaced by a package coming from a different vendor\&. The \fIvendorclass\fR argument must be a NULL terminated array of strings\&. See the section about vendor policies for more information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setvendorclasses(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclasses\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Set all allowed vendor equivalences\&. The vendorclasses argument must be an NULL terminated array consisting of all allowed classes concatenated\&. Each class itself must be NULL terminated, thus the last class ends with two NULL elements, one to finish the class and one to finish the list of classes\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_set_custom_vendorcheck(Pool *\fR\fIpool\fR\fB, int (*\fR\fIvendorcheck\fR\fB)(Pool *, Solvable *, Solvable *))\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Define a custom vendor check mechanism\&. You can use this if libsolv\(cqs internal vendor equivalence class mechanism does not match your needs\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setloadcallback(Pool *\fR\fIpool\fR\fB, int (*\fR\fIcb\fR\fB)(Pool *, Repodata *, void *), void *\fR\fIloadcbdata\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Define a callback function that gets called when repository metadata needs to be loaded on demand\&. See the section about on demand loading in the libsolv\-repodata manual\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_setnamespacecallback(Pool *\fR\fIpool\fR\fB, Id (*\fR\fIcb\fR\fB)(Pool *, void *,\fR \fIId\fR\fB,\fR \fIId\fR\fB), void *\fR\fInscbdata\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Define a callback function to implement custom namespace support\&. See the section about namespace dependencies\&. +.SH "ID POOL MANAGEMENT" +.SS "Constants" +.PP +\fBID_EMPTY\fR +.RS 4 +The Id of the empty string, it is always Id 1\&. +.RE +.PP +\fBREL_LT\fR +.RS 4 +Represents a \(lq<\(rq relation\&. +.RE +.PP +\fBREL_EQ\fR +.RS 4 +Represents a \(lq=\(rq relation\&. +.RE +.PP +\fBREL_GT\fR +.RS 4 +Represents a \(lq>\(rq relation\&. You can use combinations of REL_GT, REL_EQ, and REL_LT or\-ed together to create any relation you like\&. +.RE +.PP +\fBREL_AND\fR +.RS 4 +A boolean AND operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages must match both parts of the dependency\&. +.RE +.PP +\fBREL_OR\fR +.RS 4 +A boolean OR operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages can match any part of the dependency\&. +.RE +.PP +\fBREL_WITH\fR +.RS 4 +Like REL_AND, but packages must match both dependencies simultaneously\&. See the section about boolean dependencies about more information\&. +.RE +.PP +\fBREL_NAMESPACE\fR +.RS 4 +A special namespace relation\&. See the section about namespace dependencies for more information\&. +.RE +.PP +\fBREL_ARCH\fR +.RS 4 +An architecture filter dependency\&. The \(lqname\(rq part of the relation is a sub\-dependency, the \(lqevr\(rq part is the Id of an architecture that the matching packages must have (note that this is an exact match ignoring architecture policies)\&. +.RE +.PP +\fBREL_FILECONFLICT\fR +.RS 4 +An internal file conflict dependency used to represent file conflicts\&. See the pool_add_fileconflicts_deps() function\&. +.RE +.PP +\fBREL_COND\fR +.RS 4 +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 \{\ +.RS 4 +.\} +.nf +\fBId pool_str2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, int\fR \fIcreate\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Add a string to the pool of unified strings, returning the Id of the string\&. If \fIcreate\fR is zero, new strings will not be added to the pool, instead Id 0 is returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_strn2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, unsigned int\fR \fIlen\fR\fB, int\fR \fIcreate\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Same as pool_str2id, but only \fIlen\fR characters of the string are used\&. This can be used to add substrings to the pool\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_rel2id(Pool *\fR\fIpool\fR\fB, Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, int\fR \fIcreate\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Create a relational dependency from to other dependencies, \fIname\fR and \fIevr\fR, and a \fIflag\fR\&. See the \fBREL_\fR constants for the supported flags\&. As with pool_str2id, \fIcreate\fR defines if new dependencies will get added or Id zero will be returned instead\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_id2langid(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, int\fR \fIcreate\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Attach a language suffix to a string Id\&. This function can be used to create language keyname Ids from keynames, it is functional equivalent to converting the \fIid\fR argument to a string, adding a \(lq:\(rq character and the \fIlang\fR argument to the string and then converting the result back into an Id\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_id2str(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert an Id back into a string\&. If the Id is a relational Id, the \(lqname\(rq part will be converted instead\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_id2rel(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the relation string of a relational Id\&. Returns an empty string if the passed Id is not a relation\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_id2evr(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the \(lqevr\(rq part of a relational Id as string\&. Returns an empty string if the passed Id is not a relation\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_dep2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert an Id back into a string\&. If the passed Id belongs to a relation, a string representing the relation is returned\&. Note that in that case the string is allocated on the pool\(cqs temporary space\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_freeidhashes(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Free the hashes used to unify strings and relations\&. You can use this function to save memory if you know that you will no longer create new strings and relations\&. +.SH "SOLVABLE FUNCTIONS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBSolvable *pool_id2solvable(const Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +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\&. +.sp +.if n \{\ +.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 \{\ +.RE +.\} +.sp +Return a string representing the solvable with the Id \fIp\fR\&. The string will be some canonical representation of the solvable, usually a combination of the name, the version, and the architecture\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_solvable2str(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Same as pool_solvid2str, but instead of the Id, a pointer to the solvable is passed\&. +.SH "DEPENDENCY MATCHING" +.SS "Constants" +.PP +\fBEVRCMP_COMPARE\fR +.RS 4 +Compare all parts of the version, treat missing parts as empty strings\&. +.RE +.PP +\fBEVRCMP_MATCH_RELEASE\fR +.RS 4 +A special mode for rpm version string matching\&. If a version misses a release part, it matches all releases\&. In that case the special values \(lq\-2\(rq and \(lq2\(rq are returned, depending on which of the two versions did not have a release part\&. +.RE +.PP +\fBEVRCMP_MATCH\fR +.RS 4 +A generic match, missing parts always match\&. +.RE +.PP +\fBEVRCMP_COMPARE_EVONLY\fR +.RS 4 +Only compare the epoch and the version parts, ignore the release part\&. +.RE +.SS "Functions" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_evrcmp(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevr1id\fR\fB, Id\fR \fIevr2id\fR\fB, int\fR \fImode\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Compare two version Ids, return \-1 if the first version is less than the second version, 0 if they are identical, and 1 if the first version is bigger than the second one\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_evrcmp_str(const Pool *\fR\fIpool\fR\fB, const char *\fR\fIevr1\fR\fB, const char *\fR\fIevr2\fR\fB, int\fR \fImode\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Same as pool_evrcmp(), but uses strings instead of Ids\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_evrmatch(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevrid\fR\fB, const char *\fR\fIepoch\fR\fB, const char *\fR\fIversion\fR\fB, const char *\fR\fIrelease\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Match a version Id against an epoch, a version and a release string\&. Passing NULL means that the part should match everything\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_match_dep(Pool *\fR\fIpool\fR\fB, Id\fR \fId1\fR\fB, Id\fR \fId2\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Returns \(lq1\(rq if the dependency \fId1\fR (the provider) is matched by the dependency \fId2\fR, otherwise \(lq0\(rq is returned\&. For two dependencies to match, both the \(lqname\(rq parts must match and the version range described by the \(lqevr\(rq parts must overlap\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_match_nevr(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB, Id\fR \fId\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Like pool_match_dep, but the provider is the "self\-provides" dependency of the Solvable \fIs\fR, i\&.e\&. the dependency \(lqs→name = s→evr\(rq\&. +.SH "WHATPROVIDES INDEX" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_createwhatprovides(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Create an index that maps dependency Ids to sets of packages that provide the dependency\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_freewhatprovides(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Free the whatprovides index to save memory\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_whatprovides(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return an offset into the Pool\(cqs whatprovidesdata array\&. The solvables with the Ids stored starting at that offset provide the dependency \fId\fR\&. The solvable list is zero terminated\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId *pool_whatprovides_ptr(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Instead of returning the offset, return the pointer to the Ids stored at that offset\&. Note that this pointer has a very limit validity time, as any call that adds new values to the whatprovidesdata area may reallocate the array\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_queuetowhatprovides(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIq\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Add the contents of the Queue \fIq\fR to the end of the whatprovidesdata array, returning the offset into the array\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_addfileprovides(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_addfileprovides_queue(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIidq\fR\fB, Queue *\fR\fIidqinst\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Same as pool_addfileprovides, but the added Ids are returned in two Queues, \fIidq\fR for all repositories except the one containing the \(lqinstalled\(rq packages, \fIidqinst\fR 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 +.sp +.if n \{\ +.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 \{\ +.RE +.\} +.sp +Clear the cache of the providers for namespace dependencies matching namespace \fIns\fR\&. If the \fIevr\fR argument is non\-zero, the namespace dependency for exactly that dependency is cleared, otherwise all matching namespace dependencies are cleared\&. See the section about Namespace dependencies for further information\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_add_fileconflicts_deps(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIconflicts\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Some package managers like rpm report conflicts when a package installation overwrites a file of another installed package with different content\&. As file content information is not stored in the repository metadata, those conflicts can only be detected after the packages are downloaded\&. Libsolv provides a function to check for such conflicts, pool_findfileconflicts()\&. If conflicts are found, they can be added as special \fBREL_FILECONFLICT\fR provides dependencies, so that the solver will know about the conflict when it is re\-run\&. +.SH "UTILITY FUNCTIONS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *pool_alloctmpspace(Pool *\fR\fIpool\fR\fB, int\fR \fIlen\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Allocate space on the pool\(cqs temporary space area\&. This space has a limited lifetime, it will be automatically freed after a fixed amount (currently 16) of other pool_alloctmpspace() calls are done\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_freetmpspace(Pool *\fR\fIpool\fR\fB, const char *\fR\fIspace\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Give the space allocated with pool_alloctmpspace back to the system\&. You do not have to use this function, as the space is automatically reclaimed, but it can be useful to extend the lifetime of other pointers to the pool\(cqs temporary space area\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_bin2hex(Pool *\fR\fIpool\fR\fB, const unsigned char *\fR\fIbuf\fR\fB, int\fR \fIlen\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert some binary data to hexadecimal, returning a string allocated in the pool\(cqs temporary space area\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *pool_tmpjoin(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Join three strings and return the result in the pool\(cqs temporary space area\&. You can use NULL arguments if you just want to join less strings\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBchar *pool_tmpappend(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Like pool_tmpjoin(), but if the first argument is the last allocated space in the pool\(cqs temporary space area, it will be replaced with the result of the join and no new temporary space slot will be used\&. Thus you can join more than three strings by a combination of one pool_tmpjoin() and multiple pool_tmpappend() calls\&. Note that the \fIstr1\fR pointer is no longer usable after the call\&. +.SH "DATA LOOKUP" +.SS "Constants" +.PP +\fBSOLVID_POS\fR +.RS 4 +Use the data position stored in the pool for the lookup instead of looking up the data of a solvable\&. +.RE +.PP +\fBSOLVID_META\fR +.RS 4 +Use the data stored in the meta section of a repository (or repodata area) instead of looking up the data of a solvable\&. This constant does not work for the pool\(cqs lookup functions, use it for the repo\(cqs or repodata\(cqs lookup functions instead\&. It\(cqs just listed for completeness\&. +.RE +.SS "Functions" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_lookup_str(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the string value stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBunsigned long long pool_lookup_num(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the 64bit unsigned number stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. If no such number is found, the value of the \fInotfound\fR argument is returned instead\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBId pool_lookup_id(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the Id stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_lookup_idarray(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Queue *\fR\fIq\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Fill the queue \fIq\fR with the content of the Id array stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns \(lq1\(rq if an array was found, otherwise the queue will be empty and \(lq0\(rq will be returned\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_lookup_void(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Returns \(lq1\(rq if a void value is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR, otherwise \(lq0\(rq\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_lookup_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. The type of the checksum will be returned over the \fItypep\fR pointer\&. If no such checksum is found, NULL will be returned and the type will be set to zero\&. Note that the result is stored in the Pool\(cqs temporary space area\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst unsigned char *pool_lookup_bin_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns the checksum as binary data, you can use the returned type to calculate the length of the checksum\&. No temporary space area is needed\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_lookup_deltalocation(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, unsigned int *\fR\fImedianrp\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +This is a utility lookup function to return the delta location for a delta rpm\&. As solvables cannot store deltas, you have to use SOLVID_POS as argument and set the Pool\(cqs datapos pointer to point to valid delta rpm data\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_search(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB, int (*\fR\fIcallback\fR\fB)(void *\fR\fIcbdata\fR\fB, Solvable *\fR\fIs\fR\fB, Repodata *\fR\fIdata\fR\fB, Repokey *\fR\fIkey\fR\fB, KeyValue *\fR\fIkv\fR\fB), void *\fR\fIcbdata\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Perform a search on all data stored in the pool\&. You can limit the search area by using the \fIsolvid\fR and \fIkeyname\fR arguments\&. The values can be optionally matched against the \fImatch\fR argument, use NULL if you do not want this matching\&. See the Dataiterator manpage about the possible matches modes and the \fIflags\fR argument\&. For all (matching) values, the callback function is called with the \fIcbdata\fR callback argument and the data describing the value\&. +.SH "JOB AND SELECTION FUNCTIONS" +.sp +A Job consists of two Ids, \fIhow\fR and \fIwhat\fR\&. The \fIhow\fR part describes the action, the job flags, and the selection method while the \fIwhat\fR part is in input for the selection\&. A Selection is a queue consisting of multiple jobs (thus the number of elements in the queue must be a multiple of two)\&. See the Solver manpage for more information about jobs\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_job2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB, Id\fR \fIflagmask\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert a job into a string\&. Useful for debugging purposes\&. The \fIflagmask\fR can be used to mask the flags of the job, use \(lq0\(rq if you do not want to see such flags, \(lq\-1\(rq to see all flags, or a combination of the flags you want to see\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_job2solvables(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIpkgs\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return a list of solvables that the specified job selects\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBint pool_isemptyupdatejob(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Return \(lq1\(rq if the job is an update job that does not work with any installed package, i\&.e\&. the job is basically a no\-op\&. You can use this to turn no\-op update jobs into install jobs (as done by package managers like \(lqzypper\(rq)\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBconst char *pool_selection2str(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIselection\fR\fB, Id\fR \fIflagmask\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Convert a selection into a string\&. Useful for debugging purposes\&. See the pool_job2str() function for the \fIflagmask\fR argument\&. +.SH "ODDS AND ENDS" +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_freeallrepos(Pool *\fR\fIpool\fR\fB, int\fR \fIreuseids\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Free all repos from the pool (including all solvables)\&. If \fIreuseids\fR is true, all Ids of the solvables are free to be reused the next time solvables are created\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +\fBvoid pool_clear_pos(Pool *\fR\fIpool\fR\fB)\fR; +.fi +.if n \{\ +.RE +.\} +.sp +Clear the data position stored in the pool\&. +.SH "ARCHITECTURE POLICIES" +.sp +An architecture policy defines a list of architectures that can be installed on the system, and also the relationship between them (i\&.e\&. the ordering)\&. Architectures can be delimited with three different characters: +.PP +\fB\*(Aq:\*(Aq\fR +.RS 4 +No relationship between the architectures\&. A package of one architecture can not be replaced with one of the other architecture\&. +.RE +.PP +\fB\*(Aq>\*(Aq\fR +.RS 4 +The first architecture is better than the second one\&. An installed package of the second architecture may be replaced with one from the first architecture and vice versa\&. The solver will select the better architecture if the versions are the same\&. +.RE +.PP +\fB\*(Aq=\*(Aq\fR +.RS 4 +The two architectures are freely exchangeable\&. Used to define aliases for architectures\&. +.RE +.sp +An example would be \*(Aqx86_64:i686=athlon>i586\*(Aq\&. This means that x86_64 packages can only be replaced by other x86_64 packages, i686 packages can be replaced by i686 and i586 packages (but i686 packages will be preferred) and athlon is another name for the i686 architecture\&. +.sp +You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_ARCHCHANGE flag\&. +.SH "VENDOR POLICIES" +.sp +Different vendors often compile packages with different features, so Libsolv only replace installed packages of one vendor with packages coming from the same vendor\&. Also, while the version of a package is normally defined by the upstream project, the release part of the version is set by the vendor\(cqs package maintainer, so it\(cqs not meaningful to do version comparisons for packages coming from different vendors\&. +.sp +Vendor in this case means the SOLVABLE_VENDOR string stored in each solvable\&. Sometimes a vendor changes names, or multiple vendors form a group that coordinate their package building, so libsolv offers a way to define that a group of vendors are compatible\&. You do that be defining vendor equivalence classes, packages from a vendor from one class may be replaced with packages from all the other vendors in the class\&. +.sp +There can be multiple equivalence classes, the set of allowed vendor changes for an installed package is calculated by building the union of all of the equivalence classes the vendor of the installed package is part of\&. +.sp +You can turn off the vendor 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\&. 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 +The expression is true if either the first dependency or the second one is true\&. This is useful for package dependencies like \(lqRequires\(rq, where you can specify that either one of the packages need to be installed\&. +.RE +.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 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 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\&. \(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\&. +.SH "NAMESPACE DEPENDENCIES" +.sp +Namespace dependencies can be used to implement dependencies on attributes external to libsolv\&. An example would be a dependency on the language set by the user\&. This types of dependencies are usually only used for \(lqConflicts\(rq or \(lqSupplements\(rq dependencies, as the underlying package manager does not know how to deal with them\&. +.sp +If the library needs to evaluate a namespace dependency, it calls the namespace callback function set in the pool\&. The callback function can return a set of packages that \(lqprovide\(rq the dependency\&. If the dependency is provided by the system, the returned set should consist of just the system solvable (Solvable Id 1)\&. +.sp +The returned set of packages must be returned as offset into the whatprovidesdata array\&. You can use the pool_queuetowhatprovides function to convert a queue into such an offset\&. To ease programming the callback function, the return values \(lq0\(rq and \(lq1\(rq are not interpreted as an offset\&. \(lq0\(rq means that no package is in the return set, \(lq1\(rq means that just the system solvable is in the set\&. +.sp +The returned set is cached, so that for each namespace dependency the callback is just called once\&. If you need to flush the cache (maybe because the user has selected a different language), use the pool_flush_namespaceproviders() function\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/libsolv.3 b/doc/gen/libsolv.3 new file mode 100644 index 0000000..a6ac359 --- /dev/null +++ b/doc/gen/libsolv.3 @@ -0,0 +1,64 @@ +'\" t +.\" Title: Libsolv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "LIBSOLV" "3" "09/14/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" +libsolv \- package dependency solver library using a satisfiability algorithm +.SH "DOCUMENTATION" +.sp +The libsolv documentation is split into multiple parts: +.PP +\fBlibsolv\-history\fR +.RS 4 +how the libsolv library came into existence +.RE +.PP +\fBlibsolv\-constantids\fR +.RS 4 +fixed Ids for often used strings +.RE +.PP +\fBlibsolv\-bindings\fR +.RS 4 +access libsolv from perl/python/ruby +.RE +.PP +\fBlibsolv\-pool\fR +.RS 4 +libsolv\(cqs pool object +.RE +.SH "POINTER VALIDITY" +.sp +Note that all pointers to objects that have an Id have only a limited validity period, with the exception of Repo pointers\&. There are only guaranteed to be valid until a new object of that type is added or an object of that type is removed\&. Thus pointers to Solvable objects are only valid until another solvable is created, because adding a Solvable may relocate the Pool\(cqs Solvable array\&. This is also true for Pool strings, you should use solv_strdup() to create a copy of the string if you want to use it at some later time\&. You should use the Ids in the code and not the pointers, except for short times where you know that the pointer is safe\&. +.sp +Note also that the data lookup functions or the dataiterator also return values with limited lifetime, this is especially true for data stored in the paged data segment of solv files\&. This is normally data that consists of big strings like package descriptions or is not often needed like package checksums\&. Thus looking up a description of a solvable and then looking up the description of a different solvable or even the checksum of the same solvable may invalidate the first result\&. (The dataiterator supports a dataiterator_strdup() function to create a safe copy\&.) +.sp +The language bindings already deal with pointer validity, so you do not have to worry about this issue when using the bindings\&. +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/mdk2solv.1 b/doc/gen/mdk2solv.1 new file mode 100644 index 0000000..ac593f1 --- /dev/null +++ b/doc/gen/mdk2solv.1 @@ -0,0 +1,53 @@ +'\" t +.\" Title: mdk2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "MDK2SOLV" "1" "09/14/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" +mdk2solv \- convert files in Mandriva synthesis format into a solv file +.SH "SYNOPSIS" +.sp +\fBmdk2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The mdk2solv tool reads Mandriva synthesis data (\fBhdlist\fR) from stdin, and writes it as solv file to standard output\&. +.PP +\fB\-i\fR \fIINFO\&.xml\fR +.RS 4 +Also read the info file containing url, license, and src information from the specified xml file\&. +.RE +.PP +\fB\-f\fR \fIFILES\&.xml\fR +.RS 4 +Also read filelist information from the specified xml file\&. +.RE +.SH "SEE ALSO" +.sp +genhdlist2(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/mergesolv.1 b/doc/gen/mergesolv.1 new file mode 100644 index 0000000..65fd756 --- /dev/null +++ b/doc/gen/mergesolv.1 @@ -0,0 +1,45 @@ +'\" t +.\" Title: mergesolv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "MERGESOLV" "1" "09/14/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" +mergesolv \- merge multiple files in solv format into a single one +.SH "SYNOPSIS" +.sp +\fBmergesolv\fR [\fIOPTIONS\fR] \fIFILE1\&.solv\fR \fIFILE2\&.solv\fR \&... +.SH "DESCRIPTION" +.sp +The mergesolv tool reads all solv files specified on the command line, and writes a merged version to standard output\&. +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/repo2solv.1 b/doc/gen/repo2solv.1 new file mode 100644 index 0000000..0a8c3cf --- /dev/null +++ b/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/doc/gen/repomdxml2solv.1 b/doc/gen/repomdxml2solv.1 new file mode 100644 index 0000000..5d459cc --- /dev/null +++ b/doc/gen/repomdxml2solv.1 @@ -0,0 +1,57 @@ +'\" t +.\" Title: repomdxml2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "REPOMDXML2SOLV" "1" "09/14/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" +repomdxml2solv \- convert a repomd\&.xml file into a solv file +.SH "SYNOPSIS" +.sp +\fBrepomdxml2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The repomd\&.xml file is the index file of a rpm\-md repository, containing references to all data file with checksums\&. The repomdxml2solv tool reads the repomd\&.xml file from stdin and writes the parsed data as solv file to standard output\&. The data is stored as meta attributes in the result\&. +.PP +\fB\-q\fR \fIWHAT\fR +.RS 4 +Data query mode: instead of writing a solv file, select the +\fIWHAT\fR +element in the input data and write it to standard output\&. Examples for +\fIWHAT\fR +are +\fBtype\fR +to get a list of all types, and +\fBprimary:location\fR +to get the location of the element with type +\fBprimary\fR\&. +.RE +.SH "SEE ALSO" +.sp +rpmmd2solv(1), mergesolv(1), createrepo(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/rpmdb2solv.1 b/doc/gen/rpmdb2solv.1 new file mode 100644 index 0000000..6f84a7f --- /dev/null +++ b/doc/gen/rpmdb2solv.1 @@ -0,0 +1,95 @@ +'\" t +.\" Title: rpmdb2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "RPMDB2SOLV" "1" "09/14/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" +rpmdb2solv \- convert the rpm database into a solv file +.SH "SYNOPSIS" +.sp +\fBrpmdb2solv\fR [\fIOPTIONS\fR] [\fIREFFILE\&.solv\fR] +.SH "DESCRIPTION" +.sp +The rpmdb2solv tool reads rpm\(cqs installed packages database and writes it in solv file format to standard output\&. You can make use of an old version of the database by specifying a \fIREFFILE\&.solv\fR file\&. +.PP +\fB\-o\fR \fIOUTFILE\fR +.RS 4 +Write the generated solv to +\fIOUTFILE\fR +instead of standard output\&. +.RE +.PP +\fB\-P\fR +.RS 4 +Print percentages as packages are being read in\&. The output format is like rpm\(cqs \-\-percent option\&. +.RE +.PP +\fB\-r\fR \fIROOTDIR\fR +.RS 4 +Use +\fIROOTDIR\fR +as root directory\&. +.RE +.PP +\fB\-k\fR +.RS 4 +Read pubkeys from the rpm database instead of installed packages\&. Note that many distributions stopped storing pubkeys in the database but use a directory like +\fB/var/lib/rpm/pubkeys\fR +instead\&. +.RE +.PP +\fB\-A\fR +.RS 4 +Also scan the +\fB/usr/share/appdata\fR +for installed appdata files and create pseudo packages for each file\&. +.RE +.PP +\fB\-p\fR \fIPRODDIR\fR +.RS 4 +Also read SUSE product files from directory +\fIPRODDIR\fR\&. The standard directory is +\fB/etc/products\&.d\fR\&. +.RE +.PP +\fB\-n\fR +.RS 4 +Do not read any packages from the rpm database\&. This is useful together with +\fB\-p\fR +to only convert SUSE products\&. +.RE +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "SEE ALSO" +.sp +rpms2solv(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/rpmmd2solv.1 b/doc/gen/rpmmd2solv.1 new file mode 100644 index 0000000..5149a1c --- /dev/null +++ b/doc/gen/rpmmd2solv.1 @@ -0,0 +1,48 @@ +'\" t +.\" Title: rpmmd2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "RPMMD2SOLV" "1" "09/14/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" +rpmmd2solv \- convert files in rpm\-md format into a solv file +.SH "SYNOPSIS" +.sp +\fBrpmmd2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The rpmmd2solv tool reads rpm\-md xml data from stdin, and writes it as solv file to standard output\&. It understands the \fBprimary\fR, \fBfilelist\fR, \fBother\fR, and \fBsusedata\fR format\&. +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "SEE ALSO" +.sp +repomdxml2solv(1), mergesolv(1), createrepo(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/rpms2solv.1 b/doc/gen/rpms2solv.1 new file mode 100644 index 0000000..75a89f3 --- /dev/null +++ b/doc/gen/rpms2solv.1 @@ -0,0 +1,80 @@ +'\" t +.\" Title: rpms2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "RPMS2SOLV" "1" "09/14/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" +rpms2solv \- convert one or more rpms into a solv file +.SH "SYNOPSIS" +.sp +\fBrpms2solv\fR [\fIOPTIONS\fR] \fIRPM1\&.rpm\fR \&... +.SH "DESCRIPTION" +.sp +The rpms2solv tool converts the header data from one or more rpms into the solv file written to standard output\&. +.PP +\fB\-m\fR \fIMANIFESTFILE\fR +.RS 4 +Read the rpm file names from the specified +\fIMANIFESTFILE\fR\&. You can use +\fB\-\fR +to read the manifest from standard input\&. +.RE +.PP +\fB\-0\fR +.RS 4 +Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the +\fB\-print0\fR +option in +\fBfind\fR\&. +.RE +.PP +\fB\-F\fR +.RS 4 +Do not put all files from the headers into the file list, but instead use the filtering also found in +\fBcreaterepo\fR\&. +.RE +.PP +\fB\-k\fR +.RS 4 +Read pubkeys instead of rpms\&. +.RE +.PP +\fB\-K\fR +.RS 4 +Read pubkey keyrings instead of rpms\&. +.RE +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "SEE ALSO" +.sp +rpmdb2solv(1) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/solv.1 b/doc/gen/solv.1 new file mode 100644 index 0000000..aae1c6d --- /dev/null +++ b/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/doc/gen/susetags2solv.1 b/doc/gen/susetags2solv.1 new file mode 100644 index 0000000..8dd83d4 --- /dev/null +++ b/doc/gen/susetags2solv.1 @@ -0,0 +1,66 @@ +'\" t +.\" Title: susetags2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "SUSETAGS2SOLV" "1" "09/14/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" +susetags2solv \- convert the susetags repository format into a solv file +.SH "SYNOPSIS" +.sp +\fBsusetags2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The susetags format is most as repository format on most products created by SUSE\&. The susetags2solv reads data from standard input, converts the format into a solv file, and writes it to standard output\&. +.PP +\fB\-c\fR \fICONTENTFILE\fR +.RS 4 +Also parse the specified content file containing meta information about the repository\&. +.RE +.PP +\fB\-q\fR \fIWHAT\fR +.RS 4 +Data query mode: instead of writing a solv file, select the +\fIWHAT\fR +element in the input data and write it to standard output\&. An example for +\fIWHAT\fR +is +\fBdefaultvendor\fR +to get a default vendor for the repository\&. +.RE +.PP +\fB\-M\fR \fIMERGEFILE\&.solv\fR +.RS 4 +Merge the content of the specified solv file into the output\&. +.RE +.PP +\fB\-X\fR +.RS 4 +Autoexpand SUSE pattern and product provides into packages\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/testsolv.1 b/doc/gen/testsolv.1 new file mode 100644 index 0000000..50254f7 --- /dev/null +++ b/doc/gen/testsolv.1 @@ -0,0 +1,62 @@ +'\" t +.\" Title: testsolv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "TESTSOLV" "1" "09/14/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" +testsolv \- run a libsolv testcase through the solver +.SH "SYNOPSIS" +.sp +\fBtestsolv\fR [\fIOPTIONS\fR] \fITESTCASE\fR +.SH "DESCRIPTION" +.sp +The testsolv tools can be used to run a testcase\&. Testcases can either be manually created to test specific features, or they can be written by libsolv\(cqs testcase_write function\&. This is useful to evaluate bug reports about the solver\&. +.PP +\fB\-v\fR +.RS 4 +Increase the debug level of the solver\&. This option can be specified multiple times to further increase the amount of debug data\&. +.RE +.PP +\fB\-r\fR +.RS 4 +Write the output in testcase format instead of human readable text\&. The output can then be used in the result section of the test case\&. If the +\fB\-r\fR +option is given twice, the output is formated for verbatim inclusion\&. +.RE +.PP +\fB\-l\fR \fIPKGSPEC\fR +.RS 4 +Instead of running the solver, list packages in the repositories\&. +.RE +.PP +\fB\-s\fR \fISOLUTIONSPEC\fR +.RS 4 +This is used in the solver test suite to test the calculated solutions to encountered problems\&. +.RE +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/gen/updateinfoxml2solv.1 b/doc/gen/updateinfoxml2solv.1 new file mode 100644 index 0000000..aa60372 --- /dev/null +++ b/doc/gen/updateinfoxml2solv.1 @@ -0,0 +1,43 @@ +'\" t +.\" Title: updateinfoxml2solv +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 09/14/2018 +.\" Manual: LIBSOLV +.\" Source: libsolv +.\" Language: English +.\" +.TH "UPDATEINFOXML2SOLV" "1" "09/14/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" +updateinfoxml2solv \- convert rpm\-md\*(Aqs updateinfo\&.xml format into a solv file +.SH "SYNOPSIS" +.sp +\fBupdateinfoxml2solv\fR [\fIOPTIONS\fR] +.SH "DESCRIPTION" +.sp +The updateinfoxml2solv tool reads rpm\-md\(cqs updateinfo xml data from stdin, and writes it as solv file to standard output\&. Update elements are converted into special \fBpatch:\fR pseudo packages\&. +.SH "SEE ALSO" +.sp +mergesolv(1), createrepo(8) +.SH "AUTHOR" +.sp +Michael Schroeder diff --git a/doc/helix2solv.txt b/doc/helix2solv.txt new file mode 100644 index 0000000..40d523a --- /dev/null +++ b/doc/helix2solv.txt @@ -0,0 +1,28 @@ +helix2solv(1) +============= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +helix2solv - convert legacy helixcode format into a solv file + +Synopsis +-------- +*helix2solv* + +Description +----------- +The helix format was a metadata format used in the RedCarpet +package manager. It's still used in libzypp testcases. +The helix2solv tool reads data in helix format from standard +input and writes it in solv file format to standard output. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/installcheck.txt b/doc/installcheck.txt new file mode 100644 index 0000000..5780772 --- /dev/null +++ b/doc/installcheck.txt @@ -0,0 +1,33 @@ +installcheck(1) +=============== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +installcheck - find out which packages cannot be installed + +Synopsis +-------- +*installcheck* 'ARCH' 'REPO1' 'REPO2'... *--nocheck* 'NREPO1' 'NREPO2'... + +Description +----------- +The installcheck tool checks if all packages in 'REPO1'...'REPON' are +installable. A package is installable if there is a set of packages +from the repositories that satisfies its dependencies. The repositories +after the *--nocheck* option are only used for dependency resolving, +but the tool does not check if the packages in them are installable. + +A Repository can be a solv file, a rpmmd *primary.xml.gz* file, a SUSE +*packages* or *packages.gz* file, or a Debian *Packages* or *Packages.gz* +file. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/libsolv-bindings.txt b/doc/libsolv-bindings.txt new file mode 100644 index 0000000..ac112cf --- /dev/null +++ b/doc/libsolv-bindings.txt @@ -0,0 +1,3793 @@ +Libsolv-Bindings(3) +=================== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +libsolv-bindings - access libsolv from perl/python/ruby + + +Description +----------- +Libsolv's language bindings offer an abstract, object orientated interface +to the library. The supported languages are currently perl, python, and ruby. +All example code (except in the specifics sections, of course) lists first +the ``C-ish'' interface, then the syntax for perl, python, and ruby (in that +order). + + +Perl Specifics +-------------- +Libsolv's perl bindings can be loaded with the following statement: + + use solv; + +Objects are either created by calling the new() method on a class or they +are returned by calling methods on other objects. + + my $pool = solv::Pool->new(); + my $repo = $pool->add_repo("my_first_repo"); + +Swig encapsulates all objects as tied hashes, thus the attributes can be +accessed by treating the object as standard hash reference: + + $pool->{appdata} = 42; + printf "appdata is %d\n", $pool->{appdata}; + +A special exception to this are iterator objects, they are encapsulated as +tied arrays so that it is possible to iterate with a for() statement: + + my $iter = $pool->solvables_iter(); + for my $solvable (@$iter) { ... }; + +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 perl stack: + + my @problems = $solver->solve(\@jobs); + +Due to a bug in swig, stringification does not work for libsolv's objects. +Instead, you have to call the object's str() method. + + print $dep->str() . "\n"; + +Swig implements all constants as numeric variables (instead of the more +natural constant subs), so don't forget the leading ``$'' when accessing a +constant. Also do not forget to prepend the namespace of the constant: + + $pool->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1); + + +Python Specifics +---------------- +The python bindings can be loaded with: + + import solv + +Objects are either created by calling the constructor method for a class or they +are returned by calling methods on other objects. + + pool = solv.Pool() + repo = pool.add_repo("my_first_repo") + +Attributes can be accessed as usual: + + pool.appdata = 42 + print "appdata is %d" % (pool.appdata) + +Iterators also work as expected: + + for solvable in pool.solvables_iter(): + +Arrays are passed and returned as list objects: + + jobs = [] + problems = solver.solve(jobs) + +The bindings define stringification for many classes, some also have a +__repr__ method to ease debugging. + + print dep + print repr(repo) + +Constants are attributes of the corresponding classes: + + pool.set_flag(solv.Pool.POOL_FLAG_OBSOLETEUSESCOLORS, 1); + + +Ruby Specifics +-------------- +The ruby bindings can be loaded with: + + require 'solv' + +Objects are either created by calling the new method on a class or they +are returned by calling methods on other objects. Note that all classes start +with an uppercase letter in ruby, so the class is called ``Solv''. + + pool = Solv::Pool.new + repo = pool.add_repo("my_first_repo") + +Attributes can be accessed as usual: + + pool.appdata = 42 + puts "appdata is #{pool.appdata}" + +Iterators also work as expected: + + for solvable in pool.solvables_iter() do ... + +Arrays are passed and returned as array objects: + + jobs = [] + problems = solver.solve(jobs) + +Most classes define a to_s method, so objects can be easily stringified. +Many also define an inspect() method. + + puts dep + puts repo.inspect + +Constants live in the namespace of the class they belong to: + + pool.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1); + +Note that boolean methods have an added trailing ``?'', to be consistent with +other ruby modules: + + puts "empty" if repo.isempty? + + +Tcl Specifics +------------- +Libsolv's tcl bindings can be loaded with the following statement: + + TCL package require solv + +Objects are either created by calling class name prefixed with ``new_'', +or they are returned by calling methods on other objects. + + TCL set pool [solv::new_Pool] + TCL set repo [$pool add_repo "my_first_repo"] + +Swig provides a ``cget'' method to read object attributes, and a +``configure'' method to write them: + + TCL $pool configure -appdata 42 + TCL puts "appdata is [$pool cget -appdata]" + +The tcl bindings provide a little helper to work with iterators in +a foreach style: + + TCL set iter [$pool solvables_iter] + TCL solv::iter s $iter { ... } + +libsolv's arrays are mapped to tcl's lists: + + TCL set jobs [list $job1 $job2] + TCL set problems [$solver solve $jobs] + TCL puts "We have [llength $problems] problems..." + +Stringification is done by calling the object's ``str'' method. + + TCL puts [$dep str] + +There is one exception: you have to use ``stringify'' for Datamatch +objects, as swig reports a clash with the ``str'' attribute. +Some objects also support a ``=='' method for equality tests, and a +``!='' method. + +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 puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY] + + +The Solv Class +-------------- +This is the main namespace of the library, you cannot create objects of this +type but it contains some useful constants. + +=== CONSTANTS === + +Relational flag constants, the first three can be or-ed together + +*REL_LT*:: +the ``less than'' bit + +*REL_EQ*:: +the ``equals to'' bit + +*REL_GT*:: +the ``greater than'' bit + +*REL_ARCH*:: +used for relations that describe an extra architecture filter, the +version part of the relation is interpreted as architecture. + +Special Solvable Ids + +*SOLVID_META*:: +Access the meta section of a repository or repodata area. This is +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 most likely do not need this constant. + +Constant string Ids + +*ID_NULL*:: +Always zero + +*ID_EMPTY*:: +Always one, describes the empty string + +*SOLVABLE_NAME*:: +The keyname Id of the name of the solvable. + +*...*:: +see the libsolv-constantids manpage for a list of fixed Ids. + + +The Pool Class +-------------- +The pool is libsolv's central resource manager. A pool consists of Solvables, +Repositories, Dependencies, each indexed by Ids. + +=== CLASS METHODS === + + Pool *Pool() + my $pool = solv::Pool->new(); + pool = solv.Pool() + pool = Solv::Pool.new() + +Create a new pool instance. In most cases you just need one pool. +Note that the returned object "owns" the pool, i.e. if the object is +freed, the pool is also freed. You can use the disown method to +break this ownership relation. + +=== ATTRIBUTES === + + void *appdata; /* read/write */ + $pool->{appdata} + pool.appdata + pool.appdata + +Application specific data that may be used in any way by the code using the +pool. + + Solvable solvables[]; /* read only */ + my $solvable = $pool->{solvables}->[$solvid]; + solvable = pool.solvables[solvid] + solvable = pool.solvables[solvid] + +Look up a Solvable by its id. + + Repo repos[]; /* read only */ + my $repo = $pool->{repos}->[$repoid]; + repo = pool.repos[repoid] + repo = pool.repos[repoid] + +Look up a Repository by its id. + + Repo *installed; /* read/write */ + $pool->{installed} = $repo; + pool.installed = repo + pool.installed = repo + +Define which repository contains all the installed packages. + + const char *errstr; /* read only */ + my $err = $pool->{errstr}; + err = pool.errstr + err = pool.errstr + +Return the last error string that was stored in the pool. + +=== CONSTANTS === + +*POOL_FLAG_PROMOTEEPOCH*:: +Promote the epoch of the providing dependency to the requesting +dependency if it does not contain an epoch. Used at some time +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 since rpm-4.9.0. + +*POOL_FLAG_OBSOLETEUSESPROVIDES*:: +Make obsolete type dependency match against provides instead of +just the name and version of packages. Very old versions of rpm +used the name/version, then it got switched to provides and later +switched back again to just name/version. + +*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*:: +An implicit obsoletes is the internal mechanism to remove the +old package on an update. The default is to remove all packages +with the same name, rpm-5 switched to also removing packages +providing the same name. + +*POOL_FLAG_OBSOLETEUSESCOLORS*:: +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 +packages of the same name can be installed in parallel. For +current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be +false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true +(this is the default if FEDORA is defined when libsolv is compiled). + +*POOL_FLAG_NOINSTALLEDOBSOLETES*:: +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*:: +Mandriva added a new field called distepoch that gets checked in +version comparison if the epoch/version/release of two packages +are the same. + +*POOL_FLAG_NOOBSOLETESMULTIVERSION*:: +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. + +*POOL_FLAG_ADDFILEPROVIDESFILTERED*:: +Make the addfileprovides method only add files from the standard +locations (i.e. the ``bin'' and ``etc'' directories). This is +useful if you have only few packages that use non-standard file +dependencies, but you still want the fast speed that addfileprovides() +generates. + +=== METHODS === + + void free() + $pool->free(); + pool.free() + pool.free() + +Force a free of the pool. After this call, you must not access any object +that still references the pool. + + void disown() + $pool->disown(); + pool.disown() + pool.disown() + +Break the ownership relation between the binding object and the pool. After +this call, the pool will not get freed even if the object goes out of +scope. This also means that you must manually call the free method to free +the pool data. + + void setdebuglevel(int level) + $pool->setdebuglevel($level); + pool.setdebuglevel(level) + pool.setdebuglevel(level) + +Set the debug level. A value of zero means no debug output, the higher the +value, the more output is generated. + + int set_flag(int flag, int value) + my $oldvalue = $pool->set_flag($flag, $value); + oldvalue = pool.set_flag(flag, value) + oldvalue = pool.set_flag(flag, value) + + int get_flag(int flag) + my $value = $pool->get_flag($flag); + value = pool.get_flag(flag) + value = pool.get_flag(flag) + +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. + + void set_rootdir(const char *rootdir) + $pool->set_rootdir(rootdir); + pool.set_rootdir(rootdir) + pool.set_rootdir(rootdir) + + const char *get_rootdir() + my $rootdir = $pool->get_rootdir(); + rootdir = pool.get_rootdir() + rootdir = pool.get_rootdir() + +Set/get the rootdir to use. This is useful if you want package management +to work only in some directory, for example if you want to setup a chroot +jail. Note that the rootdir will only be prepended to file paths if the +*REPO_USE_ROOTDIR* flag is used. + + void setarch(const char *arch = 0) + $pool->setarch(); + pool.setarch() + pool.setarch() + +Set the architecture for your system. The architecture is used to determine +which packages are installable. It defaults to the result of ``uname -m''. + + Repo add_repo(const char *name) + $repo = $pool->add_repo($name); + repo = pool.add_repo(name) + repo = pool.add_repo(name) + +Add a Repository with the specified name to the pool. The repository is empty +on creation, use the repository methods to populate it with packages. + + Repoiterator repos_iter() + for my $repo (@{$pool->repos_iter()}) + for repo in pool.repos_iter(): + for repo in pool.repos_iter() + +Iterate over the existing repositories. + + Solvableiterator solvables_iter() + for my $solvable (@{$pool->solvables_iter()}) + for solvable in pool.solvables_iter(): + for solvable in pool.solvables_iter() + +Iterate over the existing solvables. + + Dep Dep(const char *str, bool create = 1) + my $dep = $pool->Dep($string); + dep = pool.Dep(string) + dep = pool.Dep(string) + +Create an object describing a string or dependency. If the string is currently +not in the pool and _create_ is false, *undef*/*None*/*nil* is returned. + + void addfileprovides() + $pool->addfileprovides(); + pool.addfileprovides() + pool.addfileprovides() + + Id *addfileprovides_queue() + my @ids = $pool->addfileprovides_queue(); + ids = pool.addfileprovides_queue() + ids = pool.addfileprovides_queue() + +Some package managers like rpm allow dependencies on files contained in other +packages. To allow libsolv to deal with those dependencies in an efficient way, +you need to call the addfileprovides method after creating and reading all +repositories. This method will scan all dependency for file names and then scan +all packages for matching files. If a filename has been matched, it will be +added to the provides list of the corresponding package. The +addfileprovides_queue variant works the same way but returns an array +containing all file dependencies. 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 createwhatprovides() + $pool->createwhatprovides(); + pool.createwhatprovides() + pool.createwhatprovides() + +Create the internal ``whatprovides'' hash over all of the provides of all +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(). + + Solvable *whatprovides(DepId dep) + my @solvables = $pool->whatprovides($dep); + solvables = pool.whatprovides(dep) + solvables = pool.whatprovides(dep) + +Return all solvables that provide the specified dependency. You can use either +a Dep object or a simple Id as argument. + + Solvable *best_solvables(Solvable *solvables, int flags = 0) + my @solvables = $pool->best_solvables($solvables); + solvables = pool.best_solvables(solvables) + solvables = pool.best_solvables(solvables) + +Filter list of solvables by repo priority, architecture and version. + + Solvable *whatcontainsdep(Id keyname, DepId dep, Id marker = -1) + my @solvables = $pool->whatcontainsdep($keyname, $dep) + solvables = pool.whatcontainsdep(keyname, dep) + solvables = pool.whatcontainsdep(keyname, dep) + +Return all solvables for which keyname contains the dependency. + + Solvable *whatmatchesdep(Id keyname, DepId dep, Id marker = -1) + my @solvables = $pool->whatmatchesdep($keyname, $sdep) + solvables = pool.whatmatchesdep(keyname, dep) + solvables = pool.whatmatchesdep(keyname, dep) + +Return all solvables that have dependencies in keyname that match the dependency. + + Solvable *whatmatchessolvable(Id keyname, Solvable solvable, Id marker = -1) + my @solvables = $pool->whatmatchessolvable($keyname, $solvable) + solvables = pool.whatmatchessolvable(keyname, solvable) + solvables = pool.whatmatchessolvable(keyname, solvable) + +Return all solvables that match package dependencies against solvable's +provides. + + Id *matchprovidingids(const char *match, int flags) + my @ids = $pool->matchprovidingids($match, $flags); + ids = pool.matchprovidingids(match, flags) + ids = pool.matchprovidingids(match, flags) + +Search the names of all provides and return the ones matching the specified +string. See the Dataiterator class for the allowed flags. + + Id towhatprovides(Id *ids) + my $offset = $pool->towhatprovides(\@ids); + offset = pool.towhatprovides(ids) + offset = pool.towhatprovides(ids) + +``Internalize'' an array containing Ids. The returned value can be used to +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) + bool = pool.isknownarch?(id) + +Return true if the specified Id describes a known architecture. + + Solver Solver() + my $solver = $pool->Solver(); + solver = pool.Solver() + solver = pool.Solver() + +Create a new solver object. + + Job Job(int how, Id what) + my $job = $pool->Job($how, $what); + job = pool.Job(how, what) + job = pool.Job(how, what) + +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(); + sel = pool.Selection() + sel = pool.Selection() + +Create an empty selection. Useful as a starting point for merging other +selections. + + Selection Selection_all() + my $sel = $pool->Selection_all(); + sel = pool.Selection_all() + sel = pool.Selection_all() + +Create a selection containing all packages. Useful as starting point for +intersecting other selections or for update/distupgrade jobs. + + Selection select(const char *name, int flags) + my $sel = $pool->select($name, $flags); + sel = pool.select(name, flags) + sel = pool.select(name, flags) + +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. + + Selection matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1) + my $sel = $pool->matchsolvable($solvable, $flags, $keyname); + sel = pool.matchsolvable(solvable, flags, keyname) + sel = pool.matchsolvable(solvable, flags, keyname) + +Create a selection by matching package dependencies against the specified +solvable's provides. + + void setpooljobs(Jobs *jobs) + $pool->setpooljobs(\@jobs); + pool.setpooljobs(jobs) + pool.setpooljobs(jobs) + + Job *getpooljobs() + @jobs = $pool->getpooljobs(); + jobs = pool.getpooljobs() + jobs = pool.getpooljobs() + +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. + + void set_loadcallback(Callable *callback) + $pool->setloadcallback(\&callbackfunction); + pool.setloadcallback(callbackfunction) + pool.setloadcallback { |repodata| ... } + +Set the callback function called when repository metadata needs to be loaded on +demand. To make use of this feature, you need to create repodata stubs that +tell the library which data is available but not loaded. If later on the data +needs to be accessed, the callback function is called with a repodata argument. +You can then load the data (maybe fetching it first from a remote server). +The callback should return true if the data has been made available. + + /* bindings only */ + $pool->appdata_disown() + pool.appdata_disown() + pool.appdata_disown() + +Decrement the reference count of the appdata object. This can be used to break +circular references (e.g. if the pool's appdata value points to some meta data +structure that contains a pool handle). If used incorrectly, this method can +lead to application crashes, so beware. (This method is a no-op for ruby and tcl.) + + Id *get_considered_list() + my @ids = $pool->get_considered_list(); + ids = pool.get_considered_list() + ids = pool.get_considered_list() + + void set_considered_list(Id *ids) + $pool->set_considered_list(\@ids); + pool.set_considered_list(ids) + pool.set_considered_list(ids) + +Get/set the list of solvables that are eligible for installation. Note that +you need to recreate the whatprovides hash after changing the list. + + Id *get_disabled_list() + my @ids = $pool->get_disabled_list(); + ids = pool.get_disabled_list() + ids = pool.get_disabled_list() + + void set_disabled_list(Id *ids) + $pool->set_disabled_list(\@ids); + pool.set_disabled_list(ids) + pool.set_disabled_list(ids) + +Get/set the list of solvables that are not eligible for installation. This is +basically the inverse of the ``considered'' methods above, i.e. calling +``set_disabled_list()'' with an empty list will make all solvables eligible for +installation. Note you need to recreate the whatprovides hash after changing the +list. + +=== DATA RETRIEVAL METHODS === + +In the following functions, the _keyname_ argument describes what to retrieve. +For the standard cases you can use the available Id constants. For example, + + $solv::SOLVABLE_SUMMARY + solv.SOLVABLE_SUMMARY + Solv::SOLVABLE_SUMMARY + +selects the ``Summary'' entry of a solvable. The _solvid_ argument selects the +desired solvable by Id. + + const char *lookup_str(Id solvid, Id keyname) + my $string = $pool->lookup_str($solvid, $keyname); + string = pool.lookup_str(solvid, keyname) + string = pool.lookup_str(solvid, keyname) + + Id lookup_id(Id solvid, Id keyname) + my $id = $pool->lookup_id($solvid, $keyname); + id = pool.lookup_id(solvid, keyname) + id = pool.lookup_id(solvid, keyname) + + unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) + my $num = $pool->lookup_num($solvid, $keyname); + num = pool.lookup_num(solvid, keyname) + num = pool.lookup_num(solvid, keyname) + + bool lookup_void(Id solvid, Id keyname) + my $bool = $pool->lookup_void($solvid, $keyname); + bool = pool.lookup_void(solvid, keyname) + bool = pool.lookup_void(solvid, keyname) + + Id *lookup_idarray(Id solvid, Id keyname) + my @ids = $pool->lookup_idarray($solvid, $keyname); + ids = pool.lookup_idarray(solvid, keyname) + ids = pool.lookup_idarray(solvid, keyname) + + Chksum lookup_checksum(Id solvid, Id keyname) + my $chksum = $pool->lookup_checksum($solvid, $keyname); + chksum = pool.lookup_checksum(solvid, keyname) + chksum = pool.lookup_checksum(solvid, keyname) + +Lookup functions. Return the data element stored in the specified solvable. +You should probably use the methods of the Solvable class instead. + + Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0) + my $di = $pool->Dataiterator($keyname, $match, $flags); + di = pool.Dataiterator(keyname, match, flags) + di = pool.Dataiterator(keyname, match, flags) + + Dataiterator Dataiterator_solvid(Id solvid, Id keyname, const char *match = 0, int flags = 0) + my $di = $pool->Dataiterator($solvid, $keyname, $match, $flags); + di = pool.Dataiterator(solvid, keyname, match, flags) + di = pool.Dataiterator(solvid, keyname, match, flags) + + for my $d (@$di) + for d in di: + for d in di + +Iterate over the matching data elements. See the Dataiterator class for more +information. The Dataiterator method iterates over all solvables in the pool, +whereas the Dataiterator_solvid only iterates over the specified solvable. + +=== ID METHODS === + +The following methods deal with Ids, i.e. integers representing objects in the +pool. They are considered ``low level'', in most cases you would not use them +but instead the object orientated methods. + + Repo id2repo(Id id) + $repo = $pool->id2repo($id); + repo = pool.id2repo(id) + repo = pool.id2repo(id) + +Lookup an existing Repository by id. You can also do this by using the *repos* +attribute. + + Solvable id2solvable(Id id) + $solvable = $pool->id2solvable($id); + solvable = pool.id2solvable(id) + solvable = pool.id2solvable(id) + +Lookup an existing Repository by id. You can also do this by using the +*solvables* attribute. + + const char *solvid2str(Id id) + my $str = $pool->solvid2str($id); + str = pool.solvid2str(id) + str = pool.solvid2str(id) + +Return a string describing the Solvable with the specified id. The string +consists of the name, version, and architecture of the Solvable. + + Id str2id(const char *str, bool create = 1) + my $id = pool->str2id($string); + id = pool.str2id(string) + id = pool.str2id(string) + + const char *id2str(Id id) + $string = pool->id2str($id); + string = pool.id2str(id) + string = pool.id2str(id) + +Convert a string into an Id and back. If the string is currently not in the +pool and _create_ is false, zero is returned. + + Id rel2id(Id name, Id evr, int flags, bool create = 1) + my $id = pool->rel2id($nameid, $evrid, $flags); + id = pool.rel2id(nameid, evrid, flags) + id = pool.rel2id(nameid, evrid, flags) + +Create a ``relational'' dependency. Such dependencies consist of a name part, +_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 + Solv::REL_EQ | Solv::REL_GT | Solv::REL_LT + +Thus, if you want a ``\<='' relation, you would use *REL_LT | REL_EQ*. + + Id id2langid(Id id, const char *lang, bool create = 1) + my $id = $pool->id2langid($id, $language); + id = pool.id2langid(id, language) + id = pool.id2langid(id, language) + +Create a language specific Id from some other id. This function simply converts +the id into a string, appends a dot and the specified language to the string +and converts the result back into an Id. + + const char *dep2str(Id id) + $string = pool->dep2str($id); + string = pool.dep2str(id) + string = pool.dep2str(id) + +Convert a dependency id into a string. If the id is just a string, this +function has the same effect as id2str(). For relational dependencies, the +result is the correct ``name relation evr'' string. + + +The Dependency Class +-------------------- +The dependency class is an object orientated way to work with strings and +dependencies. Internally, dependencies are represented as Ids, i.e. simple +numbers. Dependency objects can be constructed by using the Pool's Dep() +method. + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $dep->{pool} + dep.pool + dep.pool + +Back reference to the pool this dependency belongs to. + + Id id; /* read only */ + $dep->{id} + dep.id + dep.id + +The id of this dependency. + +=== METHODS === + + Dep Rel(int flags, DepId evrid, bool create = 1) + my $reldep = $dep->Rel($flags, $evrdep); + reldep = dep.Rel(flags, evrdep) + reldep = dep.Rel(flags, evrdep) + +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(); + sel = dep.Selection_name() + sel = dep.Selection_name() + +Create a Selection from a dependency. The selection consists of all packages +that have a name equal to the dependency. If the dependency is of a relational +type, the packages version must also fulfill the dependency. + + Selection Selection_provides(int setflags = 0) + my $sel = $dep->Selection_provides(); + sel = dep.Selection_provides() + sel = dep.Selection_provides() + +Create a Selection from a dependency. The selection consists of all packages +that have at least one provides matching the dependency. + + const char *str() + my $str = $dep->str(); + str = $dep.str() + str = $dep.str() + +Return a string describing the dependency. + + + my $str = $dep->str; + str = str(dep) + str = dep.to_s + +Same as calling the str() method. + + + if ($dep1 == $dep2) + if dep1 == dep2: + if dep1 == dep2 + +Two dependencies are equal if they are part of the same pool and have the same +ids. + + +The Repository Class +-------------------- +A Repository describes a group of packages, normally coming from the same +source. Repositories are created by the Pool's add_repo() method. + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $repo->{pool} + repo.pool + repo.pool + +Back reference to the pool this dependency belongs to. + + Id id; /* read only */ + $repo->{id} + repo.id + repo.id + +The id of the repository. + + const char *name; /* read/write */ + $repo->{name} + repo.name + repo.name + +The repositories name. To libsolv, the name is just a string with no specific +meaning. + + int priority; /* read/write */ + $repo->{priority} + repo.priority + repo.priority + +The priority of the repository. A higher number means that packages of this +repository will be chosen over other repositories, even if they have a greater +package version. + + int subpriority; /* read/write */ + $repo->{subpriority} + repo.subpriority + repo.subpriority + +The sub-priority of the repository. This value is compared when the priorities +of two repositories are the same. It is useful to make the library prefer +on-disk repositories to remote ones. + + int nsolvables; /* read only */ + $repo->{nsolvables} + repo.nsolvables + repo.nsolvables + +The number of solvables in this repository. + + void *appdata; /* read/write */ + $repo->{appdata} + repo.appdata + repo.appdata + +Application specific data that may be used in any way by the code using the +repository. + + Datapos *meta; /* read only */ + $repo->{meta} + repo.meta + repo.meta + +Return a Datapos object of the repodata's metadata. You can use the lookup +methods of the Datapos class to lookup metadata attributes, like the repository +timestamp. + +=== CONSTANTS === + +*REPO_REUSE_REPODATA*:: +Reuse the last repository data area (``repodata'') instead of creating a +new area. + +*REPO_NO_INTERNALIZE*:: +Do not internalize the added repository data. This is useful if +you plan to add more data because internalization is a costly +operation. + +*REPO_LOCALPOOL*:: +Use the repodata's pool for Id storage instead of the global pool. Useful +if you don't want to pollute the global pool with many unneeded ids, like +when storing the filelist. + +*REPO_USE_LOADING*:: +Use the repodata that is currently being loaded instead of creating a new +one. This only makes sense if used in a load callback. + +*REPO_EXTEND_SOLVABLES*:: +Do not create new solvables for the new data, but match existing solvables +and add the data to them. Repository metadata is often split into multiple +parts, with one primary file describing all packages and other parts +holding information that is normally not needed, like the changelog. + +*REPO_USE_ROOTDIR*:: +Prepend the pool's rootdir to the path when doing file operations. + +*REPO_NO_LOCATION*:: +Do not add a location element to the solvables. Useful if the solvables +are not in the final position, so you can add the correct location later +in your code. + +*SOLV_ADD_NO_STUBS*:: +Do not create stubs for repository parts that can be downloaded on demand. + +*SUSETAGS_RECORD_SHARES*:: +This is specific to the add_susetags() method. Susetags allows one to refer to +already read packages to save disk space. If this data sharing needs to +work over multiple calls to add_susetags, you need to specify this flag so +that the share information is made available to subsequent calls. + +=== METHODS === + + void free(bool reuseids = 0) + $repo->free(); + repo.free() + repo.free() + +Free the repository and all solvables it contains. If _reuseids_ is set to +true, the solvable ids and the repository id may be reused by the library when +added new solvables. Thus you should leave it false if you are not sure that +somebody holds a reference. + + void empty(bool reuseids = 0) + $repo->empty(); + repo.empty() + repo.empty() + +Free all the solvables in a repository. The repository will be empty after this +call. See the free() method for the meaning of _reuseids_. + + bool isempty() + $repo->isempty() + repo.empty() + repo.empty? + +Return true if there are no solvables in this repository. + + void internalize() + $repo->internalize(); + repo.internalize() + repo.internalize() + +Internalize added data. Data must be internalized before it is available to the +lookup and data iterator functions. + + bool write(FILE *fp) + $repo->write($fp) + repo.write(fp) + repo.write(fp) + +Write a repo as a ``solv'' file. These files can be read very fast and thus are +a good way to cache repository data. Returns false if there was some error +writing the file. + + Solvableiterator solvables_iter() + for my $solvable (@{$repo->solvables_iter()}) + for solvable in repo.solvables_iter(): + for solvable in repo.solvables_iter() + +Iterate over all solvables in a repository. + + Repodata add_repodata(int flags = 0) + my $repodata = $repo->add_repodata(); + repodata = repo.add_repodata() + repodata = repo.add_repodata() + +Add a new repodata area to the repository. This is normally automatically +done by the repo_add methods, so you need this method only in very +rare circumstances. + + void create_stubs() + $repo->create_stubs(); + repo.create_stubs() + repo.create_stubs() + +Calls the create_stubs() repodata method for the last repodata of the +repository. + + bool iscontiguous() + $repo->iscontiguous() + repo.iscontiguous() + repo.iscontiguous? + +Return true if the solvables of this repository are all in a single block with +no holes, i.e. they have consecutive ids. + + Repodata first_repodata() + my $repodata = $repo->first_repodata(); + repodata = repo.first_repodata() + repodata = repo.first_repodata() + +Checks if all repodatas but the first repodata are extensions, and return the +first repodata if this is the case. Useful if you want to do a store/retrieve +sequence on the repository to reduce the memory using and enable paging, as +this does not work if the repository contains multiple non-extension repodata +areas. + + Selection Selection(int setflags = 0) + my $sel = $repo->Selection(); + sel = repo.Selection() + sel = repo.Selection() + +Create a Selection consisting of all packages in the repository. + + Dataiterator Dataiterator(Id key, const char *match = 0, int flags = 0) + my $di = $repo->Dataiterator($keyname, $match, $flags); + di = repo.Dataiterator(keyname, match, flags) + di = repo.Dataiterator(keyname, match, flags) + + Dataiterator Dataiterator_meta(Id key, const char *match = 0, int flags = 0) + my $di = $repo->Dataiterator_meta($keyname, $match, $flags); + di = repo.Dataiterator_meta(keyname, match, flags) + di = repo.Dataiterator_meta(keyname, match, flags) + + for my $d (@$di) + for d in di: + for d in di + +Iterate over the matching data elements in this repository. See the +Dataiterator class for more information. The Dataiterator() method +iterates over all solvables in a repository, whereas the Dataiterator_meta +method only iterates over the repository's meta data. + + + my $str = $repo->str; + str = str(repo) + str = repo.to_s + +Return the name of the repository, or "Repo#" if no name is set. + + + if ($repo1 == $repo2) + if repo1 == repo2: + if repo1 == repo2 + +Two repositories are equal if they belong to the same pool and have the same id. + +=== DATA ADD METHODS === + + Solvable add_solvable() + $repo->add_solvable(); + repo.add_solvable() + repo.add_solvable() + +Add a single empty solvable to the repository. Returns a Solvable object, see +the Solvable class for more information. + + bool add_solv(const char *name, int flags = 0) + $repo->add_solv($name); + repo.add_solv(name) + repo.add_solv(name) + + bool add_solv(FILE *fp, int flags = 0) + $repo->add_solv($fp); + repo.add_solv(fp) + repo.add_solv(fp) + +Read a ``solv'' file and add its contents to the repository. These files can be +written with the write() method and are normally used as fast cache for +repository metadata. + + bool add_rpmdb(int flags = 0) + $repo->add_rpmdb(); + repo.add_rpmdb() + repo.add_rpmdb() + + bool add_rpmdb_reffp(FILE *reffp, int flags = 0) + $repo->add_rpmdb_reffp($reffp); + repo.add_rpmdb_reffp(reffp) + repo.add_rpmdb_reffp(reffp) + +Add the contents of the rpm database to the repository. If a solv file +containing an old version of the database is available, it can be passed as +reffp to speed up reading. + + Solvable add_rpm(const char *filename, int flags = 0) + my $solvable = $repo->add_rpm($filename); + solvable = repo.add_rpm(filename) + solvable = repo.add_rpm(filename) + +Add the metadata of a single rpm package to the repository. + + bool add_rpmdb_pubkeys(int flags = 0) + $repo->add_rpmdb_pubkeys(); + repo.add_rpmdb_pubkeys() + repo.add_rpmdb_pubkeys() + +Add all pubkeys contained in the rpm database to the repository. Note that +newer rpm versions also allow to store the pubkeys in some directory instead +of the rpm database. + + Solvable add_pubkey(const char *keyfile, int flags = 0) + my $solvable = $repo->add_pubkey($keyfile); + solvable = repo.add_pubkey(keyfile) + solvable = repo.add_pubkey(keyfile) + +Add a pubkey from a file to the repository. + + bool add_rpmmd(FILE *fp, const char *language, int flags = 0) + $repo->add_rpmmd($fp, undef); + repo.add_rpmmd(fp, None) + repo.add_rpmmd(fp, nil) + +Add metadata stored in the "rpm-md" format (i.e. from files in the ``repodata'' +directory) to a repository. Supported files are "primary", "filelists", +"other", "suseinfo". Do not forget to specify the *REPO_EXTEND_SOLVABLES* for +extension files like "filelists" and "other". Use the _language_ parameter if +you have language extension files, otherwise simply use a *undef*/*None*/*nil* +parameter. + + bool add_repomdxml(FILE *fp, int flags = 0) + $repo->add_repomdxml($fp); + repo.add_repomdxml(fp) + repo.add_repomdxml(fp) + +Add the repomd.xml meta description from the "rpm-md" format to the repository. +This file contains information about the repository like keywords, and also a +list of all database files with checksums. The data is added to the "meta" +section of the repository, i.e. no package gets created. + + bool add_updateinfoxml(FILE *fp, int flags = 0) + $repo->add_updateinfoxml($fp); + repo.add_updateinfoxml(fp) + repo.add_updateinfoxml(fp) + +Add the updateinfo.xml file containing available maintenance updates to the +repository. All updates are created as special packages that have a "patch:" +prefix in their name. + + bool add_deltainfoxml(FILE *fp, int flags = 0) + $repo->add_deltainfoxml($fp); + repo.add_deltainfoxml(fp) + repo.add_deltainfoxml(fp) + +Add the deltainfo.xml file (also called prestodelta.xml) containing available +delta-rpms to the repository. The data is added to the "meta" section, i.e. no +package gets created. + + bool add_debdb(int flags = 0) + $repo->add_debdb(); + repo.add_debdb() + repo.add_debdb() + +Add the contents of the debian installed package database to the repository. + + bool add_debpackages(FILE *fp, int flags = 0) + $repo->add_debpackages($fp); + repo.add_debpackages($fp) + repo.add_debpackages($fp) + +Add the contents of the debian repository metadata (the "packages" file) +to the repository. + + Solvable add_deb(const char *filename, int flags = 0) + my $solvable = $repo->add_deb($filename); + solvable = repo.add_deb(filename) + solvable = repo.add_deb(filename) + +Add the metadata of a single deb package to the repository. + + bool add_mdk(FILE *fp, int flags = 0) + $repo->add_mdk($fp); + repo.add_mdk(fp) + repo.add_mdk(fp) + +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_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*. + + bool add_arch_repo(FILE *fp, int flags = 0) + $repo->add_arch_repo($fp); + repo.add_arch_repo(fp) + repo.add_arch_repo(fp) + +Add the contents of the archlinux repository metadata (the ".db.tar" file) to +the repository. + + bool add_arch_local(const char *dir, int flags = 0) + $repo->add_arch_local($dir); + repo.add_arch_local(dir) + repo.add_arch_local(dir) + +Add the contents of the archlinux installed package database to the repository. +The _dir_ parameter is usually set to "/var/lib/pacman/local". + + bool add_content(FILE *fp, int flags = 0) + $repo->add_content($fp); + repo.add_content(fp) + repo.add_content(fp) + +Add the ``content'' meta description from the susetags format to the repository. +This file contains information about the repository like keywords, and also +a list of all database files with checksums. The data is added to the "meta" +section of the repository, i.e. no package gets created. + + bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0) + $repo->add_susetags($fp, $defvendor, $language); + repo.add_susetags(fp, defvendor, language) + repo.add_susetags(fp, defvendor, language) + +Add repository metadata in the susetags format to the repository. Like with +add_rpmmd, you can specify a language if you have language extension files. The +_defvendor_ parameter provides a default vendor for packages with missing +vendors, it is usually provided in the content file. + + bool add_products(const char *dir, int flags = 0) + $repo->add_products($dir); + repo.add_products(dir) + repo.add_products(dir) + +Add the installed SUSE products database to the repository. The _dir_ parameter +is usually "/etc/products.d". + + +The Solvable Class +------------------ +A solvable describes all the information of one package. Each solvable +belongs to one repository, it can be added and filled manually but in +most cases solvables will get created by the repo_add methods. + +=== ATTRIBUTES === + + Repo *repo; /* read only */ + $solvable->{repo} + solvable.repo + solvable.repo + +The repository this solvable belongs to. + + Pool *pool; /* read only */ + $solvable->{pool} + solvable.pool + solvable.pool + +The pool this solvable belongs to, same as the pool of the repo. + + Id id; /* read only */ + $solvable->{id} + solvable.id + solvable.id + +The specific id of the solvable. + + char *name; /* read/write */ + $solvable->{name} + solvable.name + solvable.name + + char *evr; /* read/write */ + $solvable->{evr} + solvable.evr + solvable.evr + + char *arch; /* read/write */ + $solvable->{arch} + solvable.arch + solvable.arch + + char *vendor; /* read/write */ + $solvable->{vendor} + solvable.vendor + solvable.vendor + +Easy access to often used attributes of solvables. They are +internally stored as Ids. + + Id nameid; /* read/write */ + $solvable->{nameid} + solvable.nameid + solvable.nameid + + Id evrid; /* read/write */ + $solvable->{evrid} + solvable.evrid + solvable.evrid + + Id archid; /* read/write */ + $solvable->{archid} + solvable.archid + solvable.archid + + Id vendorid; /* read/write */ + $solvable->{vendorid} + solvable.vendorid + solvable.vendorid + +Raw interface to the ids. Useful if you want to search for +a specific id and want to avoid the string compare overhead. + +=== METHODS === + + const char *lookup_str(Id keyname) + my $string = $solvable->lookup_str($keyname); + string = solvable.lookup_str(keyname) + string = solvable.lookup_str(keyname) + + Id lookup_id(Id keyname) + my $id = $solvable->lookup_id($keyname); + id = solvable.lookup_id(keyname) + id = solvable.lookup_id(keyname) + + 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) + + bool lookup_void(Id keyname) + my $bool = $solvable->lookup_void($keyname); + bool = solvable.lookup_void(keyname) + bool = solvable.lookup_void(keyname) + + Chksum lookup_checksum(Id keyname) + my $chksum = $solvable->lookup_checksum($keyname); + chksum = solvable.lookup_checksum(keyname) + chksum = solvable.lookup_checksum(keyname) + + Id *lookup_idarray(Id keyname, Id marker = -1) + my @ids = $solvable->lookup_idarray($keyname); + ids = solvable.lookup_idarray(keyname) + ids = solvable.lookup_idarray(keyname) + + Dep *lookup_deparray(Id keyname, Id marker = -1) + my @deps = $solvable->lookup_deparray($keyname); + deps = solvable.lookup_deparray(keyname) + deps = solvable.lookup_deparray(keyname) + +Generic lookup methods. Retrieve data stored for the specific keyname. +The lookup_idarray() method will return an array of Ids, use +lookup_deparray if you want an array of Dependency objects instead. +Some Id arrays contain two parts of data divided by a specific marker, +for example the provides array uses the SOLVABLE_FILEMARKER id to +store both the ids provided by the package and the ids added by +the addfileprovides method. The default, -1, translates to the +correct marker for the keyname and returns the first part of the +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, $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) + di = solvable.Dataiterator(keyname, match, flags) + + for my $d (@$di) + for d in di: + for d in di + +Iterate over the matching data elements. See the Dataiterator class for more +information. + + void add_deparray(Id keyname, DepId dep, Id marker = -1); + $solvable->add_deparray($keyname, $dep); + solvable.add_deparray(keyname, dep) + solvable.add_deparray(keyname, dep) + +Add a new dependency to the attributes stored in keyname. + + void unset(Id keyname); + $solvable->unset($keyname); + solvable.unset(keyname) + solvable.unset(keyname) + +Delete data stored for the specific keyname. + + bool installable(); + $solvable->installable() + solvable.installable() + solvable.installable? + +Return true if the solvable is installable on the system. Solvables +are not installable if the system does not support their architecture. + + bool isinstalled(); + $solvable->isinstalled() + solvable.isinstalled() + solvable.isinstalled? + +Return true if the solvable is installed on the system. + + bool identical(Solvable *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) + +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() + sel = solvable.Selection() + +Create a Selection containing just the single solvable. + + const char *str() + my $str = $solvable->str(); + str = $solvable.str() + str = $solvable.str() + +Return a string describing the solvable. The string consists of the name, +version, and architecture of the Solvable. + + + my $str = $solvable->str; + str = str(solvable) + str = solvable.to_s + +Same as calling the str() method. + + + if ($solvable1 == $solvable2) + if solvable1 == solvable2: + if solvable1 == solvable2 + +Two solvables are equal if they are part of the same pool and have the same +ids. + + +The Dataiterator Class +---------------------- +Dataiterators can be used to do complex string searches or +to iterate over arrays. They can be created via the +constructors in the Pool, Repo, and Solvable classes. The +Repo and Solvable constructors will limit the search to +the repository or the specific package. + +=== CONSTANTS === + +*SEARCH_STRING*:: +Return a match if the search string matches the value. + +*SEARCH_STRINGSTART*:: +Return a match if the value starts with the search string. + +*SEARCH_STRINGEND*:: +Return a match if the value ends with the search string. + +*SEARCH_SUBSTRING*:: +Return a match if the search string can be matched somewhere in the value. + +*SEARCH_GLOB*:: +Do a glob match of the search string against the value. + +*SEARCH_REGEX*:: +Do a regular expression match of the search string against the value. + +*SEARCH_NOCASE*:: +Ignore case when matching strings. Works for all the above match types. + +*SEARCH_FILES*:: +Match the complete filenames of the file list, not just the base name. + +*SEARCH_COMPLETE_FILELIST*:: +When matching the file list, check every file of the package not just the +subset from the primary metadata. + +*SEARCH_CHECKSUMS*:: +Allow the matching of checksum entries. + +=== METHODS === + + void prepend_keyname(Id keyname); + $di->prepend_keyname($keyname); + di.prepend_keyname(keyname) + di.prepend_keyname(keyname) + +Do a sub-search in the array stored in keyname. + + void skip_solvable(); + $di->skip_solvable(); + di.skip_solvable() + di.skip_solvable() + +Stop matching the current solvable and advance to the next +one. + + + for my $d (@$di) + for d in di: + for d in di + +Iterate through the matches. If there is a match, the object +in d will be of type Datamatch. + +The Datamatch Class +------------------- +Objects of this type will be created for every value matched +by a dataiterator. + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $d->{pool} + d.pool + d.pool + +Back pointer to pool. + + Repo *repo; /* read only */ + $d->{repo} + d.repo + d.repo + +The repository containing the matched object. + + Solvable *solvable; /* read only */ + $d->{solvable} + d.solvable + d.solvable + +The solvable containing the value that was matched. + + Id solvid; /* read only */ + $d->{solvid} + d.solvid + d.solvid + +The id of the solvable that matched. + + Id key_id; + $d->{key_id} + d.key_id + d.key_id + + const char *key_idstr; + $d->{key_idstr} + d.key_idstr + d.key_idstr + +The keyname that matched, either as id or string. + + Id type_id; + $d->{type_id} + d.type_id + d.type_id + + const char *type_idstr; + $d->{type_idstr}; + d.type_idstr + d.type_idstr + +The key type of the value that was matched, either as id or string. + + Id id; + $d->{id} + d.id + d.id + + Id idstr; + $d->{idstr} + d.idstr + d.idstr + +The Id of the value that was matched (only valid for id types), +either as id or string. + + const char *str; + $d->{str} + d.str + d.str + +The string value that was matched (only valid for string types). + + unsigned long long num; + $d->{num} + d.num + d.num + +The numeric value that was matched (only valid for numeric types). + + unsigned int num2; + $d->{num2} + d.num2 + d.num2 + +The secondary numeric value that was matched (only valid for types +containing two values). + + unsigned int binary; + $d->{binary} + d.binary + d.binary + +The value in binary form, useful for checksums and other data +that cannot be represented as a string. + +=== METHODS === + + Datapos pos(); + my $pos = $d->pos(); + pos = d.pos() + pos = d.pos() + +The position object of the current match. It can be used to do +sub-searches starting at the match (if it is of an array type). +See the Datapos class for more information. + + Datapos parentpos(); + my $pos = $d->parentpos(); + pos = d.parentpos() + pos = d.parentpos() + +The position object of the array containing the current match. +It can be used to do sub-searches, see the Datapos class for more +information. + + + my $str = $d->str; + str = str(d) + str = d.to_s + +Return the stringification of the matched value. Stringification +depends on the search flags, for file list entries it will return +just the base name unless SEARCH_FILES is used, for checksums +it will return an empty string unless SEARCH_CHECKSUMS is used. +Numeric values are currently stringified to an empty string. + + +The Selection Class +------------------- +Selections are a way to easily deal with sets of packages. +There are multiple constructors to create them, the most useful +is probably the select() method in the Pool class. + +=== CONSTANTS === + +*SELECTION_NAME*:: +Create the selection by matching package names. + +*SELECTION_PROVIDES*:: +Create the selection by matching package provides. + +*SELECTION_FILELIST*:: +Create the selection by matching package files. + +*SELECTION_CANON*:: +Create the selection by matching the canonical representation +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 +provides. + +*SELECTION_REL*:: +Allow the specification of a relation when matching names +or dependencies, e.g. "name >= 1.2". + +*SELECTION_GLOB*:: +Allow glob matching for package names, package provides, and file names. + +*SELECTION_NOCASE*:: +Ignore case when matching package names, package provides, and file names. + +*SELECTION_FLAT*:: +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. + +*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 */ + $d->{pool} + d.pool + d.pool + +Back pointer to pool. + + int flags; /* read only */ + $sel->{flags} + flags = sel.flags + flags = sel.flags + +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 +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. + +=== 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) + sel.filter(other) + +Intersect two selections. Packages will only stay in the selection if there +are also included in the other selecting. Does an in-place modification. + + void add(Selection *other) + $sel->add($other); + sel.add(other) + sel.add(other) + +Build the union of two selections. All packages of the other selection will +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. Note that the selection flags are no longer meaningful +after the add_raw operation. + + Job *jobs(int action) + my @jobs = $sel->jobs($action); + jobs = sel.jobs(action) + jobs = sel.jobs(action) + +Convert a selection into an array of Job objects. The action parameter is or-ed +to the ``how'' part of the job, it describes the type of job (e.g. install, +erase). See the Job class for the action and action modifier constants. + + Solvable *solvables() + my @solvables = $sel->solvables(); + solvables = sel.solvables() + solvables = sel.solvables() + +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. + + void matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1) + $sel->matchsolvable($solvable, $flags, $keyname); + sel.matchsolvable(solvable, flags, keyname) + sel.matchsolvable(solvable, flags, keyname) + +Do a matchsolvable operation and combine the result with the current selection. + + + my $str = $sel->str; + str = str(sel) + str = sel.to_s + +Return a string describing the selection. + +The Job Class +------------- +Jobs are the way to specify to the dependency solver what to do. +Most of the times jobs will get created by calling the jobs() method +on a Selection object, but there is also a Job() constructor in the +Pool class. + +=== CONSTANTS === + +Selection constants: + +*SOLVER_SOLVABLE*:: +The ``what'' part is the id of a solvable. + +*SOLVER_SOLVABLE_NAME*:: +The ``what'' part is the id of a package name. + +*SOLVER_SOLVABLE_PROVIDES*:: +The ``what'' part is the id of a package provides. + +*SOLVER_SOLVABLE_ONE_OF*:: +The ``what'' part is an offset into the ``whatprovides'' data, created +by calling the towhatprovides() pool method. + +*SOLVER_SOLVABLE_REPO*:: +The ``what'' part is the id of a repository. + +*SOLVER_SOLVABLE_ALL*:: +The ``what'' part is ignored, all packages are selected. + +*SOLVER_SOLVABLE_SELECTMASK*:: +A mask containing all the above selection bits. + +Action constants: + +*SOLVER_NOOP*:: +Do nothing. + +*SOLVER_INSTALL*:: +Install a package of the specified set of packages. It tries to install +the best matching package (i.e. the highest version of the packages from +the repositories with the highest priority). + +*SOLVER_ERASE*:: +Erase all of the packages from the specified set. If a package is not +installed, erasing it will keep it from getting installed. + +*SOLVER_UPDATE*:: +Update the matching installed packages to their best version. If none +of the specified packages are installed, try to update the installed +packages to the specified versions. See the section about targeted +updates about more information. + +*SOLVER_WEAKENDEPS*:: +Allow to break the dependencies of the matching packages. Handle with care. + +*SOLVER_MULTIVERSION*:: +Mark the matched packages for multiversion install. If they get to be +installed because of some other job, the installation will keep the old +version of the package installed (for rpm this is done by using ``-i'' +instead of ``-U''). + +*SOLVER_LOCK*:: +Do not change the state of the matched packages, i.e. when they are +installed they stay installed, if not they are not selected for +installation. + +*SOLVER_DISTUPGRADE*:: +Update the matching installed packages to the best version included in one +of the repositories. After this operation, all come from one of the available +repositories except orphaned packages. Orphaned packages are packages that +have no relation to the packages in the repositories, i.e. no package in the +repositories have the same name or obsolete the orphaned package. +This action brings the installed packages in sync with the ones in the +repository. By default it also turns of arch/vendor/version locking for the +affected packages to simulate a fresh installation. This means that distupgrade can +actually downgrade packages if only lower versions of a package are available +in the repositories. You can tweak this behavior with the SOLVER_FLAG_DUP_ +solver flags. + +*SOLVER_DROP_ORPHANED*:: +Erase all the matching installed packages if they are orphaned. This only makes +sense if there is a ``distupgrade all packages'' job. The default is to erase +orphaned packages only if they block the installation of other packages. + +*SOLVER_VERIFY*:: +Fix dependency problems of matching installed packages. The default is to ignore +dependency problems for installed packages. + +*SOLVER_USERINSTALLED*:: +The matching installed packages are considered to be installed by a user, +thus not installed to fulfill some dependency. This is needed input for +the calculation of unneeded packages for jobs that have the +SOLVER_CLEANDEPS flag set. + +*SOLVER_ALLOWUNINSTALL*:: +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. + +Action modifier constants: + +*SOLVER_WEAK*:: +Makes the job a weak job. The solver tries to fulfill weak jobs, but does +not report a problem if it is not possible to do so. + +*SOLVER_ESSENTIAL*:: +Makes the job an essential job. If there is a problem with the job, the +solver will not propose to remove the job as one solution (unless all +other solutions are also to remove essential jobs). + +*SOLVER_CLEANDEPS*:: +The solver will try to also erase all packages dragged in through +dependencies when erasing the package. This needs SOLVER_USERINSTALLED +jobs to maximize user satisfaction. + +*SOLVER_FORCEBEST*:: +Insist on the best package for install, update, and distupgrade jobs. If +this flag is not used, the solver will use the second-best package if the +best package cannot be installed for some reason. When this flag is used, +the solver will generate a problem instead. + +*SOLVER_TARGETED*:: +Forces targeted operation update and distupgrade jobs. See the section +about targeted updates about more information. + +Set constants. + +*SOLVER_SETEV*:: +The job specified the exact epoch and version of the package set. + +*SOLVER_SETEVR*:: +The job specified the exact epoch, version, and release of the package set. + +*SOLVER_SETARCH*:: +The job specified the exact architecture of the packages from the set. + +*SOLVER_SETVENDOR*:: +The job specified the exact vendor of the packages from the set. + +*SOLVER_SETREPO*:: +The job specified the exact repository of the packages from the set. + +*SOLVER_SETNAME*:: +The job specified the exact name of the packages from the set. + +*SOLVER_NOAUTOSET*:: +Turn of automatic set flag generation for SOLVER_SOLVABLE jobs. + +*SOLVER_SETMASK*:: +A mask containing all the above set bits. + +See the section about set bits for more information. + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $job->{pool} + d.pool + d.pool + +Back pointer to pool. + + Id how; /* read/write */ + $job->{how} + d.how + d.how + +Union of the selection, action, action modifier, and set flags. +The selection part describes the semantics of the ``what'' Id. + + Id what; /* read/write */ + $job->{what} + d.what + d.what + +Id describing the set of packages, the meaning depends on the +selection part of the ``how'' attribute. + +=== METHODS === + + Solvable *solvables() + my @solvables = $job->solvables(); + solvables = job.solvables() + solvables = job.solvables() + +Return the set of solvables of the job as an array of Solvable +objects. + + bool isemptyupdate(); + $job->isemptyupdate() + job.isemptyupdate() + job.isemptyupdate? + +Convenience function to find out if the job describes an update +job with no matching packages, i.e. a job that does nothing. +Some package managers like ``zypper'' like to turn those jobs +into install jobs, i.e. an update of a not-installed package +will result into the installation of the package. + + + my $str = $job->str; + str = str(job) + str = job.to_s + +Return a string describing the job. + + + if ($job1 == $job2) + if job1 == job2: + if job1 == job2 + +Two jobs are equal if they belong to the same pool and both the +``how'' and the ``what'' attributes are the same. + +=== TARGETED UPDATES === +Libsolv has two modes for upgrades and distupgrade: targeted and +untargeted. Untargeted mode means that the installed packages from +the specified set will be updated to the best version. Targeted means +that packages that can be updated to a package in the specified set +will be updated to the best package of the set. + +Here's an example to explain the subtle difference. Suppose that +you have package A installed in version "1.1", "A-1.2" is available +in one of the repositories and there is also package "B" that +obsoletes package A. + +An untargeted update of "A" will update the installed "A-1.1" to +package "B", because that is the newest version (B obsoletes A and +is thus newer). + +A targeted update of "A" will update "A-1.1" to "A-1.2", as the +set of packages contains both "A-1.1" and "A-1.2", and "A-1.2" is +the newer one. + +An untargeted update of "B" will do nothing, as "B" is not installed. + +An targeted update of "B" will update "A-1.1" to "B". + +Note that the default is to do "auto-targeting", thus if the specified +set of packages does not include an installed package, the solver +will assume targeted operation even if SOLVER_TARGETED is not used. + +This mostly matches the intent of the user, with one exception: In +the example above, an update of "A-1.2" will update "A-1.1" to +"A-1.2" (targeted mode), but a second update of "A-1.2" will suddenly +update to "B", as untargeted mode is chosen because "A-1.2" is now +installed. + +If you want to have full control over when targeting mode is chosen, +turn off auto-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option. +In that case, all updates are considered to be untargeted unless they +include the SOLVER_TARGETED flag. + +=== SET BITS === +Set bits specify which parts of the specified packages where specified +by the user. It is used by the solver when checking if an operation is +allowed or not. For example, the solver will normally not allow the +downgrade of an installed package. But it will not report a problem if +the SOLVER_SETEVR flag is used, as it then assumes that the user specified +the exact version and thus knows what he is doing. + +So if a package "screen-1-1" is installed for the x86_64 architecture and +version "2-1" is only available for the i586 architecture, installing +package "screen-2.1" will ask the user for confirmation because of the +different architecture. When using the Selection class to create jobs +the set bits are automatically added, e.g. selecting ``screen.i586'' will +automatically add SOLVER_SETARCH, and thus no problem will be reported. + +The Solver Class +---------------- +Dependency solving is what this library is about. A solver object is needed +for solving to store the result of the solver run. The solver object can be +used multiple times for different jobs, reusing it allows the solver to +re-use the dependency rules it already computed. + +=== CONSTANTS === + +Flags to modify some of the solver's behavior: + +*SOLVER_FLAG_ALLOW_DOWNGRADE*:: +Allow the solver to downgrade packages without asking for confirmation +(i.e. reporting a problem). + +*SOLVER_FLAG_ALLOW_ARCHCHANGE*:: +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 +vendor equivalence classes, normally installed packages may only +change their vendor if the new vendor shares at least one equivalence +class. + +*SOLVER_FLAG_ALLOW_NAMECHANGE*:: +Allow the solver to change the name of an installed package, i.e. +install a package with a different name that obsoletes the installed +package. This option is on by default. + +*SOLVER_FLAG_ALLOW_UNINSTALL*:: +Allow the solver to erase installed packages to fulfill the jobs. +This flag also includes the above flags. You may want to set this +flag if you only have SOLVER_ERASE jobs, as in that case it's +better for the user to check the transaction overview instead of +approving every single package that needs to be erased. + +*SOLVER_FLAG_DUP_ALLOW_DOWNGRADE*:: +Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode. + +*SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE*:: +Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode. + +*SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE*:: +Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode. + +*SOLVER_FLAG_DUP_ALLOW_NAMECHANGE*:: +Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode. + +*SOLVER_FLAG_NO_UPDATEPROVIDE*:: +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. + +*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 +splits. + +*SOLVER_FLAG_IGNORE_RECOMMENDED*:: +Do not process optional (aka weak) dependencies. + +*SOLVER_FLAG_ADD_ALREADY_RECOMMENDED*:: +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 +of packages from the "best" architecture if a package is available +for multiple architectures. + +*SOLVER_FLAG_BEST_OBEY_POLICY*:: +Make the SOLVER_FORCEBEST job option consider only packages that +meet the policies for installed packages, i.e. no downgrades, +no architecture change, no vendor change (see the first flags +of this section). If the flag is not specified, the solver will +enforce the installation of the best package ignoring the +installed packages, which may conflict with the set policy. + +*SOLVER_FLAG_NO_AUTOTARGET*:: +Do not enable auto-targeting up update and distupgrade jobs. See +the section on targeted updates for more information. + +*SOLVER_FLAG_KEEP_ORPHANS*:: +Do not allow orphaned packages to be deinstalled if they get +in the way of resolving other packages. + +*SOLVER_FLAG_BREAK_ORPHANS*:: +Ignore dependencies of orphaned packages that get in the way +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 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*:: +A rule of an unknown class. You should never encounter those. + +*SOLVER_RULE_PKG*:: +A package dependency rule. + +*SOLVER_RULE_UPDATE*:: +A rule to implement the update policy of installed packages. Every +installed package has an update rule that consists of the packages +that may replace the installed package. + +*SOLVER_RULE_FEATURE*:: +Feature rules are fallback rules used when an update rule is disabled. They +include all packages that may replace the installed package ignoring the +update policy, i.e. they contain downgrades, arch changes and so on. +Without them, the solver would simply erase installed packages if their +update rule gets disabled. + +*SOLVER_RULE_JOB*:: +Job rules implement the job given to the solver. + +*SOLVER_RULE_DISTUPGRADE*:: +These are simple negative assertions that make sure that only packages +are kept that are also available in one of the repositories. + +*SOLVER_RULE_INFARCH*:: +Infarch rules are also negative assertions, they disallow the installation +of packages when there are packages of the same name but with a better +architecture. + +*SOLVER_RULE_CHOICE*:: +Choice rules are used to make sure that the solver prefers updating to +installing different packages when some dependency is provided by +multiple packages with different names. The solver may always break +choice rules, so you will not see them when a problem is found. + +*SOLVER_RULE_LEARNT*:: +These rules are generated by the solver to keep it from running into +the same problem multiple times when it has to backtrack. They are +the main reason why a sat solver is faster than other dependency solver +implementations. + +Special dependency rule types: + +*SOLVER_RULE_PKG_NOT_INSTALLABLE*:: +This rule was added to prevent the installation of a package of an +architecture that does not work on the system. + +*SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP*:: +The package contains a required dependency which was not provided by +any package. + +*SOLVER_RULE_PKG_REQUIRES*:: +Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case +some packages provided the dependency but none of them could be +installed due to other dependency issues. + +*SOLVER_RULE_PKG_SELF_CONFLICT*:: +The package conflicts with itself. This is not allowed by older rpm +versions. + +*SOLVER_RULE_PKG_CONFLICTS*:: +To fulfill the dependencies two packages need to be installed, but +one of the packages contains a conflict with the other one. + +*SOLVER_RULE_PKG_SAME_NAME*:: +The dependencies can only be fulfilled by multiple versions of +a package, but installing multiple versions of the same package +is not allowed. + +*SOLVER_RULE_PKG_OBSOLETES*:: +To fulfill the dependencies two packages need to be installed, but +one of the packages obsoletes the other one. + +*SOLVER_RULE_PKG_IMPLICIT_OBSOLETES*:: +To fulfill the dependencies two packages need to be installed, but +one of the packages has provides a dependency that is obsoleted +by the other one. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES +flag. + +*SOLVER_RULE_PKG_INSTALLED_OBSOLETES*:: +To fulfill the dependencies a package needs to be installed that is +obsoleted by an installed package. See the POOL_FLAG_NOINSTALLEDOBSOLETES +flag. + +*SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP*:: +The user asked for installation of a package providing a specific +dependency, but no available package provides it. + +*SOLVER_RULE_JOB_UNKNOWN_PACKAGE*:: +The user asked for installation of a package with a specific name, +but no available package has that name. + +*SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM*:: +The user asked for the erasure of a dependency that is provided by the +system (i.e. for special hardware or language dependencies), this +cannot be done with a job. + +*SOLVER_RULE_JOB_UNSUPPORTED*:: +The user asked for something that is not yet implemented, e.g. the +installation of all packages at once. + +Policy error constants + +*POLICY_ILLEGAL_DOWNGRADE*:: +The solver ask for permission before downgrading packages. + +*POLICY_ILLEGAL_ARCHCHANGE*:: +The solver ask for permission before changing the architecture of installed +packages. + +*POLICY_ILLEGAL_VENDORCHANGE*:: +The solver ask for permission before changing the vendor of installed +packages. + +*POLICY_ILLEGAL_NAMECHANGE*:: +The solver ask for permission before replacing an installed packages with +a package that has a different name. + +Solution element type constants + +*SOLVER_SOLUTION_JOB*:: +The problem can be solved by removing the specified job. + +*SOLVER_SOLUTION_POOLJOB*:: +The problem can be solved by removing the specified job that is defined +in the pool. + +*SOLVER_SOLUTION_INFARCH*:: +The problem can be solved by allowing the installation of the specified +package with an inferior architecture. + +*SOLVER_SOLUTION_DISTUPGRADE*:: +The problem can be solved by allowing to keep the specified package +installed. + +*SOLVER_SOLUTION_BEST*:: +The problem can be solved by allowing to install the specified package +that is not the best available package. + +*SOLVER_SOLUTION_ERASE*:: +The problem can be solved by allowing to erase the specified package. + +*SOLVER_SOLUTION_REPLACE*:: +The problem can be solved by allowing to replace the package with some +other package. + +*SOLVER_SOLUTION_REPLACE_DOWNGRADE*:: +The problem can be solved by allowing to replace the package with some +other package that has a lower version. + +*SOLVER_SOLUTION_REPLACE_ARCHCHANGE*:: +The problem can be solved by allowing to replace the package with some +other package that has a different architecture. + +*SOLVER_SOLUTION_REPLACE_VENDORCHANGE*:: +The problem can be solved by allowing to replace the package with some +other package that has a different vendor. + +*SOLVER_SOLUTION_REPLACE_NAMECHANGE*:: +The problem can be solved by allowing to replace the package with some +other package that has a different name. + + +Reason constants + +*SOLVER_REASON_UNRELATED*:: +The package status did not change as it was not related to any job. + +*SOLVER_REASON_UNIT_RULE*:: +The package was installed/erased/kept because of a unit rule, i.e. a rule +where all literals but one were false. + +*SOLVER_REASON_KEEP_INSTALLED*:: +The package was chosen when trying to keep as many packages installed as +possible. + +*SOLVER_REASON_RESOLVE_JOB*:: +The decision happened to fulfill a job rule. + +*SOLVER_REASON_UPDATE_INSTALLED*:: +The decision happened to fulfill a package update request. + +*SOLVER_REASON_CLEANDEPS_ERASE*:: +The package was erased when cleaning up dependencies from other erased +packages. + +*SOLVER_REASON_RESOLVE*:: +The package was installed to fulfill package dependencies. + +*SOLVER_REASON_WEAKDEP*:: +The package was installed because of a weak dependency (Recommends or +Supplements). + +*SOLVER_REASON_RESOLVE_ORPHAN*:: +The decision about the package was made when deciding the fate of orphaned +packages. + +*SOLVER_REASON_RECOMMENDED*:: +This is a special case of SOLVER_REASON_WEAKDEP. + +*SOLVER_REASON_SUPPLEMENTED*:: +This is a special case of SOLVER_REASON_WEAKDEP. + + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $job->{pool} + d.pool + d.pool + +Back pointer to pool. + +=== METHODS === + + int set_flag(int flag, int value) + my $oldvalue = $solver->set_flag($flag, $value); + oldvalue = solver.set_flag(flag, value) + oldvalue = solver.set_flag(flag, value) + + int get_flag(int flag) + my $value = $solver->get_flag($flag); + value = solver.get_flag(flag) + value = solver.get_flag(flag) + +Set/get a solver specific flag. The flags define the policies the solver has +to obey. The flags are explained in the CONSTANTS section of this class. + + Problem *solve(Job *jobs) + my @problems = $solver->solve(\@jobs); + problems = solver.solve(jobs) + problems = solver.solve(jobs) + +Solve a problem specified in the job list (plus the jobs defined in the pool). +Returns an array of problems that need user interaction, or an empty array +if no problems were encountered. See the Problem class on how to deal with +problems. + + Transaction transaction() + my $trans = $solver->transaction(); + trans = solver.transaction() + trans = solver.transaction() + +Return the transaction to implement the calculated package changes. A transaction +is available even if problems were found, this is useful for interactive user +interfaces that show both the job result and the problems. + + int reason = describe_decision(Solvable *s, Rule *OUTPUT) + my ($reason, $rule) = $solver->describe_decision($solvable); + (reason, rule) = solver.describe_decision(solvable) + (reason, rule) = solver.describe_decision(solvable) + +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 +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. + +=== ATTRIBUTES === + + Solver *solv; /* read only */ + $problem->{solv} + problem.solv + problem.solv + +Back pointer to solver object. + + Id id; /* read only */ + $problem->{id} + problem.id + problem.id + +Id of the problem. The first problem has Id 1, they are numbered consecutively. + +=== METHODS === + + Rule findproblemrule() + my $probrule = $problem->findproblemrule(); + probrule = problem.findproblemrule() + probrule = problem.findproblemrule() + +Return the rule that caused the problem. Of course in most situations there is no +single responsible rule, but many rules that interconnect with each created the +problem. Nevertheless, the solver uses some heuristic approach to find a rule +that somewhat describes the problem best to the user. + + Rule *findallproblemrules(bool unfiltered = 0) + my @probrules = $problem->findallproblemrules(); + 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 +them to the user in a sensible way. The default is to filter out all update and +job rules (unless the returned rules only consist of those types). + + Solution *solutions() + my @solutions = $problem->solutions(); + solutions = problem.solutions() + solutions = problem.solutions() + +Return an array containing multiple possible solutions to fix the problem. See +the solution class for more information. + + int solution_count() + my $cnt = $problem->solution_count(); + cnt = problem.solution_count() + cnt = problem.solution_count() + +Return the number of solutions without creating solution objects. + + + my $str = $problem->str; + str = str(problem) + str = problem.to_s + +Return a string describing the problem. This is a convenience function, it is +a shorthand for calling findproblemrule(), then ruleinfo() on the problem +rule and problemstr() on the ruleinfo object. + +The Rule Class +-------------- +Rules are the basic block of sat solving. Each package dependency gets translated +into one or multiple rules. + +=== ATTRIBUTES === + + Solver *solv; /* read only */ + $rule->{solv} + rule.solv + rule.solv + +Back pointer to solver object. + + Id id; /* read only */ + $rule->{id} + rule.id + rule.id + +The id of the rule. + + int type; /* read only */ + $rule->{type} + rule.type + rule.type + +The basic type of the rule. See the constant section of the solver class for the type list. + +=== METHODS === + + Ruleinfo info() + my $ruleinfo = $rule->info(); + ruleinfo = rule.info() + ruleinfo = rule.info() + +Return a Ruleinfo object that contains information about why the rule was created. But +see the allinfos() method below. + + Ruleinfo *allinfos() + my @ruleinfos = $rule->allinfos(); + ruleinfos = rule.allinfos() + ruleinfos = rule.allinfos() + +As the same dependency rule can get created because of multiple dependencies, one +Ruleinfo is not enough to describe the reason. Thus the allinfos() method returns +an array of all infos about a rule. + + + if ($rule1 == $rule2) + if rule1 == rule2: + if rule1 == rule2 + +Two rules are equal if they belong to the same solver and have the same id. + +The Ruleinfo Class +------------------ +A Ruleinfo describes one reason why a rule was created. + +=== ATTRIBUTES === + + Solver *solv; /* read only */ + $ruleinfo->{solv} + ruleinfo.solv + ruleinfo.solv + +Back pointer to solver object. + + int type; /* read only */ + $ruleinfo->{type} + ruleinfo.type + ruleinfo.type + +The type of the ruleinfo. See the constant section of the solver class for the +rule type list and the special type list. + + Dep *dep; /* read only */ + $ruleinfo->{dep} + ruleinfo.dep + ruleinfo.dep + +The dependency leading to the creation of the rule. + + Dep *dep_id; /* read only */ + $ruleinfo->{'dep_id'} + ruleinfo.dep_id + ruleinfo.dep_id + +The Id of the dependency leading to the creation of the rule, or zero. + + Solvable *solvable; /* read only */ + $ruleinfo->{solvable} + ruleinfo.solvable + ruleinfo.solvable + +The involved Solvable, e.g. the one containing the dependency. + + Solvable *othersolvable; /* read only */ + $ruleinfo->{othersolvable} + ruleinfo.othersolvable + ruleinfo.othersolvable + +The other involved Solvable (if any), e.g. the one containing providing +the dependency for conflicts. + + const char *problemstr(); + my $str = $ruleinfo->problemstr(); + str = ruleinfo.problemstr() + str = ruleinfo.problemstr() + +A string describing the ruleinfo from a problem perspective. This probably +only makes sense if the rule is part of a problem. + +The Solution Class +------------------ +A solution solves one specific problem. It consists of multiple solution elements +that all need to be executed. + +=== ATTRIBUTES === + + Solver *solv; /* read only */ + $solution->{solv} + solution.solv + solution.solv + +Back pointer to solver object. + + Id problemid; /* read only */ + $solution->{problemid} + solution.problemid + solution.problemid + +Id of the problem the solution solves. + + Id id; /* read only */ + $solution->{id} + solution.id + solution.id + +Id of the solution. The first solution has Id 1, they are numbered consecutively. + +=== METHODS === + + Solutionelement *elements(bool expandreplaces = 0) + my @solutionelements = $solution->elements(); + solutionelements = solution.elements() + solutionelements = solution.elements() + +Return an array containing the elements describing what needs to be done to +implement the specific solution. If expandreplaces is true, elements of type +SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace +elements describing the policy mismatches. + + int element_count() + my $cnt = $solution->solution_count(); + cnt = solution.element_count() + cnt = solution.element_count() + +Return the number of solution elements without creating objects. Note that the +count does not match the number of objects returned by the elements() method +of expandreplaces is set to true. + + +The Solutionelement Class +------------------------- +A solution element describes a single action of a solution. The action is always +either to remove one specific job or to add a new job that installs or erases +a single specific package. + +=== ATTRIBUTES === + + Solver *solv; /* read only */ + $solutionelement->{solv} + solutionelement.solv + solutionelement.solv + +Back pointer to solver object. + + Id problemid; /* read only */ + $solutionelement->{problemid} + solutionelement.problemid + solutionelement.problemid + +Id of the problem the element (partly) solves. + + Id solutionid; /* read only */ + $solutionelement->{solutionid} + solutionelement.solutionid + solutionelement.solutionid + +Id of the solution the element is a part of. + + Id id; /* read only */ + $solutionelement->{id} + solutionelement.id + solutionelement.id + +Id of the solution element. The first element has Id 1, they are numbered consecutively. + + Id type; /* read only */ + $solutionelement->{type} + solutionelement.type + solutionelement.type + +Type of the solution element. See the constant section of the solver class for the +existing types. + + Solvable *solvable; /* read only */ + $solutionelement->{solvable} + solutionelement.solvable + solutionelement.solvable + +The installed solvable that needs to be replaced for replacement elements. + + Solvable *replacement; /* read only */ + $solutionelement->{replacement} + solutionelement.replacement + solutionelement.replacement + +The solvable that needs to be installed to fix the problem. + + int jobidx; /* read only */ + $solutionelement->{jobidx} + solutionelement.jobidx + solutionelement.jobidx + +The index of the job that needs to be removed to fix the problem, or -1 if the +element is of another type. Note that it's better to change the job to SOLVER_NOOP +type so that the numbering of other elements does not get disturbed. This +method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB. + +=== METHODS === + + Solutionelement *replaceelements() + my @solutionelements = $solutionelement->replaceelements(); + solutionelements = solutionelement.replaceelements() + solutionelements = solutionelement.replaceelements() + +If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of +elements describing the policy mismatches, otherwise return a copy of the +element. See also the ``expandreplaces'' option in the solution's elements() +method. + + int illegalreplace() + my $illegal = $solutionelement->illegalreplace(); + illegal = solutionelement.illegalreplace() + illegal = solutionelement.illegalreplace() + +Return an integer that contains the policy mismatch bits or-ed together, or +zero if there was no policy mismatch. See the policy error constants in +the solver class. + + Job Job() + my $job = $solutionelement->Job(); + illegal = solutionelement.Job() + illegal = solutionelement.Job() + +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. + + const char *str() + my $str = $solutionelement->str(); + str = solutionelement.str() + str = solutionelement.str() + +A string describing the change the solution element consists of. + +The Transaction Class +--------------------- +Transactions describe the output of a solver run. A transaction contains +a number of transaction elements, each either the installation of a new +package or the removal of an already installed package. The Transaction +class supports a classify() method that puts the elements into different +groups so that a transaction can be presented to the user in a meaningful +way. + +=== CONSTANTS === + +Transaction element types, both active and passive + +*SOLVER_TRANSACTION_IGNORE*:: +This element does nothing. Used to map element types that do not match +the view mode. + +*SOLVER_TRANSACTION_INSTALL*:: +This element installs a package. + +*SOLVER_TRANSACTION_ERASE*:: +This element erases a package. + +*SOLVER_TRANSACTION_MULTIINSTALL*:: +This element installs a package with a different version keeping the other +versions installed. + +*SOLVER_TRANSACTION_MULTIREINSTALL*:: +This element reinstalls an installed package keeping the other versions +installed. + +Transaction element types, active view + +*SOLVER_TRANSACTION_REINSTALL*:: +This element re-installs a package, i.e. installs the same package again. + +*SOLVER_TRANSACTION_CHANGE*:: +This element installs a package with same name, version, architecture but +different content. + +*SOLVER_TRANSACTION_UPGRADE*:: +This element installs a newer version of an installed package. + +*SOLVER_TRANSACTION_DOWNGRADE*:: +This element installs an older version of an installed package. + +*SOLVER_TRANSACTION_OBSOLETES*:: +This element installs a package that obsoletes an installed package. + +Transaction element types, passive view + +*SOLVER_TRANSACTION_REINSTALLED*:: +This element re-installs a package, i.e. installs the same package again. + +*SOLVER_TRANSACTION_CHANGED*:: +This element replaces an installed package with one of the same name, +version, architecture but different content. + +*SOLVER_TRANSACTION_UPGRADED*:: +This element replaces an installed package with a new version. + +*SOLVER_TRANSACTION_DOWNGRADED*:: +This element replaces an installed package with an old version. + +*SOLVER_TRANSACTION_OBSOLETED*:: +This element replaces an installed package with a package that obsoletes +it. + +Pseudo element types for showing extra information used by classify() + +*SOLVER_TRANSACTION_ARCHCHANGE*:: +This element replaces an installed package with a package of a different +architecture. + +*SOLVER_TRANSACTION_VENDORCHANGE*:: +This element replaces an installed package with a package of a different +vendor. + +Transaction mode flags + +*SOLVER_TRANSACTION_SHOW_ACTIVE*:: +Filter for active view types. The default is to return passive view type, +i.e. to show how the installed packages get changed. + +*SOLVER_TRANSACTION_SHOW_OBSOLETES*:: +Do not map the obsolete view type into INSTALL/ERASE elements. + +*SOLVER_TRANSACTION_SHOW_ALL*:: +If multiple packages replace an installed package, only the best of them +is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE +elements. This is because most applications want to show just one package +replacing the installed one. The SOLVER_TRANSACTION_SHOW_ALL makes the +library keep all OBSOLETE elements. + +*SOLVER_TRANSACTION_SHOW_MULTIINSTALL*:: +The library maps MULTIINSTALL elements to simple INSTALL elements. This +flag can be used to disable the mapping. + +*SOLVER_TRANSACTION_CHANGE_IS_REINSTALL*:: +Use this flag if you want to map CHANGE elements to the REINSTALL type. + +*SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE*:: +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. + +*SOLVER_TRANSACTION_RPM_ONLY*:: +Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL +elements. Useful if you want to find out what to feed to the underlying +package manager. + +Transaction order flags + +*SOLVER_TRANSACTION_KEEP_ORDERDATA*:: +Do not throw away the dependency graph used for ordering the transaction. +This flag is needed if you want to do manual ordering. + +=== ATTRIBUTES === + + Pool *pool; /* read only */ + $trans->{pool} + trans.pool + trans.pool + +Back pointer to pool. + +=== METHODS === + + bool isempty(); + $trans->isempty() + trans.isempty() + trans.isempty? + +Returns true if the transaction does not do anything, i.e. has no elements. + + Solvable *newsolvables(); + my @newsolvables = $trans->newsolvables(); + newsolvables = trans.newsolvables() + newsolvables = trans.newsolvables() + +Return all packages that are to be installed by the transaction. These are +the packages that need to be downloaded from the repositories. + + Solvable *keptsolvables(); + my @keptsolvables = $trans->keptsolvables(); + keptsolvables = trans.keptsolvables() + keptsolvables = trans.keptsolvables() + +Return all installed packages that the transaction will keep installed. + + Solvable *steps(); + my @steps = $trans->steps(); + steps = trans.steps() + steps = trans.steps() + +Return all solvables that need to be installed (if the returned solvable +is not already installed) or erased (if the returned solvable is installed). +A step is also called a transaction element. + + int steptype(Solvable *solvable, int mode) + my $type = $trans->steptype($solvable, $mode); + type = trans.steptype(solvable, mode) + type = trans.steptype(solvable, mode) + +Return the transaction type of the specified solvable. See the CONSTANTS +sections for the mode argument flags and the list of returned types. + + TransactionClass *classify(int mode = 0) + my @classes = $trans->classify(); + classes = trans.classify() + classes = trans.classify() + +Group the transaction elements into classes so that they can be displayed +in a structured way. You can use various mapping mode flags to tweak +the result to match your preferences, see the mode argument flag in +the CONSTANTS section. See the TransactionClass class for how to deal +with the returned objects. + + Solvable othersolvable(Solvable *solvable); + my $other = $trans->othersolvable($solvable); + other = trans.othersolvable(solvable) + other = trans.othersolvable(solvable) + +Return the ``other'' solvable for a given solvable. For installed packages +the other solvable is the best package with the same name that replaces +the installed package, or the best package of the obsoleting packages if +the package does not get replaced by one with the same name. + +For to be installed packages, the ``other'' solvable is the best installed +package with the same name that will be replaced, or the best packages +of all the packages that are obsoleted if the new package does not replace +a package with the same name. + +Thus, the ``other'' solvable is normally the package that is also shown +for a given package. + + Solvable *allothersolvables(Solvable *solvable); + my @others = $trans->allothersolvables($solvable); + others = trans.allothersolvables(solvable) + others = trans.allothersolvables(solvable) + +For installed packages, returns all of the packages that replace us. For to +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. + + long long calc_installsizechange(); + my $change = $trans->calc_installsizechange(); + change = trans.calc_installsizechange() + change = trans.calc_installsizechange() + +Return the size change of the installed system in kilobytes (kibibytes). + + void order(int flags = 0); + $trans->order(); + trans.order() + trans.order() + +Order the steps in the transactions so that dependent packages are updated +before packages that depend on them. For rpm, you can also use rpmlib's +ordering functionality, debian's dpkg does not provide a way to order a +transaction. + +=== ACTIVE/PASSIVE VIEW === + +Active view lists what new packages get installed, while passive view shows +what happens to the installed packages. Most often there's not much +difference between the two modes, but things get interesting if multiple +packages get replaced by one new package. Say you have installed packages +A-1-1 and B-1-1, and now install A-2-1 which has a new dependency that +obsoletes B. The transaction elements will be + + updated A-1-1 (other: A-2-1) + obsoleted B-1-1 (other: A-2-1) + +in passive mode, but + + update A-2-1 (other: A-1-1) + erase B + +in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the +passive mode list will be unchanged but the active mode list will just +contain A-2-1. + +The Transactionclass Class +-------------------------- +Objects of this type are returned by the classify() Transaction method. + +=== ATTRIBUTES === + + Transaction *transaction; /* read only */ + $class->{transaction} + class.transaction + class.transaction + +Back pointer to transaction object. + + int type; /* read only */ + $class->{type} + class.type + class.type + +The type of the transaction elements in the class. + + int count; /* read only */ + $class->{count} + class.count + class.count + +The number of elements in the class. + + const char *fromstr; + $class->{fromstr} + class.fromstr + class.fromstr + +The old vendor or architecture. + + const char *tostr; + $class->{tostr} + class.tostr + class.tostr + +The new vendor or architecture. + + Id fromid; + $class->{fromid} + class.fromid + class.fromid + +The id of the old vendor or architecture. + + Id toid; + $class->{toid} + class.toid + class.toid + +The id of the new vendor or architecture. + +=== METHODS === + + void solvables(); + my @solvables = $class->solvables(); + solvables = class.solvables() + solvables = class.solvables() + +Return the solvables for all transaction elements in the class. + +Checksums +--------- +Checksums (also called hashes) are used to make sure that downloaded data is +not corrupt and also as a fingerprint mechanism to check if data has changed. + +=== CLASS METHODS === + + Chksum Chksum(Id type) + my $chksum = solv::Chksum->new($type); + chksum = solv.Chksum(type) + chksum = Solv::Chksum.new(type) + +Create a checksum object. Currently the following types are supported: + + REPOKEY_TYPE_MD5 + REPOKEY_TYPE_SHA1 + REPOKEY_TYPE_SHA256 + +These keys are constants in the *solv* class. + + Chksum Chksum(Id type, const char *hex) + my $chksum = solv::Chksum->new($type, $hex); + chksum = solv.Chksum(type, hex) + chksum = Solv::Chksum.new(type, hex) + +Create an already finalized checksum object from a hex string. + + Chksum Chksum_from_bin(Id type, char *bin) + my $chksum = solv::Chksum->from_bin($type, $bin); + chksum = solv.Chksum.from_bin(type, bin) + chksum = Solv::Chksum.from_bin(type, bin) + +Create an already finalized checksum object from a binary checksum. + +=== ATTRIBUTES === + + Id type; /* read only */ + $chksum->{type} + chksum.type + chksum.type + +Return the type of the checksum object. + +=== METHODS === + + void add(const char *str) + $chksum->add($str); + chksum.add(str) + chksum.add(str) + +Add a (binary) string to the checksum. + + void add_fp(FILE *fp) + $chksum->add_fp($file); + chksum.add_fp(file) + chksum.add_fp(file) + +Add the contents of a file to the checksum. + + void add_stat(const char *filename) + $chksum->add_stat($filename); + chksum.add_stat(filename) + chksum.add_stat(filename) + +Stat the file and add the dev/ino/size/mtime member to the checksum. If the +stat fails, the members are zeroed. + + void add_fstat(int fd) + $chksum->add_fstat($fd); + chksum.add_fstat(fd) + chksum.add_fstat(fd) + +Same as add_stat, but instead of the filename a file descriptor is used. + + unsigned char *raw() + my $raw = $chksum->raw(); + raw = chksum.raw() + raw = chksum.raw() + +Finalize the checksum and return the result as raw bytes. This means that the +result can contain NUL bytes or unprintable characters. + + const char *hex() + my $raw = $chksum->hex(); + raw = chksum.hex() + raw = chksum.hex() + +Finalize the checksum and return the result as hex string. + + const char *typestr() + my $typestr = $chksum->typestr(); + typestr = chksum.typestr + typestr = chksum.typestr + +Return the type of the checksum as a string, e.g. "sha256". + + + if ($chksum1 == $chksum2) + if chksum1 == chksum2: + if chksum1 == chksum2 + +Checksums are equal if they are of the same type and the finalized results are +the same. + + + my $str = $chksum->str; + str = str(chksum) + str = chksum.to_s + +If the checksum is finished, the checksum is returned as ":" string. +Otherwise ":unfinished" is returned. + + +File Management +--------------- +This functions were added because libsolv uses standard *FILE* pointers to +read/write files, but languages like perl have their own implementation of +files. The libsolv functions also support decompression and compression, the +algorithm is selected by looking at the file name extension. + + FILE *xfopen(char *fn, char *mode = "r") + my $file = solv::xfopen($path); + file = solv.xfopen(path) + file = Solv::xfopen(path) + +Open a file at the specified path. The `mode` argument is passed on to the +stdio library. + + FILE *xfopen_fd(char *fn, int fileno) + my $file = solv::xfopen_fd($path, $fileno); + file = solv.xfopen_fd(path, fileno) + file = Solv::xfopen_fd(path, fileno) + +Create a file handle from the specified file descriptor. The path argument is +only used to select the correct (de-)compression algorithm, use an empty path +if you want to make sure to read/write raw data. The file descriptor is dup()ed +before the file handle is created. + +=== METHODS === + + int fileno() + my $fileno = $file->fileno(); + fileno = file.fileno() + fileno = file.fileno() + +Return file file descriptor of the file. If the file is not open, `-1` is +returned. + + void cloexec(bool state) + $file->cloexec($state) + file.cloexec(state) + file.cloexec(state) + +Set the close-on-exec flag of the file descriptor. The xfopen function +returns files with close-on-exec turned on, so if you want to pass +a file to some other process you need to call cloexec(0) before calling +exec. + + int dup() + my $fileno = $file->dup(); + fileno = file.dup() + fileno = file.dup() + +Return a copy of the descriptor of the file. If the file is not open, `-1` is +returned. + + bool flush() + $file->flush(); + file.flush() + file.flush() + +Flush the file. Returns false if there was an error. Flushing a closed file +always returns true. + + bool close() + $file->close(); + file.close() + file.close() + +Close the file. This is needed for languages like Ruby that do not destruct +objects right after they are no longer referenced. In that case, it is good +style to close open files so that the file descriptors are freed right away. +Returns false if there was an error. + + +The Repodata Class +------------------ +The Repodata stores attributes for packages and the repository itself, each +repository can have multiple repodata areas. You normally only need to +directly access them if you implement lazy downloading of repository data. +Repodata areas are created by calling the repository's add_repodata() method +or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING +flag. + +=== ATTRIBUTES === + + Repo *repo; /* read only */ + $data->{repo} + data.repo + data.repo + +Back pointer to repository object. + + Id id; /* read only */ + $data->{id} + data.id + data.id + +The id of the repodata area. Repodata ids of different repositories overlap. + +=== METHODS === + + internalize(); + $data->internalize(); + data.internalize() + data.internalize() + +Internalize newly added data. The lookup functions will only see the new data +after it has been internalized. + + bool write(FILE *fp); + $data->write($fp); + data.write(fp) + data.write(fp) + +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) + data.add_solv(fp) + +Replace a stub repodata object with the data from a solv file. This method +automatically adds the REPO_USE_LOADING flag. It should only be used from +a load callback. + + void create_stubs(); + $data->create_stubs() + data.create_stubs() + data.create_stubs() + +Create stub repodatas from the information stored in the repodata meta +area. + + void extend_to_repo(); + $data->extend_to_repo(); + data.extend_to_repo() + data.extend_to_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). + + + if ($data1 == $data2) + if data1 == data2: + if data1 == data2 + +Two repodata objects are equal if they belong to the same repository and have +the same id. + +=== DATA RETRIEVAL METHODS === + + const char *lookup_str(Id solvid, Id keyname) + my $string = $data->lookup_str($solvid, $keyname); + 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) + ids = data.lookup_idarray(solvid, keyname) + + Chksum lookup_checksum(Id solvid, Id keyname) + my $chksum = $data->lookup_checksum($solvid, $keyname); + chksum = data.lookup_checksum(solvid, keyname) + chksum = data.lookup_checksum(solvid, keyname) + +Lookup functions. Return the data element stored in the specified solvable. +The methods probably only make sense to retrieve data from the special +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_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); + data.set_poolstr(solvid, keyname, str) + data.set_poolstr(solvid, keyname, str) + + void set_checksum(Id solvid, Id keyname, Chksum *chksum); + $data->set_checksum($solvid, $keyname, $chksum); + 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) + data.add_idarray(solvid, keyname, id) + + Id new_handle(); + my $handle = $data->new_handle(); + handle = data.new_handle() + handle = data.new_handle() + + void add_flexarray(Id solvid, Id keyname, Id handle); + $data->add_flexarray($solvid, $keyname, $handle); + 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), +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. + + +The Datapos Class +----------------- +Datapos objects describe a specific position in the repository data area. +Thus they are only valid until the repository is modified in some way. +Datapos objects can be created by the pos() and parentpos() methods of +a Datamatch object or by accessing the ``meta'' attribute of a repository. + +=== ATTRIBUTES === + + Repo *repo; /* read only */ + $data->{repo} + data.repo + data.repo + +Back pointer to repository object. + +=== METHODS === + + Dataiterator(Id keyname, const char *match, int flags) + my $di = $datapos->Dataiterator($keyname, $match, $flags); + di = datapos.Dataiterator(keyname, match, flags) + di = datapos.Dataiterator(keyname, match, flags) + +Create a Dataiterator at the position of the datapos object. + + const char *lookup_deltalocation(unsigned int *OUTPUT); + 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 +structure describing a delta rpm. + + const char *lookup_deltaseq(); + my $seq = $datapos->lookup_deltaseq(); + seq = datapos.lookup_deltaseq(); + seq = datapos.lookup_deltaseq(); + +Return the delta rpm sequence from the structure describing a delta rpm. + +=== DATA RETRIEVAL METHODS === + + const char *lookup_str(Id keyname) + my $string = $datapos->lookup_str($keyname); + string = datapos.lookup_str(keyname) + string = datapos.lookup_str(keyname) + + Id lookup_id(Id solvid, Id keyname) + my $id = $datapos->lookup_id($keyname); + id = datapos.lookup_id(keyname) + id = datapos.lookup_id(keyname) + + unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) + my $num = $datapos->lookup_num($keyname); + num = datapos.lookup_num(keyname) + num = datapos.lookup_num(keyname) + + bool lookup_void(Id keyname) + my $bool = $datapos->lookup_void($keyname); + bool = datapos.lookup_void(keyname) + bool = datapos.lookup_void(keyname) + + Id *lookup_idarray(Id keyname) + my @ids = $datapos->lookup_idarray($keyname); + ids = datapos.lookup_idarray(keyname) + ids = datapos.lookup_idarray(keyname) + + Chksum lookup_checksum(Id keyname) + my $chksum = $datapos->lookup_checksum($keyname); + chksum = datapos.lookup_checksum(keyname) + chksum = datapos.lookup_checksum(keyname) + +Lookup functions. Note that the returned Ids are always translated into +the Ids of the global pool even if the repodata area contains its own pool. + + Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0) + my $di = $datapos->Dataiterator($keyname, $match, $flags); + di = datapos.Dataiterator(keyname, match, flags) + di = datapos.Dataiterator(keyname, match, flags) + + for my $d (@$di) + for d in di: + for d in di + +Iterate over the matching data elements. See the Dataiterator class for more +information. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/libsolv-constantids.txt b/doc/libsolv-constantids.txt new file mode 100644 index 0000000..907a7e5 --- /dev/null +++ b/doc/libsolv-constantids.txt @@ -0,0 +1,683 @@ +Libsolv-Constantids(3) +====================== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +libsolv-constantids - fixed Ids for often used strings + + +Description +----------- +Constant Ids are Ids of strings that are often needed. They are defined +to ease programming and reduce the number of pool_str2id calls. The +constant Ids are part of the binary ABI of libsolv, a minor version +update will only add new constants and not change existing Ids to +maintain compatible. The on-disk solv format works does not use the +fixed Ids, but instead references the strings, so solv files can still +be read when the ABI is broken. + + +Special Strings +--------------- +*ID_EMPTY ""*:: + The empty string. It will always have Id 1. + +*SYSTEM_SYSTEM "system:system"*:: + The name of the always installed "system" solvable. + + +Solvable Attributes +------------------- +These are Ids for keyname of attributes. They can be used in the +lookup and storage functions to select the correct attribute in the +solvable. The descriptions below describe the intended semantics +of the values stored in the attribute with the keyname. + +*SOLVABLE_NAME "solvable:name"*:: + The name of the package. + +*SOLVABLE_ARCH "solvable:arch"*:: + The architecture of the package. See the Solvable Architecture section + for predefined architecture Id values. + +*SOLVABLE_EVR "solvable:evr"*:: + The version of the package. It usually consists of some combination of + the Epoch, the Version, and the Release of the solvable. + +*SOLVABLE_VENDOR "solvable:vendor"*:: + A vendor string. Usually the company or group that created the binary + package. + +*SOLVABLE_PROVIDES "solvable:provides"*:: + Stores an array of dependency Ids that describe the capabilities + that the package provides. + +*SOLVABLE_OBSOLETES "solvable:obsoletes"*:: + Stores an array of dependency Ids that describe the packages that this + package replaces. + +*SOLVABLE_CONFLICTS "solvable:conflicts"*:: + Stores an array of dependency Ids that describe the capabilities that + this package conflicts with, i.e. that can't be installed together with + this package. + +*SOLVABLE_REQUIRES "solvable:requires"*:: + Stores an array of dependency Ids that describe the capabilities that + also must be installed when this package is installed. + +*SOLVABLE_RECOMMENDS "solvable:recommends"*:: + Stores an array of dependency Ids that describe the capabilities that + also should be installed when this package is installed. It's not an + error if not all capabilities can be met. + +*SOLVABLE_SUGGESTS "solvable:suggests"*:: + Stores an array of dependency Ids that describe the capabilities that + also useful to have installed when this package is installed. This is + intended to provide a hint to the user about other packages. + +*SOLVABLE_SUPPLEMENTS "solvable:supplements"*:: + Stores an array of dependency Ids that define that this package should + be installed if one of the capabilities is met. This is like the + recommends attribute, but works in the reverse way. + +*SOLVABLE_ENHANCES "solvable:enhances"*:: + Stores an array of dependency Ids that define that this package is + useful to have installed if one of the capabilities is met. This is like + the suggests attribute, but works in the reverse way. + +*SOLVABLE_SUMMARY "solvable:summary"*:: + The summary should be a short string without any newlines that describes + what a package does. + +*SOLVABLE_DESCRIPTION "solvable:description"*:: + The description should be a more verbose description about what a + package does. It may consist of multiple lines. + +*SOLVABLE_DISTRIBUTION "solvable:distribution"*:: + The distribution is a short string that describes the OS and OS version + this package is built for. + +*SOLVABLE_AUTHORS "solvable:authors"*:: + A list of authors of this package. This attribute was used in SUSE + packages. + +*SOLVABLE_PACKAGER "solvable:packager"*:: + The person who created the binary package, see also the vendor attribute. + +*SOLVABLE_GROUP "solvable:group"*:: + The package group that this package belongs to. See also the keywords + attribute. + +*SOLVABLE_URL "solvable:url"*:: + An URL that points to more information about the package. + +*SOLVABLE_KEYWORDS "solvable:keywords"*:: + list of keyword string IDs used for tagging this package. + +*SOLVABLE_LICENSE "solvable:license"*:: + The license(s) of this package. + +*SOLVABLE_BUILDTIME "solvable:buildtime"*:: + The seconds since the unix epoch when the binary package was created. + +*SOLVABLE_BUILDHOST "solvable:buildhost"*:: + The name of the host on which the binary package was created. + +*SOLVABLE_EULA "solvable:eula"*:: + If this attribute is present the user should be asked to accept the end + user license agreement before the package gets installed. + +*SOLVABLE_CPEID "solvable:cpeid"*:: + A Common Platform Enumeration string describes the platform this package + is intended for. See also the distribution attribute. + +*SOLVABLE_MESSAGEINS "solvable:messageins"*:: + A message that should be displayed to the user when the package gets + installed. + +*SOLVABLE_MESSAGEDEL "solvable:messagedel"*:: + A message that should be displayed to the user when the package gets + erased. + +*SOLVABLE_INSTALLSIZE "solvable:installsize"*:: + The disk space in bytes needed when installing the package. + +*SOLVABLE_DISKUSAGE "solvable:diskusage"*:: + A SUSE extension that stores for each directory the needed amount of + disk space in kilobytes and inodes. + +*SOLVABLE_FILELIST "solvable:filelist"*:: + A list of files that the package contains. + +*SOLVABLE_INSTALLTIME "solvable:installtime"*:: + The seconds since the unix epoch when the binary package was installed + on the system. + +*SOLVABLE_MEDIADIR "solvable:mediadir"*:: + The directory on the repository that contains the package. If this + attribute is set to void, the package architecture is used as + directory. + +*SOLVABLE_MEDIAFILE "solvable:mediafile"*:: + The filename on the repository that contains the package. If this + attribute is set to void, the canonical file name of the package is + used (i.e. a combination of the name, version, architecture). + +*SOLVABLE_MEDIANR "solvable:medianr"*:: + The media number. This is an integer describing on which of a multi-part + media set this package is on. + +*SOLVABLE_MEDIABASE "solvable:mediabase"*:: + This attribute can be used to overwrite the repositories base url. + +*SOLVABLE_DOWNLOADSIZE "solvable:downloadsize"*:: + The size of the binary package in bytes. + +*SOLVABLE_SOURCEARCH "solvable:sourcearch"*:: + The architecture of the source package that this package belongs to. + +*SOLVABLE_SOURCENAME "solvable:sourcename"*:: + The name of the source package that this package belongs to. If set + to void, the package name attribute is used instead. + +*SOLVABLE_SOURCEEVR "solvable:sourceevr"*:: + The version of the source package that this package belongs to. If set + to void, the package version attribute is used instead. + +*SOLVABLE_TRIGGERS "solvable:triggers"*:: + A list of package triggers for this package. Used in the transaction + ordering code. + +*SOLVABLE_CHECKSUM "solvable:checksum"*:: + The checksum of the binary package. See the Data Types section for + a list of supported algorithms. + +*SOLVABLE_PKGID "solvable:pkgid"*:: + A string identifying a package. For rpm packages, this is the md5sum + over the package header and the payload. + +*SOLVABLE_HDRID "solvable:hdrid"*:: + A string identifying a package. For rpm packages, this is the sha1sum + over just the package header. + +*SOLVABLE_LEADSIGID "solvable:leadsigid"*:: + A string identifying the signature part of a package. For rpm packages, + this is the md5sum from the start of the file up to the package header + (i.e. it includes the lead, the signature header, and the padding). + +*SOLVABLE_HEADEREND "solvable:headerend"*:: + The offset of the payload in rpm binary packages. You can use this + information to download just the header if you want to display + information not included in the repository metadata. + +*SOLVABLE_CHANGELOG "solvable:changelog"*:: + The array containing all the changelog structures. + +*SOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"*:: + The author of a changelog entry. + +*SOLVABLE_CHANGELOG_TIME "solvable:changelog:time"*:: + The seconds since the unix epoch when the changelog entry was written. + +*SOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"*:: + The text of a changelog entry. + + +Special Solvable Attributes +--------------------------- +*RPM_RPMDBID "rpm:dbid"*:: + The rpm database id of this (installed) package. Usually a small + integer number. + +*SOLVABLE_PATCHCATEGORY "solvable:patchcategory"*:: + The category field for patch solvables. Should be named + ``update:category'' instead. + +*UPDATE_REBOOT "update:reboot"*:: + If this attribute is present the system should be rebooted after + the update is installed. + +*UPDATE_RESTART "update:restart"*:: + If this attribute is present the software manager should be run + again after the update is installed. + +*UPDATE_RELOGIN "update:relogin"*:: + If this attribute is present the user should log off and on again + after the update is installed. + +*UPDATE_MESSAGE "update:message"*:: + A message that should be shown to the user to warn him about anything + non-standard. + +*UPDATE_SEVERITY "update:severity"*:: + The severity of the update. + +*UPDATE_RIGHTS "update:rights"*:: + Any legal or other rights of the update. + +*UPDATE_COLLECTION "update:collection"*:: + The array containing the package list of the update. + +*UPDATE_COLLECTION_NAME "update:collection:name"*:: + The name of the updated package. + +*UPDATE_COLLECTION_EVR "update:collection:evr"*:: + The version of the updated package. + +*UPDATE_COLLECTION_ARCH "update:collection:arch"*:: + The architecture of the updated package. + +*UPDATE_COLLECTION_FILENAME "update:collection:filename"*:: + The file name of the updated package. + +*UPDATE_REFERENCE "update:reference"*:: + The array containing the reference list of the update. + +*UPDATE_REFERENCE_TYPE "update:reference:type"*:: + The type of the reference, e.g. bugzilla. + +*UPDATE_REFERENCE_HREF "update:reference:href"*:: + The URL of the reference. + +*UPDATE_REFERENCE_ID "update:reference:id"*:: + The identification string of the reference, e.g. the bug number. + +*UPDATE_REFERENCE_TITLE "update:reference:title"*:: + The title of the reference, e.g. the bug summary. + +*PRODUCT_REFERENCEFILE "product:referencefile"*:: + The basename of the product file in the package. + +*PRODUCT_SHORTLABEL "product:shortlabel"*:: + An identification string of the product. + +*PRODUCT_DISTPRODUCT "product:distproduct"*:: + Obsolete, do not use. Was a SUSE Code-10 product name. + +*PRODUCT_DISTVERSION "product:distversion"*:: + Obsolete, do not use. Was a SUSE Code-10 product version. + +*PRODUCT_TYPE "product:type"*:: + The type of the product, e.g. ``base''. + +*PRODUCT_URL "product:url"*:: + An array of product URLs. + +*PRODUCT_URL_TYPE "product:url:type"*:: + An array of product URL types. + +*PRODUCT_FLAGS "product:flags"*:: + An array of product flags. + +*PRODUCT_PRODUCTLINE "product:productline"*:: + A product line string used for product registering. + +*PRODUCT_REGISTER_TARGET "product:regtarget"*:: + A target for product registering. + +*PRODUCT_REGISTER_RELEASE "product:regrelease"*:: + A release string for product registering. + +*PUBKEY_KEYID "pubkey:keyid"*:: + The keyid of a pubkey, consisting of 8 bytes in hex. + +*PUBKEY_FINGERPRINT "pubkey:fingerprint"*:: + The fingerprint of a pubkey, usually a sha1sum in hex. Old V3 RSA keys + use a md5sum instead. + +*PUBKEY_EXPIRES "pubkey:expires"*:: + The seconds since the unix epoch when the pubkey expires. + +*PUBKEY_SUBKEYOF "pubkey:subkeyof"*:: + The keyid of the master pubkey for subkeys. + +*PUBKEY_DATA "pubkey:data"*:: + The MPI data of the pubkey. + +*SOLVABLE_ISVISIBLE "solvable:isvisible"*:: + An attribute describing if the package should be listed to the user + or not. Used for SUSE patterns. + +*SOLVABLE_CATEGORY "solvable:category"*:: + The category of a pattern. + +*SOLVABLE_INCLUDES "solvable:includes"*:: + A list of other patterns that this pattern includes. + +*SOLVABLE_EXTENDS "solvable:extends"*:: + A list of other patterns that this pattern extends. + +*SOLVABLE_ICON "solvable:icon"*:: + The icon name of a pattern. + +*SOLVABLE_ORDER "solvable:order"*:: + An ordering clue of a pattern. + +*SUSETAGS_SHARE_NAME "susetags:share:name"*:: + Internal attribute to implement susetags shared records. Holds the + name of the solvable used for sharing attributes. + +*SUSETAGS_SHARE_EVR "susetags:share:evr"*:: + Internal attribute to implement susetags shared records. Holds the + version of the solvable used for sharing attributes. + +*SUSETAGS_SHARE_ARCH "susetags:share:arch"*:: + Internal attribute to implement susetags shared records. Holds the + architecture of the solvable used for sharing attributes. + + +Solvable Architectures +---------------------- +Predefined architecture values for commonly used architectures. + +*ARCH_SRC "src"*:: + Used for binary packages that contain the package sources. + +*ARCH_NOSRC "nosrc"*:: + Used for binary packages that contain some of the package sources, + but not all files (because of restrictions). + +*ARCH_NOARCH "noarch"*:: + This package can be installed on any architecture. Used for rpm. + +*ARCH_ALL "all"*:: + This package can be installed on any architecture. Used for Debian. + +*ARCH_ANY "any"*:: + This package can be installed on any architecture. Used for Archlinux + and Haiku. + + +Dependency Ids +-------------- +Namespaces are special modifiers that change the meaning of a dependency. +Namespace dependencies are created with the REL_NAMESPACE flag. To make +custom namespaces work you have to implement a namespace callback function. + +The dependency markers partition the dependency array in two parts with +different semantics. + +*NAMESPACE_MODALIAS "namespace:modalias"*:: + The dependency is a special modalias dependency that matches installed + hardware. + +*NAMESPACE_SPLITPROVIDES "namespace:splitprovides"*:: + The dependency is a special splitprovides dependency used to implement + updates that include a package split. A splitprovides dependency contains + a filename and a package name, it is matched if a package with the + provided package name is installed that contains the filename. + This namespace is implemented in libsolv, so you do not need a callback. + +*NAMESPACE_LANGUAGE "namespace:language"*:: + The dependency describes a language. The callback should return true + if the language was selected by the user. + +*NAMESPACE_FILESYSTEM "namespace:filesystem"*:: + The dependency describes a filesystem. The callback should return true + if the filesystem is needed. + +*NAMESPACE_OTHERPROVIDERS "namespace:otherproviders"*:: + This is a hack to allow self-conflicting packages. It is not needed + with current rpm version, so do not use this namespace. + +*SOLVABLE_PREREQMARKER "solvable:prereqmarker"*:: + This marker partitions the normal require dependencies from the + prerequires. It is not needed for dependency solving, but it is + used by the transaction ordering algorithm when a dependency cycle + needs to be broken (non-prereq deps get broken first). + +*SOLVABLE_FILEMARKER "solvable:filemarker"*:: + This marker partitions the package provides dependencies from the + synthetic file provides dependencies added by pool_addfileprovides(). + + +Data Types +---------- +Each attribute data is stored with a type, so that the lookup functions +know how to interpret the data. The following types are available: + +*REPOKEY_TYPE_VOID "repokey:type:void"*:: + No data is stored with this attribute. Thus you can only test if + the attribute exists or not. Useful to store boolean values. + +*REPOKEY_TYPE_CONSTANT "repokey:type:constant"*:: + The data is a constant 32bit number. The number is stored in the key + area, so using it does not cost extra storage space (but you need the + extra key space). + +*REPOKEY_TYPE_CONSTANTID "repokey:type:constantid"*:: + The data is a constant Id. The Id is stored in the key area, + so using it does not cost extra storage space (but you need the + extra key space). + +*REPOKEY_TYPE_ID "repokey:type:id"*:: + The data is an Id. + +*REPOKEY_TYPE_NUM "repokey:type:num"*:: + The data is an unsigned 64bit number. + +*REPOKEY_TYPE_U32 "repokey:type:num32"*:: + The data is an unsigned 32bit number. Obsolete, do not use. + +*REPOKEY_TYPE_DIR "repokey:type:dir"*:: + The data is an Id of a directory. + +*REPOKEY_TYPE_STR "repokey:type:str"*:: + The data is a regular string. + +*REPOKEY_TYPE_BINARY "repokey:type:binary"*:: + The data is a binary blob. + +*REPOKEY_TYPE_IDARRAY "repokey:type:idarray"*:: + The data is an array of non-zero Ids. + +*REPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"*:: + The data is an array of non-zero Ids ordered so that it needs less + space. + +*REPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"*:: + The data is a tuple consisting of a directory Id and a basename. + Used to store file names. + +*REPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"*:: + The data is a triple consisting of a directory Id and two 32bit + unsigned integers. Used to store disk usage information. + +*REPOKEY_TYPE_MD5 "repokey:type:md5"*:: + The data is a binary md5sum. + +*REPOKEY_TYPE_SHA1 "repokey:type:sha1"*:: + The data is a binary sha1sum. + +*REPOKEY_TYPE_SHA256 "repokey:type:sha256"*:: + The data is a binary sha256sum. + +*REPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"*:: + The data is an array of structures that have all the same layout + (i.e. the same keynames and keytypes in the same order). + +*REPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"*:: + The data is an array of structures that have a different layout. + +*REPOKEY_TYPE_DELETED "repokey:type:deleted"*:: + The data does not exist. Used to mark an attribute that was deleted. + + +Repository Metadata +------------------- +This attributes contain meta information about the repository. + +*REPOSITORY_SOLVABLES "repository:solvables"*:: + This attribute holds the array including all of the solvables. It is + only used in the on-disk solv files, internally the solvables are + stored in the pool's solvable array for fast access. + +*REPOSITORY_DELTAINFO "repository:deltainfo"*:: + This attribute holds the array including all of the delta packages. + +*REPOSITORY_EXTERNAL "repository:external"*:: + This attribute holds the array including all of the data to construct + stub repodata areas to support on-demand loading of metadata. + +*REPOSITORY_KEYS "repository:keys"*:: + This should really be named "repository:external:keys", it contains an + array if Ids that consists of (keyname, keytype) pairs that describe the + keys of the stub. + +*REPOSITORY_LOCATION "repository:location"*:: + This is used to provide a file name in the stub. + +*REPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"*:: + This attribute holds an array of filename Ids, that tell the library, + that all of the Ids were already added to the solvable provides. + +*REPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"*:: + An attribute that stores a sha256sum over the file stats of the + Packages database. It's used to detect rebuilds of the database, + as in that case the database Ids of every package are newly + distributed. + +*REPOSITORY_TIMESTAMP "repository:timestamp"*:: + The seconds since the unix epoch when the repository was created. + +*REPOSITORY_EXPIRE "repository:expire"*:: + The seconds after the timestamp when the repository will expire. + +*REPOSITORY_UPDATES "repository:updates"*:: + An array of structures describing what this repository updates. + +*REPOSITORY_DISTROS "repository:distros"*:: + Also an array of structures describing what this repository updates. + Seems to be the newer name of REPOSITORY_UPDATES. + +*REPOSITORY_PRODUCT_LABEL "repository:product:label"*:: + Should really be called "repository:updates:label". What distribution + is updated with this repository. + +*REPOSITORY_PRODUCT_CPEID "repository:product:cpeid"*:: + The cpeid of the platform updated by this repository. Is both used + in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion. + +*REPOSITORY_REPOID "repository:repoid"*:: + An array of Id strings describing keywords/tags about the repository + itself. + +*REPOSITORY_KEYWORDS "repository:keywords"*:: + An array of Id strings describing keywords/tags about the content of + the repository. + +*REPOSITORY_REVISION "repository:revision"*:: + An arbitrary string describing the revision of the repository. + +*REPOSITORY_TOOLVERSION "repository:toolversion"*:: + Some string describing somewhat the version of libsolv used to create + the solv file. + + +Repository Metadata for Susetags Repos +-------------------------------------- +Attributes describing repository files in a susetags repository. +*SUSETAGS_DATADIR "susetags:datadir"*:: + The directory that contains the packages. + +*SUSETAGS_DESCRDIR "susetags:descrdir"*:: + The directory that contains the repository file resources. + +*SUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"*:: + The default vendor used when a package does not specify a vendor. + +*SUSETAGS_FILE "susetags:file"*:: + An array of file resources of the repository. + +*SUSETAGS_FILE_NAME "susetags:file:name"*:: + The filename of the resource. + +*SUSETAGS_FILE_TYPE "susetags:file:type"*:: + The type of the resource, e.g. ``META''. + +*SUSETAGS_FILE_CHECKSUM "susetags:file:checksum"*:: + The file checksum of the resource. + + +Repository Metadata for RpmMD Repos +----------------------------------- +*REPOSITORY_REPOMD "repository:repomd"*:: + An array of file resources of the repository. + +*REPOSITORY_REPOMD_TYPE "repository:repomd:type"*:: + The type of the resource, e.g. ``primary''. + +*REPOSITORY_REPOMD_LOCATION "repository:repomd:location"*:: + The location (aka filename) of the resource + +*REPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"*:: + The seconds since the unix epoch when the resource was created. + +*REPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"*:: + The file checksum of the resource. + +*REPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"*:: + The checksum over the uncompressed contents of the resource. + +*REPOSITORY_REPOMD_SIZE "repository:repomd:size"*:: + The size of the resource file. + + +Delta Package Attributes +------------------------ +*DELTA_PACKAGE_NAME "delta:pkgname"*:: + The target package name for the delta package. Applying the delta + will recreate the target package. + +*DELTA_PACKAGE_EVR "delta:pkgevr"*:: + The version of the target package. + +*DELTA_PACKAGE_ARCH "delta:pkgarch"*:: + The architecture of the target package. + +*DELTA_LOCATION_DIR "delta:locdir"*:: + The directory in the repository that contains the delta package. + +*DELTA_LOCATION_NAME "delta:locname"*:: + The first part of the file name of the delta package. + +*DELTA_LOCATION_EVR "delta:locevr"*:: + The version part of the file name of the delta package. + +*DELTA_LOCATION_SUFFIX "delta:locsuffix"*:: + The suffix part of the file name of the delta package. + +*DELTA_LOCATION_BASE "delta:locbase"*:: + This attribute can be used to overwrite the repositories base url for + the delta. + +*DELTA_DOWNLOADSIZE "delta:downloadsize"*:: + The size of the delta rpm file. + +*DELTA_CHECKSUM "delta:checksum"*:: + The checksum of the delta rpm file. + +*DELTA_BASE_EVR "delta:baseevr"*:: + The version of the package the delta was built against. + +*DELTA_SEQ_NAME "delta:seqname"*:: + The first part of the delta sequence, the base package name. + +*DELTA_SEQ_EVR "delta:seqevr"*:: + The evr part of the delta sequence, the base package evr. Identical + to the DELTA_BASE_EVR attribute. + +*DELTA_SEQ_NUM "delta:seqnum"*:: + The last part of the delta sequence, the content selection string. + + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/libsolv-history.txt b/doc/libsolv-history.txt new file mode 100644 index 0000000..d0a5e62 --- /dev/null +++ b/doc/libsolv-history.txt @@ -0,0 +1,117 @@ +Libsolv-History(3) +================== +:man manual: LIBSOLV +:man source: libsolv + +Name +---- +libsolv-history - how the libsolv library came into existence + +History +------- +This project was started in May 2007 when the zypp folks decided to switch +to a database to speed up installation. As I am not a big fan of databases, +I (mls) wondered if there would be really some merit of using one for solving, +as package dependencies of all packages have to be read in anyway. + +Back in 2002, I researched that using a dictionary approach for storing +dependencies can reduce the packages file to 1/3 of its size. Extending +this idea a bit more, I decided to store all strings and relations +as unique 32-bit numbers. This has three big advantages: + +- because of the unification, testing whether two strings are equal is the + same as testing the equality of two numbers, thus very fast +- much space is saved, as numbers do not take up as much space as strings + the internal memory representation does not take more space on a + 64-bit system where a pointer is twice the size of a 32-bit number + +Thus, the solv format was created, which stores a repository as a string +dictionary, a relation dictionary and then all packages dependencies. +Tests showed that reading and merging multiple solv repositories takes +just some milliseconds. + +=== Early solver experiments === +Having a new repository format was one big step, but the other area +where libzypp needed improvement was the solver. Libzypp's solver was +a port from the Red Carpet solver, which was written to update packages +in an already installed system. Using it for the complete installation +progress brought it to its limits. Also, the added extensions like +support for weak dependencies and patches made it fragile and +unpredictable. + +As I was not very pleased with the way the solver worked, I looked at +other solver algorithms. I checked smart, yum and apt, but could not +find a convincing algorithm. My own experiments also were not very +convincing, they worked fine for some problems but failed miserably +for other corner cases. + +=== Using SAT for solving === +SUSE's hack week at the end of June 2007 turned out to be a turning point +for the solver. Googling for solver algorithms, I stumbled over some note +saying that some people are trying to use SAT algorithms to improve +solving on Debian. Looking at the SAT entry in Wikipedia, it was easy +to see that this indeed was the missing piece: SAT algorithms are well +researched and there are quite some open source implementations. +I decided to look at the minisat code, as it is one of the fastest +solvers while consisting of too many lines of code. + +Of course, directly using minisat would not work, as a package solver +does not need to find just one correct solution, but it also has to +optimize some metrics, i.e. keep as many packages installed as possible. +Thus, I needed to write my own solver incorporation the ideas and +algorithms used in minisat. This wasn't very hard, and at the end of +the hack week the solver calculated the first right solutions. + +=== Selling it to libzypp === +With those encouraging results, I went to Klaus Kaempf, the system +management architect at SUSE. We spoke about how to convince the +team to make libzypp switch to the new solver. Fortunately, libzypp comes +with a plethora of solver test cases, so we decided to make the solver pass +most of the test cases first. Klaus wrote a "deptestomatic" implementation +to check the test cases. Together with Stephan Kulow, who is responsible for the +openSUSE distribution, we tweaked and extended the solver until most of +the test cases looked good. + +Duncan Mac-Vicar Prett, the team lead of the YaST team, also joined +development by creating Ruby bindings for the solver. Later, Klaus +improved the bindings and ported them to some other languages. + +=== The attribute store === +The progress with the repository format and the solver attracted another +hacker to the project: Michael Matz from the compiler team. He started +with improving the repository parsers so that patches and content files +also generate solvables. After that, he concentrated on storing all +of the other metadata of the repositories that are not used for solving, +like the package summaries and descriptions. At the end of October, a first +version of this "attribute store" was checked in. Its design goals were: + +- space efficient storage of attributes +- paging/on demand loading of data +- page compression + +The first version of the attribute store used a different format for +storing information, we later merged this format with the solv file +format. + +=== libzypp integration === +Integration of the sat-solver into libzypp also started in October 2007 by +Stefan Schubert and Michael Andres from the YaST team. The first +versions supported both the old solver and the new one by using the +old repository read functions and converting the old package data +in-memory into a sat solver pool. Solvers could be switched with +the environment variable ZYPP_SAT_SOLVER. The final decision to +move to the new solver was made in January of 2008, first just by +making the new solver the default one, later by completely throwing out +the old solver code. This had the advantage that the internal solvable +storage could also be done by using the solver pool, something Michael +Matz already played with in a proof of concept implementation showing +some drastic speed gains. The last traces of the old database code +were removed in February. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/libsolv-pool.txt b/doc/libsolv-pool.txt new file mode 100644 index 0000000..991083f --- /dev/null +++ b/doc/libsolv-pool.txt @@ -0,0 +1,934 @@ +Libsolv-Pool(3) +=============== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +libsolv-pool - Libsolv's pool object + + +Public Attributes +----------------- + +*void *appdata*:: +A no-purpose pointer free to use for the library user. Freeing the pool +simply discards the pointer. + +*Stringpool ss*:: +The pool of unified strings. + +*Reldep *rels*:: +The pool of unified relation dependencies. + +*int nrels*:: +Number of allocated relation dependencies. + +*Repo **repos*:: +The array of repository pointers, indexed by repository Id. + +*int nrepos*:: +Number of allocated repository array elements, i.e. the size +of the repos array. + +*int urepos*:: +Number of used (i.e. non-zero) repository array elements. + +*Repo *installed*:: +Pointer to the repo holding the installed packages. You are free to read +this attribute, but you should use pool_set_installed() if you want to +change it. + +*Solvable *solvables*:: +The array of Solvable objects. + +*int nsolvables*:: +Number of Solvable objects, i.e. the size of the solvables array. Note +that the array may contain freed solvables, in that case the repo pointer +of the solvable will be zero. + +*int disttype*:: +The distribution type of your system, e.g. DISTTYPE_DEB. You are free to +read this attribute, but you should use pool_setdisttype() if you want to +change it. + +*Id *whatprovidesdata*:: +Multi-purpose Id storage holding zero terminated arrays of Ids. +pool_whatprovides() returns an offset into this data. + +*Map *considered*:: +Optional bitmap that can make the library ignore solvables. If a bitmap is +set, only solvables that have a set bit in the bitmap at their Id are +considered usable. + +*int debugmask*:: +A mask that defines which debug events should be reported. +pool_setdebuglevel() sets this mask. + +*Datapos pos*:: +An object storing some position in the repository data. Functions like +dataiterator_set_pos() set this object, accessing data with a pseudo +solvable Id of SOLVID_POS uses it. + +*Queue pooljobs*:: +A queue where fixed solver jobs can be stored. This jobs are automatically +added when solver_solve() is called, they are useful to store configuration +data like which packages should be multiversion installed. + +Creation and Destruction +------------------------ + + Pool *pool_create(); + +Create a new instance of a pool. + + void pool_free(Pool *pool); + +Free a pool and all of the data it contains, e.g. the solvables, +repositories, strings. + + +Debugging and error reporting +----------------------------- + +=== Constants === + +*SOLV_FATAL*:: +Report the error and call ``exit(1)'' afterwards. You cannot mask this +level. Reports to stderr instead of stdout. + +*SOLV_ERROR*:: +Used to report errors. Reports to stderr instead of stdout. + +*SOLV_WARN*:: +Used to report warnings. + +*SOLV_DEBUG_STATS*:: +Used to report statistical data. + +*SOLV_DEBUG_RULE_CREATION*:: +Used to report information about the solver's creation of rules. + +*SOLV_DEBUG_PROPAGATE*:: +Used to report information about the solver's unit rule propagation +process. + +*SOLV_DEBUG_ANALYZE*:: +Used to report information about the solver's learnt rule generation +mechanism. + +*SOLV_DEBUG_UNSOLVABLE*:: +Used to report information about the solver dealing with conflicting +rules. + +*SOLV_DEBUG_SOLUTIONS*:: +Used to report information about the solver creating solutions to solve +problems. + +*SOLV_DEBUG_POLICY*:: +Used to report information about the solver searching for an optimal +solution. + +*SOLV_DEBUG_RESULT*:: +Used by the debug functions to output results. + +*SOLV_DEBUG_JOB*:: +Used to report information about the job rule generation process. + +*SOLV_DEBUG_SOLVER*:: +Used to report information about what the solver is currently +doing. + +*SOLV_DEBUG_TRANSACTION*:: +Used to report information about the transaction generation and +ordering process. + +*SOLV_DEBUG_TO_STDERR*:: +Write debug messages to stderr instead of stdout. + +=== Functions === + + void pool_debug(Pool *pool, int type, const char *format, ...); + +Report a message of the type _type_. You can filter debug messages by +setting a debug mask. + + void pool_setdebuglevel(Pool *pool, int level); + +Set a predefined debug mask. A higher level generally means more bits in +the mask are set, thus more messages are printed. + + void pool_setdebugmask(Pool *pool, int mask); + +Set the debug mask to filter debug messages. + + int pool_error(Pool *pool, int ret, const char *format, ...); + +Set the pool's error string. The _ret_ value is simply used as a +return value of the function so that you can write code like ++return pool_error(...);+. If the debug mask contains the *SOLV_ERROR* +bit, pool_debug() is also called with the message and type *SOLV_ERROR*. + + extern char *pool_errstr(Pool *pool); + +Return the current error string stored in the pool. Like with the libc's +errno value, the string is only meaningful after a function returned an +error. + + void pool_setdebugcallback(Pool *pool, void (*debugcallback)(Pool *, void *data, int type, const char *str), void *debugcallbackdata); + +Set a custom debug callback function. Instead of writing to stdout or +stderr, the callback function will be called. + + +Pool configuration +------------------ + +=== Constants === + +*DISTTYPE_RPM*:: +Used for systems which use rpm as low level package manager. + +*DISTTYPE_DEB*:: +Used for systems which use dpkg as low level package manager. + +*DISTTYPE_ARCH*:: +Used for systems which use the arch linux package manager. + +*DISTTYPE_HAIKU*:: +Used for systems which use haiku packages. + +*POOL_FLAG_PROMOTEEPOCH*:: +Promote the epoch of the providing dependency to the requesting +dependency if it does not contain an epoch. Used at some time +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. + +*POOL_FLAG_OBSOLETEUSESPROVIDES*:: +Make obsolete type dependency match against provides instead of +just the name and version of packages. Very old versions of rpm +used the name/version, then it got switched to provides and later +switched back again to just name/version. + +*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*:: +An implicit obsoletes is the internal mechanism to remove the +old package on an update. The default is to remove all packages +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. + +*POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*:: +Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if +packages of the same name can be installed in parallel. For +current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be +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 +also erase the other package. + +*POOL_FLAG_HAVEDISTEPOCH*:: +Mandriva added a new field called distepoch that gets checked in +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 +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. + +*POOL_FLAG_ADDFILEPROVIDESFILTERED*:: +Make the addfileprovides method only add files from the standard +locations (i.e. the ``bin'' and ``etc'' directories). This is +useful if you have only few packages that use non-standard file +dependencies, but you still want the fast speed that addfileprovides() +generates. + + +=== Functions === + int pool_setdisttype(Pool *pool, int disttype); + +Set the package type of your system. The disttype is used for example +to define package comparison semantics. Libsolv's 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. + + int pool_set_flag(Pool *pool, int flag, int value); + +Set a flag to a new value. Returns the old value of the flag. + + int pool_get_flag(Pool *pool, int flag); + +Get the value of a pool flag. See the constants section about the meaning +of the flags. + + void pool_set_rootdir(Pool *pool, const char *rootdir); + +Set a specific root directory. Some library functions support a flag that +tells the function to prepend the rootdir to file and directory names. + + const char *pool_get_rootdir(Pool *pool); + +Return the current value of the root directory. + + char *pool_prepend_rootdir(Pool *pool, const char *dir); + +Prepend the root directory to the _dir_ argument string. The returned +string has been newly allocated and needs to be freed after use. + + char *pool_prepend_rootdir_tmp(Pool *pool, const char *dir); + +Same as pool_prepend_rootdir, but uses the pool's temporary space for +allocation. + + void pool_set_installed(Pool *pool, Repo *repo); + +Set which repository should be treated as the ``installed'' repository, +i.e. the one that holds information about the installed packages. + + void pool_set_languages(Pool *pool, const char **languages, int nlanguages); + +Set the language of your system. The library provides lookup functions that +return localized strings, for example for package descriptions. You can +set an array of languages to provide a fallback mechanism if one language +is not available. + + void pool_setarch(Pool *pool, const char *arch); + +Set the architecture of your system. The architecture is used to determine +which packages are installable and which packages cannot be installed. +The _arch_ argument is normally the ``machine'' value of the ``uname'' +system call. + + void pool_setarchpolicy(Pool *, const char *); + +Set the architecture policy for your system. This is the general version +of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally). +See the section about architecture policies for more information. + + void pool_addvendorclass(Pool *pool, const char **vendorclass); + +Add a new vendor equivalence class to the system. A vendor equivalence class +defines if an installed package of one vendor can be replaced by a package +coming from a different vendor. The _vendorclass_ argument must be a +NULL terminated array of strings. See the section about vendor policies for +more information. + + void pool_setvendorclasses(Pool *pool, const char **vendorclasses); + +Set all allowed vendor equivalences. The vendorclasses argument must be an +NULL terminated array consisting of all allowed classes concatenated. +Each class itself must be NULL terminated, thus the last class ends with +two NULL elements, one to finish the class and one to finish the list +of classes. + + void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *)); + +Define a custom vendor check mechanism. You can use this if libsolv's +internal vendor equivalence class mechanism does not match your needs. + + void pool_setloadcallback(Pool *pool, int (*cb)(Pool *, Repodata *, void *), void *loadcbdata); + +Define a callback function that gets called when repository metadata needs +to be loaded on demand. See the section about on demand loading in the +libsolv-repodata manual. + + void pool_setnamespacecallback(Pool *pool, Id (*cb)(Pool *, void *, Id, Id), void *nscbdata); + +Define a callback function to implement custom namespace support. See the +section about namespace dependencies. + + +Id pool management +------------------ +=== Constants === + +*ID_EMPTY*:: +The Id of the empty string, it is always Id 1. + +*REL_LT*:: +Represents a ``<'' relation. + +*REL_EQ*:: +Represents a ``='' relation. + +*REL_GT*:: +Represents a ``>'' relation. You can use combinations of REL_GT, REL_EQ, +and REL_LT or-ed together to create any relation you like. + +*REL_AND*:: +A boolean AND operation, the ``name'' and ``evr'' parts of the relation can +be two sub-dependencies. Packages must match both parts of the dependency. + +*REL_OR*:: +A boolean OR operation, the ``name'' and ``evr'' parts of the relation can +be two sub-dependencies. Packages can match any part of the dependency. + +*REL_WITH*:: +Like REL_AND, but packages must match both dependencies simultaneously. See +the section about boolean dependencies about more information. + +*REL_NAMESPACE*:: +A special namespace relation. See the section about namespace dependencies +for more information. + +*REL_ARCH*:: +An architecture filter dependency. The ``name'' part of the relation is a +sub-dependency, the ``evr'' part is the Id of an architecture that the +matching packages must have (note that this is an exact match ignoring +architecture policies). + +*REL_FILECONFLICT*:: +An internal file conflict dependency used to represent file conflicts. See +the pool_add_fileconflicts_deps() function. + +*REL_COND*:: +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); + +Add a string to the pool of unified strings, returning the Id of the string. +If _create_ is zero, new strings will not be added to the pool, instead +Id 0 is returned. + + Id pool_strn2id(Pool *pool, const char *str, unsigned int len, int create); + +Same as pool_str2id, but only _len_ characters of the string are used. This +can be used to add substrings to the pool. + + Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create); + +Create a relational dependency from to other dependencies, _name_ and _evr_, +and a _flag_. See the *REL_* constants for the supported flags. As with +pool_str2id, _create_ defines if new dependencies will get added or Id zero +will be returned instead. + + Id pool_id2langid(Pool *pool, Id id, const char *lang, int create); + +Attach a language suffix to a string Id. This function can be used to +create language keyname Ids from keynames, it is functional equivalent +to converting the _id_ argument to a string, adding a ``:'' character +and the _lang_ argument to the string and then converting the result back +into an Id. + + const char *pool_id2str(const Pool *pool, Id id); + +Convert an Id back into a string. If the Id is a relational Id, the +``name'' part will be converted instead. + + const char *pool_id2rel(const Pool *pool, Id id); + +Return the relation string of a relational Id. Returns an empty string if +the passed Id is not a relation. + + const char *pool_id2evr(const Pool *pool, Id id); + +Return the ``evr'' part of a relational Id as string. Returns an empty +string if the passed Id is not a relation. + + const char *pool_dep2str(Pool *pool, Id id); + +Convert an Id back into a string. If the passed Id belongs to a relation, +a string representing the relation is returned. Note that in that case +the string is allocated on the pool's temporary space. + + void pool_freeidhashes(Pool *pool); + +Free the hashes used to unify strings and relations. You can use this +function to save memory if you know that you will no longer create new +strings and relations. + + +Solvable functions +------------------ + + Solvable *pool_id2solvable(const Pool *pool, Id p); + +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 +be some canonical representation of the solvable, usually a combination of +the name, the version, and the architecture. + + const char *pool_solvable2str(Pool *pool, Solvable *s); + +Same as pool_solvid2str, but instead of the Id, a pointer to the solvable +is passed. + + +Dependency matching +------------------- + +=== Constants === +*EVRCMP_COMPARE*:: +Compare all parts of the version, treat missing parts as empty strings. + +*EVRCMP_MATCH_RELEASE*:: +A special mode for rpm version string matching. If a version misses a +release part, it matches all releases. In that case the special values +``-2'' and ``2'' are returned, depending on which of the two versions +did not have a release part. + +*EVRCMP_MATCH*:: +A generic match, missing parts always match. + +*EVRCMP_COMPARE_EVONLY*:: +Only compare the epoch and the version parts, ignore the release part. + +=== Functions === + int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode); + +Compare two version Ids, return -1 if the first version is less than the +second version, 0 if they are identical, and 1 if the first version is +bigger than the second one. + + int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode); + +Same as pool_evrcmp(), but uses strings instead of Ids. + + int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release); + +Match a version Id against an epoch, a version and a release string. Passing +NULL means that the part should match everything. + + int pool_match_dep(Pool *pool, Id d1, Id d2); + +Returns ``1'' if the dependency _d1_ (the provider) is matched by the +dependency _d2_, otherwise ``0'' is returned. For two dependencies to +match, both the ``name'' parts must match and the version range described +by the ``evr'' parts must overlap. + + int pool_match_nevr(Pool *pool, Solvable *s, Id d); + +Like pool_match_dep, but the provider is the "self-provides" dependency +of the Solvable _s_, i.e. the dependency ``s->name = s->evr''. + + +Whatprovides Index +------------------ + void pool_createwhatprovides(Pool *pool); + +Create an index that maps dependency Ids to sets of packages that provide the +dependency. + + void pool_freewhatprovides(Pool *pool); + +Free the whatprovides index to save memory. + + Id pool_whatprovides(Pool *pool, Id d); + +Return an offset into the Pool's whatprovidesdata array. The solvables with +the Ids stored starting at that offset provide the dependency _d_. The +solvable list is zero terminated. + + Id *pool_whatprovides_ptr(Pool *pool, Id d); + +Instead of returning the offset, return the pointer to the Ids stored at +that offset. Note that this pointer has a very limit validity time, as any +call that adds new values to the whatprovidesdata area may reallocate the +array. + + Id pool_queuetowhatprovides(Pool *pool, Queue *q); + +Add the contents of the Queue _q_ to the end of the whatprovidesdata array, +returning the offset into the array. + + void pool_addfileprovides(Pool *pool); + +Some package managers like rpm allow dependencies on files contained in +other packages. To allow libsolv to deal with those dependencies in an +efficient way, you need to call the addfileprovides method after creating +and reading all repositories. This method will scan all dependency for file +names and then scan all packages for matching files. If a filename has been +matched, it will be added to the provides list of the corresponding +package. + + void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst); + +Same as pool_addfileprovides, but the added Ids are returned in two Queues, +_idq_ for all repositories except the one containing the ``installed'' +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 +namespace _ns_. If the _evr_ argument is non-zero, the namespace dependency +for exactly that dependency is cleared, otherwise all matching namespace +dependencies are cleared. See the section about Namespace dependencies +for further information. + + void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts); + +Some package managers like rpm report conflicts when a package installation +overwrites a file of another installed package with different content. As +file content information is not stored in the repository metadata, those +conflicts can only be detected after the packages are downloaded. Libsolv +provides a function to check for such conflicts, pool_findfileconflicts(). +If conflicts are found, they can be added as special *REL_FILECONFLICT* +provides dependencies, so that the solver will know about the conflict when +it is re-run. + + +Utility functions +----------------- + char *pool_alloctmpspace(Pool *pool, int len); + +Allocate space on the pool's temporary space area. This space has a limited +lifetime, it will be automatically freed after a fixed amount (currently +16) of other pool_alloctmpspace() calls are done. + + void pool_freetmpspace(Pool *pool, const char *space); + +Give the space allocated with pool_alloctmpspace back to the system. You +do not have to use this function, as the space is automatically reclaimed, +but it can be useful to extend the lifetime of other pointers to the pool's +temporary space area. + + const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len); + +Convert some binary data to hexadecimal, returning a string allocated in +the pool's temporary space area. + + char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3); + +Join three strings and return the result in the pool's temporary space +area. You can use NULL arguments if you just want to join less strings. + + char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3); + +Like pool_tmpjoin(), but if the first argument is the last allocated space +in the pool's temporary space area, it will be replaced with the result of +the join and no new temporary space slot will be used. Thus you can join +more than three strings by a combination of one pool_tmpjoin() and multiple +pool_tmpappend() calls. Note that the _str1_ pointer is no longer usable +after the call. + + +Data lookup +----------- +=== Constants === + +*SOLVID_POS*:: +Use the data position stored in the pool for the lookup instead of looking +up the data of a solvable. + +*SOLVID_META*:: +Use the data stored in the meta section of a repository (or repodata +area) instead of looking up the data of a solvable. This constant does +not work for the pool's lookup functions, use it for the repo's or +repodata's lookup functions instead. It's just listed for completeness. + +=== Functions === + const char *pool_lookup_str(Pool *pool, Id solvid, Id keyname); + +Return the string value stored under the attribute _keyname_ in solvable +_solvid_. + + unsigned long long pool_lookup_num(Pool *pool, Id solvid, Id keyname, unsigned long long notfound); + +Return the 64bit unsigned number stored under the attribute _keyname_ in +solvable _solvid_. If no such number is found, the value of the _notfound_ +argument is returned instead. + + Id pool_lookup_id(Pool *pool, Id solvid, Id keyname); + +Return the Id stored under the attribute _keyname_ in solvable _solvid_. + + int pool_lookup_idarray(Pool *pool, Id solvid, Id keyname, Queue *q); + +Fill the queue _q_ with the content of the Id array stored under the +attribute _keyname_ in solvable _solvid_. Returns ``1'' if an array was +found, otherwise the queue will be empty and ``0'' will be returned. + + int pool_lookup_void(Pool *pool, Id solvid, Id keyname); + +Returns ``1'' if a void value is stored under the attribute _keyname_ in +solvable _solvid_, otherwise ``0''. + + const char *pool_lookup_checksum(Pool *pool, Id solvid, Id keyname, Id *typep); + +Return the checksum that is stored under the attribute _keyname_ in +solvable _solvid_. The type of the checksum will be returned over the +_typep_ pointer. If no such checksum is found, NULL will be returned and +the type will be set to zero. Note that the result is stored in the Pool's +temporary space area. + + const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id solvid, Id keyname, Id *typep); + +Return the checksum that is stored under the attribute _keyname_ in +solvable _solvid_. Returns the checksum as binary data, you can use the +returned type to calculate the length of the checksum. No temporary space +area is needed. + + const char *pool_lookup_deltalocation(Pool *pool, Id solvid, unsigned int *medianrp); + +This is a utility lookup function to return the delta location for a delta +rpm. As solvables cannot store deltas, you have to use SOLVID_POS as +argument and set the Pool's datapos pointer to point to valid delta rpm +data. + + void pool_search(Pool *pool, Id solvid, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata); + +Perform a search on all data stored in the pool. You can limit the search +area by using the _solvid_ and _keyname_ arguments. The values can be +optionally matched against the _match_ argument, use NULL if you do not +want this matching. See the Dataiterator manpage about the possible matches +modes and the _flags_ argument. For all (matching) values, the callback +function is called with the _cbdata_ callback argument and the data +describing the value. + + +Job and Selection functions +--------------------------- +A Job consists of two Ids, _how_ and _what_. The _how_ part describes the +action, the job flags, and the selection method while the _what_ part is +in input for the selection. A Selection is a queue consisting of multiple +jobs (thus the number of elements in the queue must be a multiple of two). +See the Solver manpage for more information about jobs. + + const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask); + +Convert a job into a string. Useful for debugging purposes. The _flagmask_ +can be used to mask the flags of the job, use ``0'' if you do not want to +see such flags, ``-1'' to see all flags, or a combination of the flags +you want to see. + + void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what); + +Return a list of solvables that the specified job selects. + + int pool_isemptyupdatejob(Pool *pool, Id how, Id what); + +Return ``1'' if the job is an update job that does not work with any +installed package, i.e. the job is basically a no-op. You can use this +to turn no-op update jobs into install jobs (as done by package managers +like ``zypper''). + + const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask); + +Convert a selection into a string. Useful for debugging purposes. See the +pool_job2str() function for the _flagmask_ argument. + + +Odds and Ends +------------- + void pool_freeallrepos(Pool *pool, int reuseids); + +Free all repos from the pool (including all solvables). If _reuseids_ is +true, all Ids of the solvables are free to be reused the next time +solvables are created. + + void pool_clear_pos(Pool *pool); + +Clear the data position stored in the pool. + + +Architecture Policies +--------------------- +An architecture policy defines a list of architectures that can be +installed on the system, and also the relationship between them (i.e. the +ordering). Architectures can be delimited with three different characters: + +*\':'*:: +No relationship between the architectures. A package of one architecture +can not be replaced with one of the other architecture. + +*\'>'*:: +The first architecture is better than the second one. An installed package +of the second architecture may be replaced with one from the first +architecture and vice versa. The solver will select the better architecture +if the versions are the same. + +*\'='*:: +The two architectures are freely exchangeable. Used to define aliases +for architectures. + +An example would be \'+x86_64:i686=athlon>i586+'. This means that x86_64 +packages can only be replaced by other x86_64 packages, i686 packages +can be replaced by i686 and i586 packages (but i686 packages will be +preferred) and athlon is another name for the i686 architecture. + +You can turn off the architecture replacement checks with the Solver's +SOLVER_FLAG_ALLOW_ARCHCHANGE flag. + +Vendor Policies +--------------- +Different vendors often compile packages with different features, so +Libsolv only replace installed packages of one vendor with packages coming +from the same vendor. Also, while the version of a package is normally +defined by the upstream project, the release part of the version is +set by the vendor's package maintainer, so it's not meaningful to +do version comparisons for packages coming from different vendors. + +Vendor in this case means the SOLVABLE_VENDOR string stored in each +solvable. Sometimes a vendor changes names, or multiple vendors form a +group that coordinate their package building, so libsolv offers a way +to define that a group of vendors are compatible. You do that be +defining vendor equivalence classes, packages from a vendor from +one class may be replaced with packages from all the other vendors +in the class. + +There can be multiple equivalence classes, the set of allowed vendor +changes for an installed package is calculated by building the union +of all of the equivalence classes the vendor of the installed package +is part of. + +You can turn off the vendor replacement checks with the Solver's +SOLVER_FLAG_ALLOW_VENDORCHANGE flag. + + +Boolean Dependencies +-------------------- +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. + +*REL_OR*:: +The expression is true if either the first dependency or the second +one is true. This is useful for package dependencies like ``Requires'', +where you can specify that either one of the packages need to be +installed. + +*REL_AND*:: +The expression is true if both dependencies are true. The packages +fulfilling the dependencies may be different, i.e. +``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 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. ``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. + + +Namespace Dependencies +---------------------- +Namespace dependencies can be used to implement dependencies on +attributes external to libsolv. An example would be a dependency +on the language set by the user. This types of dependencies are +usually only used for ``Conflicts'' or ``Supplements'' dependencies, +as the underlying package manager does not know how to deal with +them. + +If the library needs to evaluate a namespace dependency, it calls +the namespace callback function set in the pool. The callback +function can return a set of packages that ``provide'' the +dependency. If the dependency is provided by the system, the +returned set should consist of just the system solvable (Solvable +Id 1). + +The returned set of packages must be returned as offset into +the whatprovidesdata array. You can use the pool_queuetowhatprovides +function to convert a queue into such an offset. To ease programming +the callback function, the return values ``0'' and ``1'' are not +interpreted as an offset. ``0'' means that no package is in the +return set, ``1'' means that just the system solvable is in the set. + +The returned set is cached, so that for each namespace dependency +the callback is just called once. If you need to flush the cache (maybe +because the user has selected a different language), use the +pool_flush_namespaceproviders() function. + + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/libsolv.txt b/doc/libsolv.txt new file mode 100644 index 0000000..f101808 --- /dev/null +++ b/doc/libsolv.txt @@ -0,0 +1,61 @@ +Libsolv(3) +========== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +libsolv - package dependency solver library using a satisfiability algorithm + + +Documentation +------------- +The libsolv documentation is split into multiple parts: + +*libsolv-history*:: + how the libsolv library came into existence + +*libsolv-constantids*:: + fixed Ids for often used strings + +*libsolv-bindings*:: + access libsolv from perl/python/ruby + +*libsolv-pool*:: + libsolv's pool object + +Pointer Validity +---------------- +Note that all pointers to objects that have an Id have only a limited +validity period, with the exception of Repo pointers. There are only +guaranteed to be valid until a new object of that type is added or an +object of that type is removed. Thus pointers to Solvable objects are only +valid until another solvable is created, because adding a Solvable may +relocate the Pool's Solvable array. This is also true for Pool strings, +you should use solv_strdup() to create a copy of the string if you +want to use it at some later time. You should use the Ids in the code +and not the pointers, except for short times where you know that the +pointer is safe. + +Note also that the data lookup functions or the dataiterator also +return values with limited lifetime, this is especially true for data +stored in the paged data segment of solv files. This is normally +data that consists of big strings like package descriptions or is not +often needed like package checksums. Thus looking up a description of +a solvable and then looking up the description of a different solvable +or even the checksum of the same solvable may invalidate the first +result. (The dataiterator supports a dataiterator_strdup() function +to create a safe copy.) + +The language bindings already deal with pointer validity, so you do +not have to worry about this issue when using the bindings. + + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/mdk2solv.txt b/doc/mdk2solv.txt new file mode 100644 index 0000000..eb2ac14 --- /dev/null +++ b/doc/mdk2solv.txt @@ -0,0 +1,37 @@ +mdk2solv(1) +=========== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +mdk2solv - convert files in Mandriva synthesis format into a solv file + +Synopsis +-------- +*mdk2solv* ['OPTIONS'] + +Description +----------- +The mdk2solv tool reads Mandriva synthesis data (*hdlist*) from stdin, and writes +it as solv file to standard output. + +*-i* 'INFO.xml':: +Also read the info file containing url, license, and src information from +the specified xml file. + +*-f* 'FILES.xml':: +Also read filelist information from the specified xml file. + +See Also +-------- +genhdlist2(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/mergesolv.txt b/doc/mergesolv.txt new file mode 100644 index 0000000..8ae67d1 --- /dev/null +++ b/doc/mergesolv.txt @@ -0,0 +1,29 @@ +mergesolv(1) +============ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +mergesolv - merge multiple files in solv format into a single one + +Synopsis +-------- +*mergesolv* ['OPTIONS'] 'FILE1.solv' 'FILE2.solv' ... + +Description +----------- +The mergesolv tool reads all solv files specified on the command line, +and writes a merged version to standard output. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/repo2solv.txt b/doc/repo2solv.txt new file mode 100644 index 0000000..3b2145f --- /dev/null +++ b/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/doc/repomdxml2solv.txt b/doc/repomdxml2solv.txt new file mode 100644 index 0000000..3b77820 --- /dev/null +++ b/doc/repomdxml2solv.txt @@ -0,0 +1,40 @@ +repomdxml2solv(1) +================= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +repomdxml2solv - convert a repomd.xml file into a solv file + +Synopsis +-------- +*repomdxml2solv* ['OPTIONS'] + +Description +----------- +The repomd.xml file is the index file of a rpm-md repository, +containing references to all data file with checksums. The +repomdxml2solv tool reads the repomd.xml file from stdin and +writes the parsed data as solv file to standard output. The +data is stored as meta attributes in the result. + +*-q* 'WHAT':: +Data query mode: instead of writing a solv file, select the +'WHAT' element in the input data and write it to standard output. +Examples for 'WHAT' are *type* to get a list of all types, and +*primary:location* to get the location of the element with +type *primary*. + +See Also +-------- +rpmmd2solv(1), mergesolv(1), createrepo(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/rpmdb2solv.txt b/doc/rpmdb2solv.txt new file mode 100644 index 0000000..128e179 --- /dev/null +++ b/doc/rpmdb2solv.txt @@ -0,0 +1,66 @@ +rpmdb2solv(1) +============= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +rpmdb2solv - convert the rpm database into a solv file + +Synopsis +-------- +*rpmdb2solv* ['OPTIONS'] ['REFFILE.solv'] + +Description +----------- +The rpmdb2solv tool reads rpm's installed packages database +and writes it in solv file format to standard output. You can +make use of an old version of the database by specifying a +'REFFILE.solv' file. + +*-o* 'OUTFILE':: +Write the generated solv to 'OUTFILE' instead of standard output. + +*-P*:: +Print percentages as packages are being read in. The output +format is like rpm's --percent option. + +*-r* 'ROOTDIR':: +Use 'ROOTDIR' as root directory. + +*-k*:: +Read pubkeys from the rpm database instead of installed packages. +Note that many distributions stopped storing pubkeys in the +database but use a directory like */var/lib/rpm/pubkeys* +instead. + +*-A*:: +Also scan the */usr/share/appdata* for installed appdata files +and create pseudo packages for each file. + +*-p* 'PRODDIR':: +Also read SUSE product files from directory 'PRODDIR'. The +standard directory is */etc/products.d*. + +*-n*:: +Do not read any packages from the rpm database. This is useful +together with *-p* to only convert SUSE products. + +*-C*:: +Include the package changelog in the generated solv file. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +See Also +-------- +rpms2solv(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/rpmmd2solv.txt b/doc/rpmmd2solv.txt new file mode 100644 index 0000000..f103f06 --- /dev/null +++ b/doc/rpmmd2solv.txt @@ -0,0 +1,34 @@ +rpmmd2solv(1) +============= +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +rpmmd2solv - convert files in rpm-md format into a solv file + +Synopsis +-------- +*rpmmd2solv* ['OPTIONS'] + +Description +----------- +The rpmmd2solv tool reads rpm-md xml data from stdin, and writes +it as solv file to standard output. It understands the *primary*, +*filelist*, *other*, and *susedata* format. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +See Also +-------- +repomdxml2solv(1), mergesolv(1), createrepo(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/rpms2solv.txt b/doc/rpms2solv.txt new file mode 100644 index 0000000..11bdcf0 --- /dev/null +++ b/doc/rpms2solv.txt @@ -0,0 +1,52 @@ +rpms2solv(1) +============ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +rpms2solv - convert one or more rpms into a solv file + +Synopsis +-------- +*rpms2solv* ['OPTIONS'] 'RPM1.rpm' ... + +Description +----------- +The rpms2solv tool converts the header data from one or more +rpms into the solv file written to standard output. + +*-m* 'MANIFESTFILE':: +Read the rpm file names from the specified 'MANIFESTFILE'. You can +use *-* to read the manifest from standard input. + +*-0*:: +Use a null byte as line terminator for manifest files instead of +a newline. This is useful if the file names can contain newlines. +See also the *-print0* option in *find*. + +*-F*:: +Do not put all files from the headers into the file list, but +instead use the filtering also found in *createrepo*. + +*-k*:: +Read pubkeys instead of rpms. + +*-K*:: +Read pubkey keyrings instead of rpms. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +See Also +-------- +rpmdb2solv(1) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/solv.txt b/doc/solv.txt new file mode 100644 index 0000000..936ae78 --- /dev/null +++ b/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/doc/susetags2solv.txt b/doc/susetags2solv.txt new file mode 100644 index 0000000..0d61c4d --- /dev/null +++ b/doc/susetags2solv.txt @@ -0,0 +1,43 @@ +susetags2solv(1) +================ +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +susetags2solv - convert the susetags repository format into a solv file + +Synopsis +-------- +*susetags2solv* ['OPTIONS'] + +Description +----------- +The susetags format is most as repository format on most products +created by SUSE. The susetags2solv reads data from standard input, +converts the format into a solv file, and writes it to standard output. + +*-c* 'CONTENTFILE':: +Also parse the specified content file containing meta information +about the repository. + +*-q* 'WHAT':: +Data query mode: instead of writing a solv file, select the +'WHAT' element in the input data and write it to standard output. +An example for 'WHAT' is *defaultvendor* to get a default vendor for +the repository. + +*-M* 'MERGEFILE.solv':: +Merge the content of the specified solv file into the output. + +*-X*:: +Autoexpand SUSE pattern and product provides into packages. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/testsolv.txt b/doc/testsolv.txt new file mode 100644 index 0000000..eb52d95 --- /dev/null +++ b/doc/testsolv.txt @@ -0,0 +1,45 @@ +testsolv(1) +=========== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +testsolv - run a libsolv testcase through the solver + +Synopsis +-------- +*testsolv* ['OPTIONS'] 'TESTCASE' + +Description +----------- +The testsolv tools can be used to run a testcase. Testcases can +either be manually created to test specific features, or they +can be written by libsolv's testcase_write function. This is useful +to evaluate bug reports about the solver. + +*-v*:: +Increase the debug level of the solver. This option can be specified +multiple times to further increase the amount of debug data. + +*-r*:: +Write the output in testcase format instead of human readable text. +The output can then be used in the result section of the test case. +If the *-r* option is given twice, the output is formated for +verbatim inclusion. + +*-l* 'PKGSPEC':: +Instead of running the solver, list packages in the repositories. + +*-s* 'SOLUTIONSPEC':: +This is used in the solver test suite to test the calculated solutions +to encountered problems. + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/doc/updateinfoxml2solv.txt b/doc/updateinfoxml2solv.txt new file mode 100644 index 0000000..6ebdeb4 --- /dev/null +++ b/doc/updateinfoxml2solv.txt @@ -0,0 +1,31 @@ +updateinfoxml2solv(1) +===================== +:man manual: LIBSOLV +:man source: libsolv + + +Name +---- +updateinfoxml2solv - convert rpm-md's updateinfo.xml format into a solv file + +Synopsis +-------- +*updateinfoxml2solv* ['OPTIONS'] + +Description +----------- +The updateinfoxml2solv tool reads rpm-md's updateinfo xml data from stdin, +and writes it as solv file to standard output. Update elements are converted +into special *patch:* pseudo packages. + +See Also +-------- +mergesolv(1), createrepo(8) + +Author +------ +Michael Schroeder + +//// +vim: syntax=asciidoc +//// diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..703796c --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +IF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA) + +ADD_SUBDIRECTORY (solv) + +ENDIF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA) diff --git a/examples/p5solv b/examples/p5solv new file mode 100755 index 0000000..6f54247 --- /dev/null +++ b/examples/p5solv @@ -0,0 +1,751 @@ +#!/usr/bin/perl -w + +use POSIX; +use Fcntl; +use Config::IniFiles; +use Data::Dumper; +use solv; +use Devel::Peek; +use FileHandle; +use File::Temp (); +use strict; + +package Repo::generic; + +sub new { + my ($class, $alias, $type, $attr) = @_; + my $r = { %{$attr || {}} }; + $r->{alias} = $alias; + $r->{type} = $type; + return bless $r, $class; +} + +sub calc_cookie_fp { + my ($self, $fp) = @_; + my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256); + $chksum->add("1.1"); + $chksum->add_fp($fp); + return $chksum->raw(); +} + +sub calc_cookie_file { + my ($self, $filename) = @_; + my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256); + $chksum->add("1.1"); + $chksum->add_stat($filename); + return $chksum->raw(); +} + +sub calc_cookie_ext { + my ($self, $f, $cookie) = @_; + my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256); + $chksum->add("1.1"); + $chksum->add($cookie); + $chksum->add_fstat(fileno($f)); + return $chksum->raw(); +} + +sub cachepath { + my ($self, $ext) = @_; + my $path = $self->{alias}; + $path =~ s/^\./_/s; + $path .= $ext ? "_$ext.solvx" : '.solv'; + $path =~ s!/!_!gs; + return "/var/cache/solv/$path"; +} + +sub load { + my ($self, $pool) = @_; + $self->{handle} = $pool->add_repo($self->{alias}); + $self->{handle}->{appdata} = $self; + $self->{handle}->{priority} = 99 - $self->{priority}; + my $dorefresh = $self->{autorefresh}; + if ($dorefresh) { + my @s = stat($self->cachepath()); + $dorefresh = 0 if @s && ($self->{metadata_expire} == -1 || time() - $s[9] < $self->{metadata_expire}); + } + $self->{cookie} = ''; + $self->{extcookie} = ''; + if (!$dorefresh && $self->usecachedrepo()) { + print "repo: '$self->{alias}' cached\n"; + return 1; + } + return 0; +} + +sub load_ext { + return 0; +} + +sub download { + my ($self, $file, $uncompress, $chksum, $markincomplete) = @_; + if (!$self->{baseurl}) { + print "$self->{alias}: no baseurl\n"; + return undef; + } + my $url = $self->{baseurl}; + $url =~ s!/$!!; + $url .= "/$file"; + open(my $f, '+>', undef) || die; + fcntl($f, Fcntl::F_SETFD, 0); # turn off CLOEXEC + my $st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" . fileno($f), '--', $url); + if (POSIX::lseek(fileno($f), 0, POSIX::SEEK_END) == 0 && ($st == 0 || !$chksum)) { + return undef; + } + POSIX::lseek(fileno($f), 0, POSIX::SEEK_SET); + if ($st) { + print "$file: download error #$st\n"; + $self->{incomplete} = 1 if $markincomplete; + return undef; + } + if ($chksum) { + my $fchksum = solv::Chksum->new($chksum->{type}); + $fchksum->add_fd(fileno($f)); + if ($fchksum != $chksum) { + print "$file: checksum error\n"; + $self->{incomplete} = 1 if $markincomplete; + return undef; + } + } + if ($uncompress) { + return solv::xfopen_fd($file, fileno($f)); + } else { + return solv::xfopen_fd(undef, fileno($f)); + } +} + +sub usecachedrepo { + my ($self, $ext, $mark) = @_; + my $cookie = $ext ? $self->{extcookie} : $self->{cookie}; + my $cachepath = $self->cachepath($ext); + my $fextcookie; + if (sysopen(my $f, $cachepath, POSIX::O_RDONLY)) { + sysseek($f, -32, Fcntl::SEEK_END); + my $fcookie = ''; + return undef if sysread($f, $fcookie, 32) != 32; + return undef if $cookie && $fcookie ne $cookie; + if ($self->{type} ne 'system' && !$ext) { + sysseek($f, -32 * 2, Fcntl::SEEK_END); + return undef if sysread($f, $fextcookie, 32) != 32; + } + sysseek($f, 0, Fcntl::SEEK_SET); + my $fd = solv::xfopen_fd(undef, fileno($f)); + my $flags = $ext ? $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES : 0; + $flags |= $solv::Repo::REPO_LOCALPOOL if $ext && $ext ne 'DL'; + if (!$self->{handle}->add_solv($fd, $flags)) { + return undef; + } + $self->{cookie} = $fcookie unless $ext; + $self->{extcookie} = $fextcookie if $fextcookie; + utime undef, undef, $f if $mark; + return 1; + } + return undef; +} + +sub writecachedrepo { + my ($self, $ext, $repodata) = @_; + return if $self->{incomplete}; + mkdir("/var/cache/solv", 0755) unless -d "/var/cache/solv"; + my ($f, $tmpname); + eval { + ($f, $tmpname) = File::Temp::tempfile(".newsolv-XXXXXX", 'DIR' => '/var/cache/solv'); + }; + return unless $f; + chmod 0444, $f; + my $ff = solv::xfopen_fd(undef, fileno($f)); + if (!$repodata) { + $self->{handle}->write($ff); + } elsif ($ext) { + $repodata->write($ff); + } else { + $self->{handle}->write_first_repodata($ff); + } + undef $ff; # also flushes + if ($self->{type} ne 'system' && !$ext) { + $self->{extcookie} ||= $self->calc_cookie_ext($f, $self->{cookie}); + syswrite($f, $self->{extcookie}); + } + syswrite($f, $ext ? $self->{extcookie} : $self->{cookie}); + close($f); + if ($self->{handle}->iscontiguous()) { + $f = solv::xfopen($tmpname); + if ($f) { + if (!$ext) { + $self->{handle}->empty(); + die("internal error, cannot reload solv file\n") unless $self->{handle}->add_solv($f, $repodata ? 0 : $solv::Repo::SOLV_ADD_NO_STUBS); + } else { + $repodata->extend_to_repo(); + my $flags = $solv::Repo::REPO_EXTEND_SOLVABLES; + $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL'; + $repodata->add_solv($f, $flags); + } + } + } + rename($tmpname, $self->cachepath($ext)); +} + +sub packagespath { + my ($self) = @_; + return ''; +} + +my %langtags = ( + $solv::SOLVABLE_SUMMARY => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_EULA => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_MESSAGEINS => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_MESSAGEDEL => $solv::REPOKEY_TYPE_STR, + $solv::SOLVABLE_CATEGORY => $solv::REPOKEY_TYPE_ID, +); + +sub add_ext_keys { + my ($self, $ext, $repodata, $handle) = @_; + if ($ext eq 'DL') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY); + } elsif ($ext eq 'DU') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY); + } elsif ($ext eq 'FL') { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY); + } else { + for my $langid (sort { $a <=> $b } keys %langtags) { + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{handle}->{pool}->id2langid($langid, $ext, 1)); + $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid}); + } + } +} + +package Repo::rpmmd; + +our @ISA = ('Repo::generic'); + +sub find { + my ($self, $what) = @_; + my $di = $self->{handle}->Dataiterator_meta($solv::REPOSITORY_REPOMD_TYPE, $what, $solv::Dataiterator::SEARCH_STRING); + $di->prepend_keyname($solv::REPOSITORY_REPOMD); + for my $d (@$di) { + my $dp = $d->parentpos(); + my $filename = $dp->lookup_str($solv::REPOSITORY_REPOMD_LOCATION); + next unless $filename; + my $chksum = $dp->lookup_checksum($solv::REPOSITORY_REPOMD_CHECKSUM); + if (!$chksum) { + print "no $filename file checksum!\n"; + return (undef, undef); + } + return ($filename, $chksum); + } + return (undef, undef); +} + +sub add_ext { + my ($self, $repodata, $what, $ext) = @_; + my ($filename, $chksum) = $self->find($what); + ($filename, $chksum) = $self->find('prestodelta') if !$filename && $what eq 'deltainfo'; + return unless $filename; + my $handle = $repodata->new_handle(); + $repodata->set_poolstr($handle, $solv::REPOSITORY_REPOMD_TYPE, $what); + $repodata->set_str($handle, $solv::REPOSITORY_REPOMD_LOCATION, $filename); + $repodata->set_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum); + $self->add_ext_keys($ext, $repodata, $handle); + $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle); +} + +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(); +} + +sub load_ext { + my ($self, $repodata) = @_; + my $repomdtype = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_TYPE); + my $ext; + if ($repomdtype eq 'filelists') { + $ext = 'FL'; + } elsif ($repomdtype eq 'deltainfo') { + $ext = 'DL'; + } else { + return 0; + } + print("[$self->{alias}:$ext: "); + STDOUT->flush(); + if ($self->usecachedrepo($ext)) { + print "cached]\n"; + return 1; + } + print "fetching]\n"; + my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_LOCATION); + my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_CHECKSUM); + my $f = $self->download($filename, 1, $filechksum); + return 0 unless $f; + if ($ext eq 'FL') { + $self->{handle}->add_rpmmd($f, 'FL', $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES|$solv::Repo::REPO_LOCALPOOL); + } elsif ($ext eq 'DL') { + $self->{handle}->add_deltainfoxml($f, $solv::Repo::REPO_USE_LOADING); + } + $self->writecachedrepo($ext, $repodata); + return 1; +} + +sub load { + my ($self, $pool) = @_; + return 1 if $self->Repo::generic::load($pool); + print "rpmmd repo '$self->{alias}': "; + STDOUT->flush(); + my $f = $self->download("repodata/repomd.xml"); + if (!$f) { + print "no repomd.xml file, skipped\n"; + $self->{handle}->free(1); + delete $self->{handle}; + return undef; + } + $self->{cookie} = $self->calc_cookie_fp($f); + if ($self->usecachedrepo(undef, 1)) { + print "cached\n"; + return 1; + } + $self->{handle}->add_repomdxml($f, 0); + print "fetching\n"; + my ($filename, $filechksum) = $self->find('primary'); + if ($filename) { + $f = $self->download($filename, 1, $filechksum, 1); + if ($f) { + $self->{handle}->add_rpmmd($f, undef, 0); + } + return undef if $self->{incomplete}; + } + ($filename, $filechksum) = $self->find('updateinfo'); + if ($filename) { + $f = $self->download($filename, 1, $filechksum, 1); + if ($f) { + $self->{handle}->add_updateinfoxml($f, 0); + } + } + $self->add_exts(); + $self->writecachedrepo(); + $self->{handle}->create_stubs(); + return 1; +} + +package Repo::susetags; + +our @ISA = ('Repo::generic'); + +sub find { + my ($self, $what) = @_; + + my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, $what, $solv::Dataiterator::SEARCH_STRING); + $di->prepend_keyname($solv::SUSETAGS_FILE); + for my $d (@$di) { + my $dp = $d->parentpos(); + my $chksum = $dp->lookup_checksum($solv::SUSETAGS_FILE_CHECKSUM); + return ($what, $chksum); + } + return (undef, undef); +} + + +sub add_ext { + my ($self, $repodata, $what, $ext) = @_; + my ($filename, $chksum) = $self->find($what); + return unless $filename; + my $handle = $repodata->new_handle(); + $repodata->set_str($handle, $solv::SUSETAGS_FILE_NAME, $filename); + $repodata->set_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum); + $self->add_ext_keys($ext, $repodata, $handle); + $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle); +} + +sub add_exts { + my ($self) = @_; + my $repodata = $self->{handle}->add_repodata(0); + my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, undef, 0); + $di->prepend_keyname($solv::SUSETAGS_FILE); + for my $d (@$di) { + my $filename = $d->str(); + next unless $filename && $filename =~ /^packages\.(..)(?:\..*)$/; + next if $1 eq 'en' || $1 eq 'gz'; + $self->add_ext($repodata, $filename, $1); + } + $repodata->internalize(); +} + +sub load_ext { + my ($self, $repodata) = @_; + my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME); + my $ext = substr($filename, 9, 2); + print("[$self->{alias}:$ext: "); + STDOUT->flush(); + if ($self->usecachedrepo($ext)) { + print "cached]\n"; + return 1; + } + print "fetching]\n"; + my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR); + my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; + my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::SUSETAGS_FILE_CHECKSUM); + my $f = $self->download("$descrdir/$filename", 1, $filechksum); + return 0 unless $f; + my $flags = $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES; + $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL'; + $self->{handle}->add_susetags($f, $defvendorid, $ext, $flags); + $self->writecachedrepo($ext, $repodata); + return 1; +} + +sub load { + my ($self, $pool) = @_; + return 1 if $self->Repo::generic::load($pool); + print "susetags repo '$self->{alias}': "; + STDOUT->flush(); + my $f = $self->download("content"); + if (!$f) { + print "no content file, skipped\n"; + $self->{handle}->free(1); + delete $self->{handle}; + return undef; + } + $self->{cookie} = $self->calc_cookie_fp($f); + if ($self->usecachedrepo(undef, 1)) { + print "cached\n"; + return 1; + } + $self->{handle}->add_content($f, 0); + print "fetching\n"; + my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR); + my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; + my ($filename, $filechksum) = $self->find('packages.gz'); + ($filename, $filechksum) = $self->find('packages') unless $filename; + if ($filename) { + $f = $self->download("$descrdir/$filename", 1, $filechksum, 1); + if ($f) { + $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::SUSETAGS_RECORD_SHARES); + ($filename, $filechksum) = $self->find('packages.en.gz'); + ($filename, $filechksum) = $self->find('packages.en') unless $filename; + if ($filename) { + $f = $self->download("$descrdir/$filename", 1, $filechksum, 1); + if ($f) { + $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::REPO_REUSE_REPODATA|$solv::Repo::REPO_EXTEND_SOLVABLES); + } + } + $self->{handle}->internalize(); + } + } + $self->add_exts(); + $self->writecachedrepo(); + $self->{handle}->create_stubs(); + return undef; +} + +sub packagespath { + my ($self) = @_; + return ($self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DATADIR) || 'suse') . '/'; +} + +package Repo::unknown; + +our @ISA = ('Repo::generic'); + +sub load { + my ($self) = @_; + print "unsupported repo '$self->{alias}': skipped\n"; + return 0; +} + +package Repo::system; + +our @ISA = ('Repo::generic'); + +sub load { + my ($self, $pool) = @_; + + $self->{handle} = $pool->add_repo($self->{alias}); + $self->{handle}->{appdata} = $self; + $pool->{installed} = $self->{handle}; + print "rpm database: "; + $self->{cookie} = $self->calc_cookie_file('/var/lib/rpm/Packages'); + if ($self->usecachedrepo()) { + print "cached\n"; + return 1; + } + print "reading\n"; + if (defined(&solv::Repo::add_products)) { + $self->{handle}->add_products("/etc/products.d", $solv::Repo::REPO_NO_INTERNALIZE); + } + my $f = solv::xfopen($self->cachepath()); + $self->{handle}->add_rpmdb_reffp($f, $solv::Repo::REPO_REUSE_REPODATA); + $self->writecachedrepo(); + return 1; +} + +package main; + +sub load_stub { + my ($repodata) = @_; + my $repo = $repodata->{repo}->{appdata}; + return $repo ? $repo->load_ext($repodata) : 0; +} + +die("Usage: p5solv COMMAND [ARGS]\n") unless @ARGV; +my $cmd = shift @ARGV; +my %cmdabbrev = ( 'ls' => 'list', 'in' => 'install', 'rm' => 'erase', + 've' => 'verify', 'se' => 'search' ); +$cmd = $cmdabbrev{$cmd} if $cmdabbrev{$cmd}; + +my %cmdactionmap = ( + 'install' => $solv::Job::SOLVER_INSTALL, + 'erase' => $solv::Job::SOLVER_ERASE, + 'up' => $solv::Job::SOLVER_UPDATE, + 'dup' => $solv::Job::SOLVER_DISTUPGRADE, + 'verify' => $solv::Job::SOLVER_VERIFY, + 'list' => 0, + 'info' => 0, +); + +my @repos; +my @reposdirs; +if (-d '/etc/zypp/repos.d') { + @reposdirs = ( '/etc/zypp/repos.d' ); +} else { + @reposdirs = ( '/etc/yum/repos.d' ); +} +for my $reposdir (@reposdirs) { + next unless -d $reposdir; + my $dir; + next unless opendir($dir, $reposdir); + for my $reponame (sort(grep {/\.repo$/} readdir($dir))) { + my $cfg = new Config::IniFiles('-file' => "$reposdir/$reponame"); + for my $alias ($cfg->Sections()) { + my $repoattr = {'alias' => $alias, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}; + for my $p ($cfg->Parameters($alias)) { + $repoattr->{$p} = $cfg->val($alias, $p); + } + my $repo; + if ($repoattr->{type} eq 'rpm-md') { + $repo = Repo::rpmmd->new($alias, 'repomd', $repoattr); + } elsif ($repoattr->{type} eq 'yast2') { + $repo = Repo::susetags->new($alias, 'susetags', $repoattr); + } else { + $repo = Repo::unknown->new($alias, 'unknown', $repoattr); + } + push @repos, $repo; + } + } +} + +my $pool = solv::Pool->new(); +$pool->setarch(); +$pool->set_loadcallback(\&load_stub); + +my $sysrepo = Repo::system->new('@System', 'system'); +$sysrepo->load($pool); +for my $repo (@repos) { + $repo->load($pool) if $repo->{enabled}; +} + +if ($cmd eq 'search') { + $pool->createwhatprovides(); + my $sel = $pool->Selection(); + my $di = $pool->Dataiterator($solv::SOLVABLE_NAME, $ARGV[0], $solv::Dataiterator::SEARCH_SUBSTRING | $solv::Dataiterator::SEARCH_NOCASE); + for my $d (@$di) { + $sel->add_raw($solv::Job::SOLVER_SOLVABLE, $d->{solvid}); + } + for my $s ($sel->solvables()) { + print "- ".$s->str()." [$s->{repo}->{name}]: ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n"; + } + exit(0); +} + +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) { + my $flags = $solv::Selection::SELECTION_NAME | $solv::Selection::SELECTION_PROVIDES | $solv::Selection::SELECTION_GLOB; + $flags |= $solv::Selection::SELECTION_CANON | $solv::Selection::SELECTION_DOTARCH | $solv::Selection::SELECTION_REL; + if ($arg =~ m!^/!) { + $flags |= $solv::Selection::SELECTION_FILELIST; + $flags |= $solv::Selection::SELECTION_INSTALLED_ONLY if $cmd eq 'erase'; + } + my $sel = $pool->select($arg, $flags); + if ($sel->isempty()) { + $sel = $pool->select($arg, $flags | $solv::Selection::SELECTION_NOCASE); + 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; + push @jobs, $sel->jobs($cmdactionmap{$cmd}); +} + +if (!@jobs && ($cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify')) { + my $sel = $pool->Selection_all(); + push @jobs, $sel->jobs($cmdactionmap{$cmd}); +} + +die("no package matched.\n") unless @jobs; + +if ($cmd eq 'list' || $cmd eq 'info') { + for my $job (@jobs) { + for my $s ($job->solvables()) { + if ($cmd eq 'info') { + printf "Name: %s\n", $s->str(); + printf "Repo: %s\n", $s->{repo}->{name}; + printf "Summary: %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY); + my $str = $s->lookup_str($solv::SOLVABLE_URL); + printf "Url: %s\n", $str if $str; + $str = $s->lookup_str($solv::SOLVABLE_LICENSE); + printf "License: %s\n", $str if $str; + printf "Description:\n%s\n", $s->lookup_str($solv::SOLVABLE_DESCRIPTION); + } else { + printf " - %s [%s]\n", $s->str(), $s->{repo}->{name}; + printf " %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY); + } + } + } + exit 0; +} + +# up magic, turn into install if nothing matches +for my $job (@jobs) { + $job->{how} ^= $solv::Job::SOLVER_UPDATE ^ $solv::Job::SOLVER_INSTALL if $cmd eq 'up' && $job->isemptyupdate(); +} + +my $solver = $pool->Solver(); +$solver->set_flag($solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1); +$solver->set_flag($solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if $cmd eq 'erase'; + +while (1) { + my @problems = $solver->solve(\@jobs); + last unless @problems; + for my $problem (@problems) { + print "Problem $problem->{id}/".@problems.":\n"; + print $problem->str()."\n"; + my @solutions = $problem->solutions(); + for my $solution (@solutions) { + print " Solution $solution->{id}:\n"; + for my $element ($solution->elements(1)) { + print " - ".$element->str()."\n"; + } + print "\n"; + } + my $sol; + while (1) { + print "Please choose a solution: "; + $sol = ; + chomp $sol; + last if $sol eq 's' || $sol eq 'q' || ($sol =~ /^\d+$/ && $sol >= 1 && $sol <= @solutions); + } + next if $sol eq 's'; + exit(1) if $sol eq 'q'; + my $solution = $solutions[$sol - 1]; + for my $element ($solution->elements()) { + my $newjob = $element->Job(); + if ($element->{type} == $solv::Solver::SOLVER_SOLUTION_JOB) { + $jobs[$element->{jobidx}] = $newjob; + } else { + push @jobs, $newjob if $newjob && !grep {$_ == $newjob} @jobs; + } + } + } +} + +my $trans = $solver->transaction(); +undef $solver; +if ($trans->isempty()) { + print "Nothing to do.\n"; + exit 0; +} + +print "\nTransaction summary:\n\n"; +for my $c ($trans->classify($solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES|$solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE)) { + if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ERASE) { + print "$c->{count} erased packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_INSTALL) { + print "$c->{count} installed packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_REINSTALLED) { + print "$c->{count} reinstalled packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) { + print "$c->{count} downgraded packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_CHANGED) { + print "$c->{count} changed packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED) { + print "$c->{count} upgraded packages:\n"; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE) { + printf "$c->{count} vendor changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr}; + } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE) { + printf "$c->{count} arch changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr}; + } else { + next; + } + for my $p ($c->solvables()) { + if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED || $c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) { + my $other = $trans->othersolvable($p); + printf " - %s -> %s\n", $p->str(), $other->str(); + } else { + printf " - %s\n", $p->str(); + } + } + print "\n"; +} +printf "install size change: %d K\n\n", $trans->calc_installsizechange(); + +while (1) { + print("OK to continue (y/n)? "); + my $yn = ; + chomp $yn; + last if $yn eq 'y'; + exit(1) if $yn eq 'n' || $yn eq 'q'; +} + +my @newpkgs = $trans->newsolvables(); +my %newpkgsfps; +if (@newpkgs) { + my $downloadsize = 0; + $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs; + printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize / 1024; + for my $p (@newpkgs) { + my $repo = $p->{repo}->{appdata}; + my ($location) = $p->lookup_location(); + next unless $location; + $location = $repo->packagespath() . $location; + my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM); + my $f = $repo->download($location, 0, $chksum); + die("\n$repo->{alias}: $location not found in repository\n") unless $f; + $newpkgsfps{$p->{id}} = $f; + print "."; + STDOUT->flush(); + } + print "\n"; +} + +print "Committing transaction:\n\n"; +$trans->order(); +for my $p ($trans->steps()) { + my $steptype = $trans->steptype($p, $solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY); + if ($steptype == $solv::Transaction::SOLVER_TRANSACTION_ERASE) { + print "erase ".$p->str()."\n"; + next unless $p->lookup_num($solv::RPM_RPMDBID); + my $evr = $p->{evr}; + $evr =~ s/^[0-9]+://; # strip epoch + system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "$p->{name}-$evr.$p->{arch}") && die("rpm failed: $?\n"); + } elsif ($steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) { + print "install ".$p->str()."\n"; + my $f = $newpkgsfps{$p->{id}}; + my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'; + $f->cloexec(0); + system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n"); + delete $newpkgsfps{$p->{id}}; + } +} + +exit 0; diff --git a/examples/pysolv b/examples/pysolv new file mode 100755 index 0000000..75067f2 --- /dev/null +++ b/examples/pysolv @@ -0,0 +1,961 @@ +#!/usr/bin/python + +# +# Copyright (c) 2011, Novell Inc. +# +# This program is licensed under the BSD license, read LICENSE.BSD +# for further information +# + +# pysolv a little software installer demoing the sat solver library/bindings + +# things it does: +# - understands globs for package names / dependencies +# - understands .arch suffix +# - repository data caching +# - on demand loading of secondary repository data +# - checksum verification +# - deltarpm support +# - installation of commandline packages +# +# things not yet ported: +# - gpg verification +# - file conflicts +# - fastestmirror implementation +# +# things available in the library but missing from pysolv: +# - vendor policy loading +# - soft locks file handling +# - multi version handling + +import sys +import os +import glob +import solv +import re +import tempfile +import time +import subprocess +import rpm +from stat import * +from iniparse import INIConfig +from optparse import OptionParser + +#import gc +#gc.set_debug(gc.DEBUG_LEAK) + +class repo_generic(dict): + def __init__(self, name, type, attribs = {}): + for k in attribs: + self[k] = attribs[k] + self.name = name + self.type = type + + def calc_cookie_file(self, filename): + chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256) + chksum.add("1.1") + chksum.add_stat(filename) + return chksum.raw() + + def calc_cookie_fp(self, fp): + chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256) + chksum.add("1.1"); + chksum.add_fp(fp) + return chksum.raw() + + def calc_cookie_ext(self, f, cookie): + chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256) + chksum.add("1.1"); + chksum.add(cookie) + chksum.add_fstat(f.fileno()) + return chksum.raw() + + def cachepath(self, ext = None): + path = re.sub(r'^\.', '_', self.name) + if ext: + path += "_" + ext + ".solvx" + else: + path += ".solv" + return "/var/cache/solv/" + re.sub(r'[/]', '_', path) + + def load(self, pool): + self.handle = pool.add_repo(self.name) + self.handle.appdata = self + self.handle.priority = 99 - self['priority'] + dorefresh = bool(int(self['autorefresh'])) + if dorefresh: + try: + st = os.stat(self.cachepath()) + if self['metadata_expire'] == -1 or time.time() - st[ST_MTIME] < self['metadata_expire']: + dorefresh = False + except OSError: + pass + self['cookie'] = '' + self['extcookie'] = '' + if not dorefresh and self.usecachedrepo(None): + print("repo: '%s': cached" % self.name) + return True + return False + + def load_ext(self, repodata): + return False + + def setfromurls(self, urls): + if not urls: + return + url = urls[0] + print("[using mirror %s]" % re.sub(r'^(.*?/...*?)/.*$', r'\1', url)) + self['baseurl'] = url + + def setfrommetalink(self, metalink): + f = self.download(metalink, False, None) + if not f: + return None + f = os.fdopen(f.dup(), 'r') + urls = [] + chksum = None + for l in f.readlines(): + l = l.strip() + m = re.match(r'^([0-9a-fA-F]{64})', l) + if m: + chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256, m.group(1)) + m = re.match(r'^(https?://.+)repodata/repomd.xml', l) + if m: + urls.append(m.group(1)) + if not urls: + chksum = None # in case the metalink is about a different file + f.close() + self.setfromurls(urls) + return chksum + + def setfrommirrorlist(self, mirrorlist): + f = self.download(mirrorlist, False, None) + if not f: + return + f = os.fdopen(f.dup(), 'r') + urls = [] + for l in f.readline(): + l = l.strip() + if l[0:6] == 'http://' or l[0:7] == 'https://': + urls.append(l) + self.setfromurls(urls) + f.close() + + def download(self, file, uncompress, chksum, markincomplete=False): + url = None + if 'baseurl' not in self: + if 'metalink' in self: + if file != self['metalink']: + metalinkchksum = self.setfrommetalink(self['metalink']) + if file == 'repodata/repomd.xml' and metalinkchksum and not chksum: + chksum = metalinkchksum + else: + url = file + elif 'mirrorlist' in self: + if file != self['mirrorlist']: + self.setfrommirrorlist(self['mirrorlist']) + else: + url = file + if not url: + if 'baseurl' not in self: + print("%s: no baseurl" % self.name) + return None + url = re.sub(r'/$', '', self['baseurl']) + '/' + file + f = tempfile.TemporaryFile() + st = subprocess.call(['curl', '-f', '-s', '-L', url], stdout=f.fileno()) + if os.lseek(f.fileno(), 0, os.SEEK_CUR) == 0 and (st == 0 or not chksum): + return None + os.lseek(f.fileno(), 0, os.SEEK_SET) + if st: + print("%s: download error %d" % (file, st)) + if markincomplete: + self['incomplete'] = True + return None + if chksum: + fchksum = solv.Chksum(chksum.type) + if not fchksum: + print("%s: unknown checksum type" % file) + if markincomplete: + self['incomplete'] = True + return None + fchksum.add_fd(f.fileno()) + if fchksum != chksum: + print("%s: checksum mismatch" % file) + if markincomplete: + self['incomplete'] = True + return None + if uncompress: + return solv.xfopen_fd(file, f.fileno()) + return solv.xfopen_fd(None, f.fileno()) + + def usecachedrepo(self, ext, mark=False): + try: + repopath = self.cachepath(ext) + f = open(repopath, 'rb') + f.seek(-32, os.SEEK_END) + fcookie = f.read(32) + if len(fcookie) != 32: + return False + if not ext: + cookie = self['cookie'] + else: + cookie = self['extcookie'] + if cookie and fcookie != cookie: + return False + if self.type != 'system' and not ext: + f.seek(-32 * 2, os.SEEK_END) + fextcookie = f.read(32) + if len(fextcookie) != 32: + return False + f.seek(0) + f = solv.xfopen_fd('', f.fileno()) + flags = 0 + if ext: + flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES + if ext != 'DL': + flags |= solv.Repo.REPO_LOCALPOOL + if not self.handle.add_solv(f, flags): + return False + if self.type != 'system' and not ext: + self['cookie'] = fcookie + self['extcookie'] = fextcookie + if mark: + # no futimes in python? + try: + os.utime(repopath, None) + except Exception: + pass + except IOError: + return False + return True + + def writecachedrepo(self, ext, repodata=None): + if 'incomplete' in self: + return + tmpname = None + try: + if not os.path.isdir("/var/cache/solv"): + os.mkdir("/var/cache/solv", 0o755) + (fd, tmpname) = tempfile.mkstemp(prefix='.newsolv-', dir='/var/cache/solv') + os.fchmod(fd, 0o444) + f = os.fdopen(fd, 'wb+') + f = solv.xfopen_fd(None, f.fileno()) + if not repodata: + self.handle.write(f) + elif ext: + repodata.write(f) + else: # rewrite_repos case, do not write stubs + self.handle.write_first_repodata(f) + f.flush() + if self.type != 'system' and not ext: + if not self['extcookie']: + self['extcookie'] = self.calc_cookie_ext(f, self['cookie']) + f.write(self['extcookie']) + if not ext: + f.write(self['cookie']) + else: + f.write(self['extcookie']) + f.close + if self.handle.iscontiguous(): + # switch to saved repo to activate paging and save memory + nf = solv.xfopen(tmpname) + if not ext: + # main repo + self.handle.empty() + flags = solv.Repo.SOLV_ADD_NO_STUBS + if repodata: + flags = 0 # rewrite repos case, recreate stubs + if not self.handle.add_solv(nf, flags): + sys.exit("internal error, cannot reload solv file") + else: + # extension repodata + # need to extend to repo boundaries, as this is how + # repodata.write() has written the data + repodata.extend_to_repo() + flags = solv.Repo.REPO_EXTEND_SOLVABLES + if ext != 'DL': + flags |= solv.Repo.REPO_LOCALPOOL + repodata.add_solv(nf, flags) + os.rename(tmpname, self.cachepath(ext)) + except (OSError, IOError): + if tmpname: + os.unlink(tmpname) + + def updateaddedprovides(self, addedprovides): + if 'incomplete' in self: + return + if not hasattr(self, 'handle'): + return + if self.handle.isempty(): + return + # make sure there's just one real repodata with extensions + repodata = self.handle.first_repodata() + if not repodata: + return + oldaddedprovides = repodata.lookup_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES) + if not set(addedprovides) <= set(oldaddedprovides): + for id in addedprovides: + repodata.add_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES, id) + repodata.internalize() + self.writecachedrepo(None, repodata) + + def packagespath(self): + return '' + + def add_ext_keys(self, ext, repodata, handle): + if ext == 'DL': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY) + elif ext == 'DU': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY) + elif ext == 'FL': + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY) + else: + for langtag, langtagtype in [ + (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR), + (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID) + ]: + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1)) + repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype) + + +class repo_repomd(repo_generic): + def load(self, pool): + if super(repo_repomd, self).load(pool): + return True + sys.stdout.write("rpmmd repo '%s': " % self.name) + sys.stdout.flush() + f = self.download("repodata/repomd.xml", False, None, None) + if not f: + print("no repomd.xml file, skipped") + self.handle.free(True) + del self.handle + return False + self['cookie'] = self.calc_cookie_fp(f) + if self.usecachedrepo(None, True): + print("cached") + return True + self.handle.add_repomdxml(f, 0) + print("fetching") + (filename, filechksum) = self.find('primary') + if filename: + f = self.download(filename, True, filechksum, True) + if f: + self.handle.add_rpmmd(f, None, 0) + if 'incomplete' in self: + return False # hopeless, need good primary + (filename, filechksum) = self.find('updateinfo') + if filename: + f = self.download(filename, True, filechksum, True) + if f: + self.handle.add_updateinfoxml(f, 0) + self.add_exts() + self.writecachedrepo(None) + # must be called after writing the repo + self.handle.create_stubs() + return True + + def find(self, what): + di = self.handle.Dataiterator_meta(solv.REPOSITORY_REPOMD_TYPE, what, solv.Dataiterator.SEARCH_STRING) + di.prepend_keyname(solv.REPOSITORY_REPOMD) + for d in di: + dp = d.parentpos() + filename = dp.lookup_str(solv.REPOSITORY_REPOMD_LOCATION) + chksum = dp.lookup_checksum(solv.REPOSITORY_REPOMD_CHECKSUM) + if filename and not chksum: + print("no %s file checksum!" % filename) + filename = None + chksum = None + if filename: + return (filename, chksum) + return (None, None) + + def add_ext(self, repodata, what, ext): + filename, chksum = self.find(what) + if not filename and what == 'deltainfo': + filename, chksum = self.find('prestodelta') + if not filename: + return + handle = repodata.new_handle() + repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what) + repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename) + repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum) + self.add_ext_keys(ext, repodata, handle) + repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle) + + 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() + + def load_ext(self, repodata): + repomdtype = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE) + if repomdtype == 'filelists': + ext = 'FL' + elif repomdtype == 'deltainfo': + ext = 'DL' + else: + return False + sys.stdout.write("[%s:%s: " % (self.name, ext)) + if self.usecachedrepo(ext): + sys.stdout.write("cached]\n") + sys.stdout.flush() + return True + sys.stdout.write("fetching]\n") + sys.stdout.flush() + filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION) + filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM) + f = self.download(filename, True, filechksum) + if not f: + return False + if ext == 'FL': + self.handle.add_rpmmd(f, 'FL', solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES|solv.Repo.REPO_LOCALPOOL) + elif ext == 'DL': + self.handle.add_deltainfoxml(f, solv.Repo.REPO_USE_LOADING) + self.writecachedrepo(ext, repodata) + return True + +class repo_susetags(repo_generic): + def load(self, pool): + if super(repo_susetags, self).load(pool): + return True + sys.stdout.write("susetags repo '%s': " % self.name) + sys.stdout.flush() + f = self.download("content", False, None, None) + if not f: + print("no content file, skipped") + self.handle.free(True) + del self.handle + return False + self['cookie'] = self.calc_cookie_fp(f) + if self.usecachedrepo(None, True): + print("cached") + return True + self.handle.add_content(f, 0) + print("fetching") + defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR) + descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR) + if not descrdir: + descrdir = "suse/setup/descr" + (filename, filechksum) = self.find('packages.gz') + if not filename: + (filename, filechksum) = self.find('packages') + if filename: + f = self.download(descrdir + '/' + filename, True, filechksum, True) + if f: + self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.SUSETAGS_RECORD_SHARES) + (filename, filechksum) = self.find('packages.en.gz') + if not filename: + (filename, filechksum) = self.find('packages.en') + if filename: + f = self.download(descrdir + '/' + filename, True, filechksum, True) + if f: + self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_EXTEND_SOLVABLES) + self.handle.internalize() + self.add_exts() + self.writecachedrepo(None) + # must be called after writing the repo + self.handle.create_stubs() + return True + + def find(self, what): + di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, what, solv.Dataiterator.SEARCH_STRING) + di.prepend_keyname(solv.SUSETAGS_FILE) + for d in di: + dp = d.parentpos() + chksum = dp.lookup_checksum(solv.SUSETAGS_FILE_CHECKSUM) + return (what, chksum) + return (None, None) + + def add_ext(self, repodata, what, ext): + (filename, chksum) = self.find(what) + if not filename: + return + handle = repodata.new_handle() + repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename) + if chksum: + repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum) + self.add_ext_keys(ext, repodata, handle) + repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle) + + def add_exts(self): + repodata = self.handle.add_repodata(0) + di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, None, 0) + di.prepend_keyname(solv.SUSETAGS_FILE) + for d in di: + filename = d.str + if not filename: + continue + if filename[0:9] != "packages.": + continue + if len(filename) == 11 and filename != "packages.gz": + ext = filename[9:11] + elif filename[11:12] == ".": + ext = filename[9:11] + else: + continue + if ext == "en": + continue + self.add_ext(repodata, filename, ext) + repodata.internalize() + + def load_ext(self, repodata): + filename = repodata.lookup_str(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME) + ext = filename[9:11] + sys.stdout.write("[%s:%s: " % (self.name, ext)) + if self.usecachedrepo(ext): + sys.stdout.write("cached]\n") + sys.stdout.flush() + return True + sys.stdout.write("fetching]\n") + sys.stdout.flush() + defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR) + descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR) + if not descrdir: + descrdir = "suse/setup/descr" + filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.SUSETAGS_FILE_CHECKSUM) + f = self.download(descrdir + '/' + filename, True, filechksum) + if not f: + return False + flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES + if ext != 'DL': + flags |= solv.Repo.REPO_LOCALPOOL + self.handle.add_susetags(f, defvendorid, ext, flags) + self.writecachedrepo(ext, repodata) + return True + + def packagespath(self): + datadir = repo.handle.meta.lookup_str(solv.SUSETAGS_DATADIR) + if not datadir: + datadir = 'suse' + return datadir + '/' + +class repo_unknown(repo_generic): + def load(self, pool): + print("unsupported repo '%s': skipped" % self.name) + return False + +class repo_system(repo_generic): + def load(self, pool): + self.handle = pool.add_repo(self.name) + self.handle.appdata = self + pool.installed = self.handle + sys.stdout.write("rpm database: ") + self['cookie'] = self.calc_cookie_file("/var/lib/rpm/Packages") + if self.usecachedrepo(None): + print("cached") + return True + print("reading") + if hasattr(self.handle.__class__, 'add_products'): + self.handle.add_products("/etc/products.d", solv.Repo.REPO_NO_INTERNALIZE) + f = solv.xfopen(self.cachepath()) + self.handle.add_rpmdb_reffp(f, solv.Repo.REPO_REUSE_REPODATA) + self.writecachedrepo(None) + return True + +class repo_cmdline(repo_generic): + def load(self, pool): + self.handle = pool.add_repo(self.name) + self.handle.appdata = self + return True + +def load_stub(repodata): + repo = repodata.repo.appdata + if repo: + return repo.load_ext(repodata) + return False + + +parser = OptionParser(usage="usage: solv.py [options] COMMAND") +parser.add_option('-r', '--repo', action="append", type="string", dest="repos", help="limit to specified repositories") +parser.add_option('--best', action="store_true", dest="best", help="force installation/update to best packages") +parser.add_option('--clean', action="store_true", dest="clean", help="delete no longer needed packages") +(options, args) = parser.parse_args() +if not args: + parser.print_help(sys.stderr) + sys.exit(1) + +cmd = args[0] +args = args[1:] + +cmdabbrev = {'ls': 'list', 'in': 'install', 'rm': 'erase', 've': 'verify', 'se': 'search'} +if cmd in cmdabbrev: + cmd = cmdabbrev[cmd] + +cmdactionmap = { + 'install': solv.Job.SOLVER_INSTALL, + 'erase': solv.Job.SOLVER_ERASE, + 'up': solv.Job.SOLVER_UPDATE, + 'dup': solv.Job.SOLVER_DISTUPGRADE, + 'verify': solv.Job.SOLVER_VERIFY, + 'list': 0, + 'info': 0 +} + +# read all repo configs +repos = [] +reposdirs = [] +if os.path.isdir("/etc/zypp/repos.d"): + reposdirs = [ "/etc/zypp/repos.d" ] +else: + reposdirs = [ "/etc/yum/repos.d" ] + +for reposdir in reposdirs: + if not os.path.isdir(reposdir): + continue + for reponame in sorted(glob.glob('%s/*.repo' % reposdir)): + cfg = INIConfig(open(reponame)) + for alias in cfg: + repoattr = {'enabled': 0, 'priority': 99, 'autorefresh': 1, 'type': 'rpm-md', 'metadata_expire': 900} + for k in cfg[alias]: + repoattr[k] = cfg[alias][k] + if 'mirrorlist' in repoattr and 'metalink' not in repoattr: + if repoattr['mirrorlist'].find('/metalink'): + repoattr['metalink'] = repoattr['mirrorlist'] + del repoattr['mirrorlist'] + if repoattr['type'] == 'rpm-md': + repo = repo_repomd(alias, 'repomd', repoattr) + elif repoattr['type'] == 'yast2': + repo = repo_susetags(alias, 'susetags', repoattr) + else: + repo = repo_unknown(alias, 'unknown', repoattr) + repos.append(repo) + +pool = solv.Pool() +pool.setarch() +pool.set_loadcallback(load_stub) + +# now load all enabled repos into the pool +sysrepo = repo_system('@System', 'system') +sysrepo.load(pool) +for repo in repos: + if int(repo['enabled']): + repo.load(pool) + +repofilter = None +if options.repos: + for reponame in options.repos: + mrepos = [ repo for repo in repos if repo.name == reponame ] + if not mrepos: + print("no repository matches '%s'" % reponame) + sys.exit(1) + repo = mrepos[0] + if hasattr(repo, 'handle'): + if not repofilter: + repofilter = pool.Selection() + repofilter.add(repo.handle.Selection(solv.Job.SOLVER_SETVENDOR)) + +if cmd == 'search': + pool.createwhatprovides() + sel = pool.Selection() + di = pool.Dataiterator(solv.SOLVABLE_NAME, args[0], solv.Dataiterator.SEARCH_SUBSTRING|solv.Dataiterator.SEARCH_NOCASE) + for d in di: + sel.add_raw(solv.Job.SOLVER_SOLVABLE, d.solvid) + if repofilter: + sel.filter(repofilter) + for s in sel.solvables(): + print(" - %s [%s]: %s" % (s, s.repo.name, s.lookup_str(solv.SOLVABLE_SUMMARY))) + sys.exit(0) + +if cmd not in cmdactionmap: + print("unknown command %s" % cmd) + sys.exit(1) + +cmdlinerepo = None +if cmd == 'list' or cmd == 'info' or cmd == 'install': + for arg in args: + if arg.endswith(".rpm") and os.access(arg, os.R_OK): + if not cmdlinerepo: + cmdlinerepo = repo_cmdline('@commandline', 'cmdline') + cmdlinerepo.load(pool) + cmdlinerepo['packages'] = {} + s = cmdlinerepo.handle.add_rpm(arg, solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_NO_INTERNALIZE) + if not s: + print(pool.errstr) + sys.exit(1) + cmdlinerepo['packages'][arg] = s + if cmdlinerepo: + cmdlinerepo.handle.internalize() + +addedprovides = pool.addfileprovides_queue() +if addedprovides: + sysrepo.updateaddedprovides(addedprovides) + for repo in repos: + repo.updateaddedprovides(addedprovides) + +pool.createwhatprovides() + +# convert arguments into jobs +jobs = [] +for arg in args: + if cmdlinerepo and arg in cmdlinerepo['packages']: + jobs.append(pool.Job(solv.Job.SOLVER_SOLVABLE, cmdlinerepo['packages'][arg].id)) + else: + flags = solv.Selection.SELECTION_NAME|solv.Selection.SELECTION_PROVIDES|solv.Selection.SELECTION_GLOB + flags |= solv.Selection.SELECTION_CANON|solv.Selection.SELECTION_DOTARCH|solv.Selection.SELECTION_REL + if len(arg) and arg[0] == '/': + flags |= solv.Selection.SELECTION_FILELIST + if cmd == 'erase': + flags |= solv.Selection.SELECTION_INSTALLED_ONLY + sel = pool.select(arg, flags) + if repofilter: + sel.filter(repofilter) + if sel.isempty(): + sel = pool.select(arg, flags | solv.Selection.SELECTION_NOCASE) + if repofilter: + sel.filter(repofilter) + if not sel.isempty(): + print("[ignoring case for '%s']" % arg) + if sel.isempty(): + print("nothing matches '%s'" % arg) + sys.exit(1) + if sel.flags & solv.Selection.SELECTION_FILELIST: + print("[using file list match for '%s']" % arg) + if sel.flags & solv.Selection.SELECTION_PROVIDES: + print("[using capability match for '%s']" % arg) + jobs += sel.jobs(cmdactionmap[cmd]) + +if not jobs and (cmd == 'up' or cmd == 'dup' or cmd == 'verify' or repofilter): + sel = pool.Selection_all() + if repofilter: + sel.filter(repofilter) + jobs += sel.jobs(cmdactionmap[cmd]) + +if not jobs: + print("no package matched.") + sys.exit(1) + +if cmd == 'list' or cmd == 'info': + for job in jobs: + for s in job.solvables(): + if cmd == 'info': + print("Name: %s" % s) + print("Repo: %s" % s.repo) + print("Summary: %s" % s.lookup_str(solv.SOLVABLE_SUMMARY)) + str = s.lookup_str(solv.SOLVABLE_URL) + if str: + print("Url: %s" % str) + str = s.lookup_str(solv.SOLVABLE_LICENSE) + if str: + print("License: %s" % str) + print("Description:\n%s" % s.lookup_str(solv.SOLVABLE_DESCRIPTION)) + print('') + else: + print(" - %s [%s]" % (s, s.repo)) + print(" %s" % s.lookup_str(solv.SOLVABLE_SUMMARY)) + sys.exit(0) + +# up magic: use install instead of update if no installed package matches +for job in jobs: + if cmd == 'up' and job.isemptyupdate(): + job.how ^= solv.Job.SOLVER_UPDATE ^ solv.Job.SOLVER_INSTALL + if options.best: + job.how |= solv.Job.SOLVER_FORCEBEST + if options.clean: + job.how |= solv.Job.SOLVER_CLEANDEPS + +#pool.set_debuglevel(2) +solver = pool.Solver() +solver.set_flag(solv.Solver.SOLVER_FLAG_SPLITPROVIDES, 1); +if cmd == 'erase': + solver.set_flag(solv.Solver.SOLVER_FLAG_ALLOW_UNINSTALL, 1); + +while True: + problems = solver.solve(jobs) + if not problems: + break + for problem in problems: + print("Problem %d/%d:" % (problem.id, len(problems))) + print(problem) + solutions = problem.solutions() + for solution in solutions: + print(" Solution %d:" % solution.id) + elements = solution.elements(True) + for element in elements: + print(" - %s" % element.str()) + print('') + sol = '' + while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))): + sys.stdout.write("Please choose a solution: ") + sys.stdout.flush() + sol = sys.stdin.readline().strip() + if sol == 's': + continue # skip problem + if sol == 'q': + sys.exit(1) + solution = solutions[int(sol) - 1] + for element in solution.elements(): + newjob = element.Job() + if element.type == solv.Solver.SOLVER_SOLUTION_JOB: + jobs[element.jobidx] = newjob + else: + if newjob and newjob not in jobs: + jobs.append(newjob) + +# no problems, show transaction +trans = solver.transaction() +del solver +if trans.isempty(): + print("Nothing to do.") + sys.exit(0) +print('') +print("Transaction summary:") +print('') +for cl in trans.classify(solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | solv.Transaction.SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE): + if cl.type == solv.Transaction.SOLVER_TRANSACTION_ERASE: + print("%d erased packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_INSTALL: + print("%d installed packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_REINSTALLED: + print("%d reinstalled packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED: + print("%d downgraded packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_CHANGED: + print("%d changed packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED: + print("%d upgraded packages:" % cl.count) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_VENDORCHANGE: + print("%d vendor changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr)) + elif cl.type == solv.Transaction.SOLVER_TRANSACTION_ARCHCHANGE: + print("%d arch changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr)) + else: + continue + for p in cl.solvables(): + if cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED or cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED: + op = trans.othersolvable(p) + print(" - %s -> %s" % (p, op)) + else: + print(" - %s" % p) + print('') +print("install size change: %d K" % trans.calc_installsizechange()) +print('') + +while True: + sys.stdout.write("OK to continue (y/n)? ") + sys.stdout.flush() + yn = sys.stdin.readline().strip() + if yn == 'y': break + if yn == 'n' or yn == 'q': sys.exit(1) +newpkgs = trans.newsolvables() +newpkgsfp = {} +if newpkgs: + downloadsize = 0 + for p in newpkgs: + downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE) + print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize / 1024)) + for p in newpkgs: + repo = p.repo.appdata + location, medianr = p.lookup_location() + if not location: + continue + if repo.type == 'commandline': + f = solv.xfopen(location) + if not f: + sys.exit("\n%s: %s not found" % location) + newpkgsfp[p.id] = f + continue + if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK): + pname = p.name + di = p.repo.Dataiterator_meta(solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING) + di.prepend_keyname(solv.REPOSITORY_DELTAINFO) + for d in di: + dp = d.parentpos() + if dp.lookup_id(solv.DELTA_PACKAGE_EVR) != p.evrid or dp.lookup_id(solv.DELTA_PACKAGE_ARCH) != p.archid: + continue + baseevrid = dp.lookup_id(solv.DELTA_BASE_EVR) + candidate = None + for installedp in pool.whatprovides(p.nameid): + if installedp.isinstalled() and installedp.nameid == p.nameid and installedp.archid == p.archid and installedp.evrid == baseevrid: + candidate = installedp + if not candidate: + continue + seq = dp.lookup_deltaseq() + st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, '-c', '-s', seq]) + if st: + continue + chksum = dp.lookup_checksum(solv.DELTA_CHECKSUM) + if not chksum: + continue + dloc, dmedianr = dp.lookup_deltalocation() + dloc = repo.packagespath() + dloc + f = repo.download(dloc, False, chksum) + if not f: + continue + nf = tempfile.TemporaryFile() + nf = os.dup(nf.fileno()) # get rid of CLOEXEC + f.cloexec(0) + st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf]) + if st: + os.close(nf) + continue + os.lseek(nf, 0, os.SEEK_SET) + newpkgsfp[p.id] = solv.xfopen_fd("", nf) + os.close(nf) + break + if p.id in newpkgsfp: + sys.stdout.write("d") + sys.stdout.flush() + continue + + chksum = p.lookup_checksum(solv.SOLVABLE_CHECKSUM) + location = repo.packagespath() + location + f = repo.download(location, False, chksum) + if not f: + sys.exit("\n%s: %s not found in repository" % (repo.name, location)) + newpkgsfp[p.id] = f + sys.stdout.write(".") + sys.stdout.flush() + print('') +print("Committing transaction:") +print('') +ts = rpm.TransactionSet('/') +ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES) +erasenamehelper = {} +for p in trans.steps(): + type = trans.steptype(p, solv.Transaction.SOLVER_TRANSACTION_RPM_ONLY) + if type == solv.Transaction.SOLVER_TRANSACTION_ERASE: + rpmdbid = p.lookup_num(solv.RPM_RPMDBID) + erasenamehelper[p.name] = p + if not rpmdbid: + sys.exit("\ninternal error: installed package %s has no rpmdbid\n" % p) + ts.addErase(rpmdbid) + elif type == solv.Transaction.SOLVER_TRANSACTION_INSTALL: + f = newpkgsfp[p.id] + h = ts.hdrFromFdno(f.fileno()) + os.lseek(f.fileno(), 0, os.SEEK_SET) + ts.addInstall(h, p, 'u') + elif type == solv.Transaction.SOLVER_TRANSACTION_MULTIINSTALL: + f = newpkgsfp[p.id] + h = ts.hdrFromFdno(f.fileno()) + os.lseek(f.fileno(), 0, os.SEEK_SET) + ts.addInstall(h, p, 'i') +checkproblems = ts.check() +if checkproblems: + print(checkproblems) + sys.exit("Sorry.") +ts.order() +def runCallback(reason, amount, total, p, d): + if reason == rpm.RPMCALLBACK_INST_OPEN_FILE: + return newpkgsfp[p.id].fileno() + if reason == rpm.RPMCALLBACK_INST_START: + print("install %s" % p) + if reason == rpm.RPMCALLBACK_UNINST_START: + # argh, p is just the name of the package + if p in erasenamehelper: + p = erasenamehelper[p] + print("erase %s" % p) +runproblems = ts.run(runCallback, '') +if runproblems: + print(runproblems) + sys.exit(1) +sys.exit(0) + +# vim: sw=4 et diff --git a/examples/rbsolv b/examples/rbsolv new file mode 100755 index 0000000..87f0d16 --- /dev/null +++ b/examples/rbsolv @@ -0,0 +1,763 @@ +#!/usr/bin/ruby + +require 'solv' +require 'rubygems' +require 'inifile' +require 'tempfile' + +class Repo_generic + def initialize(name, type, attribs = {}) + @name = name + @type = type + @attribs = attribs.dup + @incomplete = false + end + + def enabled? + return @attribs['enabled'].to_i != 0 + end + + def autorefresh? + return @attribs['autorefresh'].to_i != 0 + end + + def id + return @handle ? @handle.id : 0 + end + + def calc_cookie_fp(f) + chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256) + chksum.add("1.1") + chksum.add_fp(f) + return chksum.raw + end + + def calc_cookie_file(filename) + chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256) + chksum.add("1.1") + chksum.add_stat(filename) + return chksum.raw + end + + def calc_cookie_ext(f, cookie) + chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256) + chksum.add("1.1") + chksum.add(cookie) + chksum.add_fstat(f.fileno) + return chksum.raw() + end + + def cachepath(ext = nil) + path = @name.sub(/^\./, '_') + path += ext ? "_#{ext}.solvx" : '.solv' + return '/var/cache/solv/' + path.gsub(/\//, '_') + end + + def load(pool) + @handle = pool.add_repo(@name) + @handle.appdata = self + @handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority'] + dorefresh = autorefresh? + if dorefresh + begin + s = File.stat(cachepath) + dorefresh = false if s && (@attribs['metadata_expire'].to_i == -1 || Time.now - s.mtime < @attribs['metadata_expire'].to_i) + rescue SystemCallError + end + end + @cookie = nil + @extcookie = nil + if !dorefresh && usecachedrepo(nil) + puts "repo: '#{@name}' cached" + return true + end + return false + end + + def load_ext(repodata) + return false + end + + def download(file, uncompress, chksum, markincomplete = false) + url = @attribs['baseurl'] + if !url + puts "%{@name}: no baseurl" + return nil + end + url = url.sub(/\/$/, '') + "/#{file}" + f = Tempfile.new('rbsolv') + f.unlink + st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url) + return nil if f.stat.size == 0 && (st || !chksum) + if !st + puts "#{file}: download error #{$? >> 8}" + @incomplete = true if markincomplete + return nil + end + if chksum + fchksum = Solv::Chksum.new(chksum.type) + fchksum.add_fd(f.fileno) + if !fchksum == chksum + puts "#{file}: checksum error" + @incomplete = true if markincomplete + return nil + end + end + rf = nil + if uncompress + rf = Solv::xfopen_fd(file, f.fileno) + else + rf = Solv::xfopen_fd('', f.fileno) + end + f.close + return rf + end + + def usecachedrepo(ext, mark = false) + cookie = ext ? @extcookie : @cookie + begin + repopath = cachepath(ext) + f = File.new(repopath, "r") + f.sysseek(-32, IO::SEEK_END) + fcookie = f.sysread(32) + return false if fcookie.length != 32 + return false if cookie && fcookie != cookie + if !ext && @type != 'system' + f.sysseek(-32 * 2, IO::SEEK_END) + fextcookie = f.sysread(32) + return false if fextcookie.length != 32 + end + f.sysseek(0, IO::SEEK_SET) + nf = Solv::xfopen_fd('', f.fileno) + f.close + flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0 + flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL' + if ! @handle.add_solv(nf, flags) + nf.close + return false + end + nf.close() + @cookie = fcookie unless ext + @extcookie = fextcookie if !ext && @type != 'system' + now = Time.now + begin + File::utime(now, now, repopath) if mark + rescue SystemCallError + end + return true + rescue SystemCallError + return false + end + return true + end + + def writecachedrepo(ext, repodata = nil) + return if @incomplete + begin + Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv") + f = Tempfile.new('.newsolv-', '/var/cache/solv') + f.chmod(0444) + sf = Solv::xfopen_fd('', f.fileno) + if !repodata + @handle.write(sf) + elsif ext + repodata.write(sf) + else + @handle.write_first_repodata(sf) + end + sf.close + f.sysseek(0, IO::SEEK_END) + if @type != 'system' && !ext + @extcookie = calc_cookie_ext(f, @cookie) unless @extcookie + f.syswrite(@extcookie) + end + f.syswrite(ext ? @extcookie : @cookie) + f.close + if @handle.iscontiguous? + sf = Solv::xfopen(f.path) + if sf + if !ext + @handle.empty() + abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, repodata ? 0 : Solv::Repo::SOLV_ADD_NO_STUBS) + else + repodata.extend_to_repo() + flags = Solv::Repo::REPO_EXTEND_SOLVABLES + flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL' + repodata.add_solv(sf, flags) + end + sf.close + end + end + File.rename(f.path, cachepath(ext)) + f.unlink + return true + rescue SystemCallError + return false + end + end + + def updateaddedprovides(addedprovides) + return if @incomplete + return unless @handle && !@handle.isempty? + repodata = @handle.first_repodata() + return unless repodata + oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES) + return if (oldaddedprovides | addedprovides) == oldaddedprovides + for id in addedprovides + repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id) + end + repodata.internalize() + writecachedrepo(nil, repodata) + end + + def packagespath() + return '' + end + + @@langtags = { + Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR, + Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID, + } + + def add_ext_keys(ext, repodata, h) + if ext == 'DL' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY) + elsif ext == 'DU' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY) + elsif ext == 'FL' + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY) + else + @@langtags.sort.each do |langid, langtype| + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true)) + repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype) + end + end + end +end + +class Repo_rpmmd < Repo_generic + + def find(what) + di = @handle.Dataiterator_meta(Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING) + di.prepend_keyname(Solv::REPOSITORY_REPOMD) + for d in di + dp = d.parentpos() + filename = dp.lookup_str(Solv::REPOSITORY_REPOMD_LOCATION) + next unless filename + checksum = dp.lookup_checksum(Solv::REPOSITORY_REPOMD_CHECKSUM) + if !checksum + puts "no #{filename} checksum!" + return nil, nil + end + return filename, checksum + end + return nil, nil + end + + def load(pool) + return true if super(pool) + print "rpmmd repo '#{@name}: " + f = download("repodata/repomd.xml", false, nil, nil) + if !f + puts "no repomd.xml file, skipped" + @handle.free(true) + @handle = nil + return false + end + @cookie = calc_cookie_fp(f) + if usecachedrepo(nil, true) + puts "cached" + f.close + return true + end + @handle.add_repomdxml(f, 0) + f.close + puts "fetching" + filename, filechksum = find('primary') + if filename + f = download(filename, true, filechksum, true) + if f + @handle.add_rpmmd(f, nil, 0) + f.close + end + return false if @incomplete + end + filename, filechksum = find('updateinfo') + if filename + f = download(filename, true, filechksum, true) + if f + @handle.add_updateinfoxml(f, 0) + f.close + end + end + add_exts() + writecachedrepo(nil) + @handle.create_stubs() + return true + end + + def add_ext(repodata, what, ext) + filename, filechksum = find(what) + filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo' + return unless filename + h = repodata.new_handle() + repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what) + repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename) + repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum) + add_ext_keys(ext, repodata, h) + repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h) + end + + def add_exts + repodata = @handle.add_repodata(0) + repodata.extend_to_repo() + add_ext(repodata, 'deltainfo', 'DL') + add_ext(repodata, 'filelists', 'FL') + repodata.internalize() + end + + def load_ext(repodata) + repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE) + if repomdtype == 'filelists' + ext = 'FL' + elsif repomdtype == 'deltainfo' + ext = 'DL' + else + return false + end + print "[#{@name}:#{ext}: " + STDOUT.flush + if usecachedrepo(ext) + puts "cached]\n" + return true + end + puts "fetching]\n" + filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION) + filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM) + f = download(filename, true, filechksum) + return false unless f + if ext == 'FL' + @handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES|Solv::Repo::REPO_LOCALPOOL) + elsif ext == 'DL' + @handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING) + end + f.close + writecachedrepo(ext, repodata) + return true + end + +end + +class Repo_susetags < Repo_generic + + def find(what) + di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING) + di.prepend_keyname(Solv::SUSETAGS_FILE) + for d in di + dp = d.parentpos() + checksum = dp.lookup_checksum(Solv::SUSETAGS_FILE_CHECKSUM) + return what, checksum + end + return nil, nil + end + + def load(pool) + return true if super(pool) + print "susetags repo '#{@name}: " + f = download("content", false, nil, nil) + if !f + puts "no content file, skipped" + @handle.free(true) + @handle = nil + return false + end + @cookie = calc_cookie_fp(f) + if usecachedrepo(nil, true) + puts "cached" + f.close + return true + end + @handle.add_content(f, 0) + f.close + puts "fetching" + defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR) + descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR) + descrdir = "suse/setup/descr" unless descrdir + (filename, filechksum) = find('packages.gz') + (filename, filechksum) = find('packages') unless filename + if filename + f = download("#{descrdir}/#{filename}", true, filechksum, true) + if f + @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES) + f.close + (filename, filechksum) = find('packages.en.gz') + (filename, filechksum) = find('packages.en') unless filename + if filename + f = download("#{descrdir}/#{filename}", true, filechksum, true) + if f + @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES) + f.close + end + end + @handle.internalize() + end + end + add_exts() + writecachedrepo(nil) + @handle.create_stubs() + return true + end + + def add_ext(repodata, what, ext) + (filename, filechksum) = find(what) + h = repodata.new_handle() + repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename) + repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum) + add_ext_keys(ext, repodata, h) + repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h) + end + + def add_exts + repodata = @handle.add_repodata(0) + di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, nil, 0) + di.prepend_keyname(Solv::SUSETAGS_FILE) + for d in di + filename = d.str + next unless filename && filename =~ /^packages\.(..)(?:\..*)$/ + next if $1 == 'en' || $1 == 'gz' + add_ext(repodata, filename, $1) + end + repodata.internalize() + end + + def load_ext(repodata) + filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME) + ext = filename[9,2] + print "[#{@name}:#{ext}: " + STDOUT.flush + if usecachedrepo(ext) + puts "cached]\n" + return true + end + puts "fetching]\n" + defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR) + descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR) + descrdir = "suse/setup/descr" unless descrdir + filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM) + f = download("#{descrdir}/#{filename}", true, filechksum) + return false unless f + flags = Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES + flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL' + @handle.add_susetags(f, defvendorid, ext, flags) + f.close + writecachedrepo(ext, repodata) + return true + end + + def packagespath() + datadir = @handle.meta.lookup_str(Solv::SUSETAGS_DATADIR) + datadir = "suse" unless datadir + return datadir + '/' + end +end + +class Repo_unknown < Repo_generic + def load(pool) + puts "unsupported repo '#{@name}: skipped" + return false + end +end + +class Repo_system < Repo_generic + def load(pool) + @handle = pool.add_repo(@name) + @handle.appdata = self + pool.installed = @handle + print "rpm database: " + @cookie = calc_cookie_file("/var/lib/rpm/Packages") + if usecachedrepo(nil) + puts "cached" + return true + end + puts "reading" + if @handle.respond_to? :add_products + @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE) + end + f = Solv::xfopen(cachepath()) + @handle.add_rpmdb_reffp(f, Solv::Repo::REPO_REUSE_REPODATA) + f.close if f + writecachedrepo(nil) + return true + end +end + +args = ARGV +cmd = args.shift + +cmdabbrev = { 'ls' => 'list', 'in' => 'install', 'rm' => 'erase', + 've' => 'verify', 'se' => 'search' } +cmd = cmdabbrev[cmd] if cmdabbrev.has_key?(cmd) + +cmdactionmap = { + 'install' => Solv::Job::SOLVER_INSTALL, + 'erase' => Solv::Job::SOLVER_ERASE, + 'up' => Solv::Job::SOLVER_UPDATE, + 'dup' => Solv::Job::SOLVER_DISTUPGRADE, + 'verify' => Solv::Job::SOLVER_VERIFY, + 'list' => 0, + 'info' => 0, +} + +repos = [] +reposdirs = [] +if FileTest.directory?('/etc/zypp/repos.d') + reposdirs = [ '/etc/zypp/repos.d' ] +else + reposdirs = [ '/etc/yum/repos.d' ] +end +for reposdir in reposdirs do + next unless FileTest.directory?(reposdir) + for reponame in Dir["#{reposdir}/*.repo"].sort do + cfg = IniFile.load(reponame) + cfg.each_section do |ali| + repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900} + repoattr.update(cfg[ali]) + if repoattr['type'] == 'rpm-md' + repo = Repo_rpmmd.new(ali, 'repomd', repoattr) + elsif repoattr['type'] == 'yast2' + repo = Repo_susetags.new(ali, 'susetags', repoattr) + else + repo = Repo_unknown.new(ali, 'unknown', repoattr) + end + repos.push(repo) + end + end +end + +pool = Solv::Pool.new() +pool.setarch() + +pool.set_loadcallback { |repodata| + repo = repodata.repo.appdata + repo ? repo.load_ext(repodata) : false +} + +sysrepo = Repo_system.new('@System', 'system') +sysrepo.load(pool) +for repo in repos + repo.load(pool) if repo.enabled? +end + +if cmd == 'search' + pool.createwhatprovides() + sel = pool.Selection + for di in pool.Dataiterator(Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE) + sel.add_raw(Solv::Job::SOLVER_SOLVABLE, di.solvid) + end + for s in sel.solvables + puts "- #{s.str} [#{s.repo.name}]: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}" + end + exit +end + +abort("unknown command '#{cmd}'\n") unless cmdactionmap.has_key?(cmd) + +addedprovides = pool.addfileprovides_queue() +if !addedprovides.empty? + sysrepo.updateaddedprovides(addedprovides) + for repo in repos + repo.updateaddedprovides(addedprovides) + end +end +pool.createwhatprovides() + +jobs = [] +for arg in args + flags = Solv::Selection::SELECTION_NAME | Solv::Selection::SELECTION_PROVIDES | Solv::Selection::SELECTION_GLOB + flags |= Solv::Selection::SELECTION_CANON | Solv::Selection::SELECTION_DOTARCH | Solv::Selection::SELECTION_REL + if arg =~ /^\// + flags |= Solv::Selection::SELECTION_FILELIST + flags |= Solv::Selection::SELECTION_INSTALLED_ONLY if cmd == 'erase' + end + sel = pool.select(arg, flags) + if sel.isempty? + sel = pool.select(arg, flags | Solv::Selection::SELECTION_NOCASE) + puts "[ignoring case for '#{arg}']" unless sel.isempty? + end + puts "[using file list match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_FILELIST != 0 + puts "[using capability match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_PROVIDES != 0 + jobs += sel.jobs(cmdactionmap[cmd]) +end + +if jobs.empty? && (cmd == 'up' || cmd == 'dup' || cmd == 'verify') + sel = pool.Selection_all() + jobs += sel.jobs(cmdactionmap[cmd]) +end + +abort("no package matched.") if jobs.empty? + +if cmd == 'list' || cmd == 'info' + for job in jobs + for s in job.solvables() + if cmd == 'info' + puts "Name: #{s.str}" + puts "Repo: #{s.repo.name}" + puts "Summary: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}" + str = s.lookup_str(Solv::SOLVABLE_URL) + puts "Url: #{str}" if str + str = s.lookup_str(Solv::SOLVABLE_LICENSE) + puts "License: #{str}" if str + puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}" + puts + else + puts " - #{s.str} [#{s.repo.name}]" + puts " #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}" + end + end + end + exit +end + +for job in jobs + job.how ^= Solv::Job::SOLVER_UPDATE ^ Solv::Job::SOLVER_INSTALL if cmd == 'up' and job.isemptyupdate? +end + +solver = pool.Solver +solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1) +solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase' +#pool.set_debuglevel(1) + +while true + problems = solver.solve(jobs) + break if problems.empty? + for problem in problems + puts "Problem #{problem.id}/#{problems.count}:" + puts problem + solutions = problem.solutions + for solution in solutions + puts " Solution #{solution.id}:" + elements = solution.elements(true) + for element in elements + puts " - #{element.str}" + end + puts + end + sol = nil + while true + print "Please choose a solution: " + STDOUT.flush + sol = STDIN.gets.strip + break if sol == 's' || sol == 'q' + break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length + end + next if sol == 's' + abort if sol == 'q' + solution = solutions[sol.to_i - 1] + for element in solution.elements + newjob = element.Job() + if element.type == Solv::Solver::SOLVER_SOLUTION_JOB + jobs[element.jobidx] = newjob + else + jobs.push(newjob) if newjob && !jobs.include?(newjob) + end + end + end +end + +trans = solver.transaction +solver = nil +if trans.isempty? + puts "Nothing to do." + exit +end + +puts "\nTransaction summary:\n" +for cl in trans.classify(Solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES | Solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE) + if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE + puts "#{cl.count} erased packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL + puts "#{cl.count} installed packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED + puts "#{cl.count} reinstalled packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED + puts "#{cl.count} downgraded packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED + puts "#{cl.count} changed packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED + puts "#{cl.count} upgraded packages:" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE + puts "#{cl.count} vendor changes from '#{cl.fromstr}' to '#{cl.tostr}':" + elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE + puts "#{cl.count} arch changes from '#{cl.fromstr}' to '#{cl.tostr}':" + else + next + end + for p in cl.solvables + if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED + puts " - #{p.str} -> #{trans.othersolvable(p).str}" + else + puts " - #{p.str}" + end + end + puts +end +puts "install size change: #{trans.calc_installsizechange()} K\n\n" + +while true + print("OK to continue (y/n)? ") + STDOUT.flush + yn = STDIN.gets.strip + break if yn == 'y' + abort if yn == 'n' || yn == 'q' +end + +newpkgs = trans.newsolvables() +newpkgsfp = {} +if !newpkgs.empty? + downloadsize = 0 + for p in newpkgs + downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE) + end + puts "Downloading #{newpkgs.length} packages, #{downloadsize / 1024} K" + for p in newpkgs + repo = p.repo.appdata + location, medianr = p.lookup_location() + next unless location + location = repo.packagespath + location + chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM) + f = repo.download(location, false, chksum) + abort("\n#{@name}: #{location} not found in repository\n") unless f + newpkgsfp[p.id] = f + print "." + STDOUT.flush() + end + puts +end + +puts "Committing transaction:" +puts +trans.order() +for p in trans.steps + steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY) + if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE + puts "erase #{p.str}" + next unless p.lookup_num(Solv::RPM_RPMDBID) + evr = p.evr.sub(/^[0-9]+:/, '') + system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}") + elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) + puts "install #{p.str}" + f = newpkgsfp.delete(p.id) + next unless f + mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i' + f.cloexec(0) + system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}") + f.close + end +end diff --git a/examples/repo2solv.sh b/examples/repo2solv.sh new file mode 100755 index 0000000..450b7fa --- /dev/null +++ b/examples/repo2solv.sh @@ -0,0 +1,303 @@ +#! /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 + +get_DESCRDIR () { + local d=$(grep '^DESCRDIR' content | sed 's/^DESCRDIR[[:space:]]\+\(.*[^[:space:]]\)[[:space:]]*$/\1/') + if test -z "$d"; then + echo suse/setup/descr + else + echo ${d} + fi +} + +test_susetags() { + if test -s content; then + DESCR=$(get_DESCRDIR) + test -d $DESCR + return $? + else + return 1 + fi +} + +repomd_findfile() { + local t=$1 + 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=${f##*/} + if test -f "$f" ; then + echo "$f" + return + fi + fi + if test -f "$p.bz2" ; then + echo "$p.bz2" + elif test -f "$p.gz" ; then + echo "$p.gz" + elif test -f "$p" ; then + echo "$p" + fi +} + +repomd_types() { + test -s repomd.xml && repomdxml2solv -q type < repomd.xml +} + +repomd_decompress() { + case $1 in + *.gz) gzip -dc "$1" ;; + *.bz2) bzip2 -dc "$1" ;; + *.lzma) lzma -dc "$1" ;; + *.xz) xz -dc "$1" ;; + *) cat "$1" ;; + esac +} + +susetags_findfile() { + if test -s "$1.xz" ; then + echo "$1.xz" + elif test -s "$1.lzma" ; then + echo "$1.lzma" + elif test -s "$1.bz2" ; then + echo "$1.bz2" + elif test -s "$1.gz" ; then + echo "$1.gz" + fi +} + +susetags_findfile_cat() { + if test -s "$1.xz" ; then + xz -dc "$1.xz" + elif test -s "$1.lzma" ; then + lzma -dc "$1.lzma" + elif test -s "$1.bz2" ; then + bzip2 -dc "$1.bz2" + elif test -s "$1.gz" ; then + gzip -dc "$1.gz" + elif test -s "$1" ; then + cat "$1" + fi +} + +# signal an error if there is a problem +set -e + +LANG=C +unset CDPATH +parser_options=${PARSER_OPTIONS:-} + +findopt="-prune" +repotype= +addautooption= + +while true ; do + if test "$1" = "-o" ; then + exec > "$2" + shift + shift + elif test "$1" = "-R" ; then + # recursive + findopt= + repotype=plaindir + shift + elif test "$1" = "-X" ; then + addautooption=-X + shift + elif test "$1" = "-A" ; then + shift + else + break + fi +done + +dir="$1" +cd "$dir" || exit 1 + +if test -z "$repotype" ; then + # autodetect repository type + if test -d repodata -o -f repomd.xml; then + repotype=rpmmd + elif test_susetags ; then + repotype=susetags + else + repotype=plaindir + fi +fi + +if test "$repotype" = rpmmd ; then + test -d repodata && { + cd repodata || exit 2 + } + + primfile= + primxml=`repomd_findfile primary primary.xml` + if test -n "$primxml" -a -s "$primxml" ; then + primfile=`mktemp` || exit 3 + ( + # fake tag to combine primary.xml and extensions + # like susedata.xml, other.xml, filelists.xml + echo '' + if test -f $primxml ; then + repomd_decompress $primxml + # add a newline + echo + fi + susedataxml=`repomd_findfile susedata susedata.xml` + 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 + + prodfile= + prodxml=`repomd_findfile products products.xml` + if test -z "$prodxml" ; then + prodxml=`repomd_findfile product product.xml` + fi + if test -n "$prodxml" -a -s "$prodxml" ; then + prodfile=`mktemp` || exit 3 + repomd_decompress "$prodxml" | rpmmd2solv $parser_options > $prodfile || exit 4 + fi + + patternfile= + patternxml=`repomd_findfile 'patterns' patterns.xml` + if test -n "$patternxml" -a -s "$patternxml" ; then + patternfile=`mktemp` || exit 3 + repomd_decompress "$patternxml" | rpmmd2solv $parser_options > $patternfile || exit 4 + fi + + # This contains repomd.xml + # for now we only read some keys like timestamp + repomdfile= + repomdxml=`repomd_findfile '' repomd.xml` + if test -n "$repomdxml" -a -s "$repomdxml" ; then + repomdfile=`mktemp` || exit 3 + repomd_decompress "$repomdxml" | repomdxml2solv $parser_options > $repomdfile || exit 4 + fi + + # This contains suseinfo.xml, which is an extension to repomd.xml + # for now we only read some keys like expiration and products + suseinfofile= + suseinfoxml=`repomd_findfile suseinfo suseinfo.xml` + if test -n "$suseinfoxml" -a -s "$suseinfoxml" ; then + suseinfofile=`mktemp` || exit 3 + repomd_decompress "$suseinfoxml" | repomdxml2solv $parser_options > $suseinfofile || exit 4 + fi + + # This contains a updateinfo.xml* and maybe patches + updateinfofile= + updateinfoxml=`repomd_findfile updateinfo updateinfo.xml` + if test -n "$updateinfoxml" -a -s "$updateinfoxml" ; then + updateinfofile=`mktemp` || exit 3 + repomd_decompress "$updateinfoxml" | updateinfoxml2solv $parser_options > $updateinfofile || exit 4 + fi + + # This contains a deltainfo.xml* + deltainfofile= + deltainfoxml=`repomd_findfile deltainfo deltainfo.xml` + if test -z "$deltainfoxml"; then + deltainfoxml=`repomd_findfile prestodelta prestodelta.xml` + fi + if test -n "$deltainfoxml" -a -s "$deltainfoxml" ; then + deltainfofile=`mktemp` || exit 3 + repomd_decompress "$deltainfoxml" | deltainfoxml2solv $parser_options > $deltainfofile || exit 4 + fi + + # This contains appdata + appdataxml= + appdatafile= + if test -x /usr/bin/appdata2solv ; then + appdataxml=`repomd_findfile appdata appdata.xml` + fi + if test -n "$appdataxml" -a -s "$appdataxml" ; then + appdatafile=`mktemp` || exit 3 + repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4 + fi + + # Now merge primary, patches, updateinfo, and deltainfo + mergesolv $addautooption $repomdfile $suseinfofile $primfile $prodfile $patternfile $updateinfofile $deltainfofile $appdatafile + rm -f $repomdfile $suseinfofile $primfile $patternfile $prodfile $updateinfofile $deltainfofile $appdatafile + +elif test "$repotype" = susetags ; then + olddir=`pwd` + DESCR=$(get_DESCRDIR) + cd ${DESCR} || exit 2 + appdataxml= + appdatafile= + if test -x /usr/bin/appdata2solv ; then + appdataxml=`susetags_findfile appdata.xml` + fi + if test -n "$appdataxml" ; then + appdatafile=`mktemp` || exit 3 + repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4 + parser_options="-M $appdatafile $parser_options" + fi + ( + # First packages + susetags_findfile_cat packages + + # DU + susetags_findfile_cat packages.DU + + # 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 + for i in `cat patterns`; do + if test -s "$i" ; then + repomd_decompress "$i" + fi + done + fi + + # Now all other packages.{lang}. Needs to come last as it switches + # languages for all following susetags files + for i in packages.* ; do + case $i in + *.gz|*.bz2|*.xz|*.lzma) name="${i%.*}" ;; + *) name="$i" ;; + esac + case $name in + # ignore files we handled already + *.DU | *.en | *.FL | *.DL | packages ) continue ;; + *) + suff=${name#packages.} + echo "=Lan: $suff" + repomd_decompress "$i" + esac + done + + ) | susetags2solv $addautooption -c "${olddir}/content" $parser_options || exit 4 + test -n "$appdatafile" && rm -f "$appdatafile" + cd "$olddir" +elif test "$repotype" = plaindir ; then + find * -name .\* -prune -o $findopt -name \*.delta.rpm -o -name \*.patch.rpm -o -name \*.rpm -a -type f -print0 | rpms2solv $addautooption -0 -m - +else + echo "unknown repository type '$repotype'" >&2 + exit 1 +fi diff --git a/examples/solv/CMakeLists.txt b/examples/solv/CMakeLists.txt new file mode 100644 index 0000000..0f3bd47 --- /dev/null +++ b/examples/solv/CMakeLists.txt @@ -0,0 +1,29 @@ + +ADD_EXECUTABLE (solv solv.c +checksig.c +deltarpm.c +fastestmirror.c +fileconflicts.c +fileprovides.c +mirror.c +patchjobs.c +repoinfo.c +repoinfo_cache.c +repoinfo_config_debian.c +repoinfo_config_yum.c +repoinfo_config_urpmi.c +repoinfo_download.c +repoinfo_system_debian.c +repoinfo_system_rpm.c +repoinfo_type_debian.c +repoinfo_type_mdk.c +repoinfo_type_rpmmd.c +repoinfo_type_susetags.c +) + +TARGET_LINK_LIBRARIES (solv libsolvext libsolv ${SYSTEM_LIBRARIES}) + +INSTALL(TARGETS + solv + DESTINATION ${CMAKE_INSTALL_BINDIR}) + diff --git a/examples/solv/checksig.c b/examples/solv/checksig.c new file mode 100644 index 0000000..44603d3 --- /dev/null +++ b/examples/solv/checksig.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#ifdef ENABLE_PUBKEY +#include "repo_pubkey.h" +#endif + +#include "checksig.h" + +#ifndef DEBIAN + +static void +cleanupgpg(char *gpgdir) +{ + char cmd[256]; + snprintf(cmd, sizeof(cmd), "%s/pubring.gpg", gpgdir); + unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/pubring.gpg~", gpgdir); + unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/secring.gpg", gpgdir); + unlink(cmd); + snprintf(cmd, sizeof(cmd), "%s/trustdb.gpg", 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); +} + +int +checksig(Pool *sigpool, FILE *fp, FILE *sigfp) +{ + char *gpgdir; + char *keysfile; + const char *pubkey, *pubring; + char cmd[256]; + FILE *kfp; + Solvable *s; + Id p; + off_t posfp, possigfp; + int r, nkeys; + + gpgdir = mkdtemp(pool_tmpjoin(sigpool, "/var/tmp/solvgpg.XXXXXX", 0, 0)); + if (!gpgdir) + return 0; + keysfile = pool_tmpjoin(sigpool, gpgdir, "/keys", 0); + if (!(kfp = fopen(keysfile, "w")) ) + { + cleanupgpg(gpgdir); + return 0; + } + nkeys = 0; + for (p = 1, s = sigpool->solvables + p; p < sigpool->nsolvables; p++, s++) + { + if (!s->repo) + continue; + pubkey = solvable_lookup_str(s, SOLVABLE_DESCRIPTION); + if (!pubkey || !*pubkey) + continue; + if (fwrite(pubkey, strlen(pubkey), 1, kfp) != 1) + break; + if (fputc('\n', kfp) == EOF) /* Just in case... */ + break; + nkeys++; + } + if (fclose(kfp) || !nkeys || p < sigpool->nsolvables) + { + cleanupgpg(gpgdir); + return 0; + } + snprintf(cmd, sizeof(cmd), "gpg2 -q --homedir %s --import %s", gpgdir, keysfile); + if (system(cmd)) + { + fprintf(stderr, "key import error\n"); + cleanupgpg(gpgdir); + return 0; + } + unlink(keysfile); + posfp = lseek(fileno(fp), 0, SEEK_CUR); + lseek(fileno(fp), 0, SEEK_SET); + possigfp = lseek(fileno(sigfp), 0, SEEK_CUR); + lseek(fileno(sigfp), 0, SEEK_SET); + 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); + lseek(fileno(sigfp), possigfp, SEEK_SET); + lseek(fileno(fp), posfp, SEEK_SET); + fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); + fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC); + cleanupgpg(gpgdir); + return r == 0 ? 1 : 0; +} + +#else + +int +checksig(Pool *sigpool, FILE *fp, FILE *sigfp) +{ + char cmd[256]; + int r; + + snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp)); + fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */ + fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */ + r = system(cmd); + fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); + fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC); + return r == 0 ? 1 : 0; +} + +#endif + +Pool * +read_sigs() +{ + Pool *sigpool = pool_create(); +#if defined(ENABLE_PUBKEY) && defined(ENABLE_RPMDB) + Repo *repo = repo_create(sigpool, "pubkeys"); + repo_add_rpmdb_pubkeys(repo, 0); +#endif + return sigpool; +} diff --git a/examples/solv/checksig.h b/examples/solv/checksig.h new file mode 100644 index 0000000..67ebaf8 --- /dev/null +++ b/examples/solv/checksig.h @@ -0,0 +1,3 @@ +extern int checksig(Pool *sigpool, FILE *fp, FILE *sigfp); +extern Pool *read_sigs(); + diff --git a/examples/solv/deltarpm.c b/examples/solv/deltarpm.c new file mode 100644 index 0000000..438c2d8 --- /dev/null +++ b/examples/solv/deltarpm.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repoinfo.h" +#include "repoinfo_download.h" + +#include "deltarpm.h" + +static inline int +opentmpfile() +{ + char tmpl[100]; + int fd; + + strcpy(tmpl, "/var/tmp/solvXXXXXX"); + fd = mkstemp(tmpl); + if (fd < 0) + { + perror("mkstemp"); + exit(1); + } + unlink(tmpl); + return fd; +} + +FILE * +trydeltadownload(Solvable *s, const char *loc) +{ + Repo *repo = s->repo; + Pool *pool = repo->pool; + struct repoinfo *cinfo = repo->appdata; + Dataiterator di; + Id pp; + const unsigned char *chksum; + Id chksumtype; + FILE *retfp = 0; + char *matchname = strdup(pool_id2str(pool, s->name)); + + dataiterator_init(&di, pool, repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING); + dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO); + while (dataiterator_step(&di)) + { + Id baseevr, op; + + dataiterator_setpos_parent(&di); + if (pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_EVR) != s->evr || + pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_ARCH) != s->arch) + continue; + baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR); + FOR_PROVIDES(op, pp, s->name) + { + Solvable *os = pool->solvables + op; + if (os->repo == pool->installed && os->name == s->name && os->arch == s->arch && os->evr == baseevr) + break; + } + if (op && access("/usr/bin/applydeltarpm", X_OK) == 0) + { + /* base is installed, run sequence check */ + const char *seq; + const char *dloc; + const char *archstr; + FILE *fp; + char cmd[128]; + int newfd; + + archstr = pool_id2str(pool, s->arch); + if (strlen(archstr) > 10 || strchr(archstr, '\'') != 0) + continue; + + seq = pool_tmpjoin(pool, pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME), "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR)); + seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM)); + if (strchr(seq, '\'') != 0) + continue; +#if defined(FEDORA) || defined(MAGEIA) + sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr); +#else + sprintf(cmd, "/usr/bin/applydeltarpm -c -s '"); +#endif + if (system(pool_tmpjoin(pool, cmd, seq, "'")) != 0) + continue; /* didn't match */ + /* looks good, download delta */ + chksumtype = 0; + chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &chksumtype); + if (!chksumtype) + continue; /* no way! */ + dloc = pool_lookup_deltalocation(pool, SOLVID_POS, 0); + if (!dloc) + continue; +#ifdef ENABLE_SUSEREPO + if (cinfo->type == TYPE_SUSETAGS) + { + const char *datadir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DATADIR); + dloc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", dloc); + } +#endif + if ((fp = curlfopen(cinfo, dloc, 0, chksum, chksumtype, 0)) == 0) + continue; + /* got it, now reconstruct */ + newfd = opentmpfile(); +#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); +#endif + fcntl(fileno(fp), F_SETFD, 0); + if (system(cmd)) + { + close(newfd); + fclose(fp); + continue; + } + lseek(newfd, 0, SEEK_SET); + chksumtype = 0; + chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype); + if (chksumtype && !verify_checksum(newfd, loc, chksum, chksumtype)) + { + close(newfd); + fclose(fp); + continue; + } + retfp = fdopen(newfd, "r"); + fclose(fp); + break; + } + } + dataiterator_free(&di); + solv_free(matchname); + return retfp; +} diff --git a/examples/solv/deltarpm.h b/examples/solv/deltarpm.h new file mode 100644 index 0000000..528e5a2 --- /dev/null +++ b/examples/solv/deltarpm.h @@ -0,0 +1 @@ +extern FILE *trydeltadownload(Solvable *s, const char *loc); diff --git a/examples/solv/fastestmirror.c b/examples/solv/fastestmirror.c new file mode 100644 index 0000000..0ee4e73 --- /dev/null +++ b/examples/solv/fastestmirror.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +#include "fastestmirror.h" + +void +findfastest(char **urls, int nurls) +{ + int i, j, port; + int *socks, qc; + struct pollfd *fds; + char *p, *p2, *q; + char portstr[16]; + struct addrinfo hints, *result;; + + fds = solv_calloc(nurls, sizeof(*fds)); + socks = solv_calloc(nurls, sizeof(*socks)); + for (i = 0; i < nurls; i++) + { + socks[i] = -1; + p = strchr(urls[i], '/'); + if (!p) + continue; + if (p[1] != '/') + continue; + p += 2; + q = strchr(p, '/'); + qc = 0; + if (q) + { + qc = *q; + *q = 0; + } + if ((p2 = strchr(p, '@')) != 0) + p = p2 + 1; + port = 80; + if (!strncmp("https:", urls[i], 6)) + port = 443; + else if (!strncmp("ftp:", urls[i], 4)) + port = 21; + if ((p2 = strrchr(p, ':')) != 0) + { + port = atoi(p2 + 1); + if (q) + *q = qc; + q = p2; + qc = *q; + *q = 0; + } + sprintf(portstr, "%d", port); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + result = 0; + if (!getaddrinfo(p, portstr, &hints, &result)) + { + socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (socks[i] >= 0) + { + if (fcntl(socks[i], F_SETFL, O_NONBLOCK) == -1) + { + close(socks[i]); + socks[i] = -1; + } + if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1) + { + if (errno != EINPROGRESS) + { + close(socks[i]); + socks[i] = -1; + } + } + } + freeaddrinfo(result); + } + if (q) + *q = qc; + } + for (;;) + { + for (i = j = 0; i < nurls; i++) + { + if (socks[i] < 0) + continue; + fds[j].fd = socks[i]; + fds[j].events = POLLOUT; + j++; + } + if (j < 2) + { + i = j - 1; + break; + } + if (poll(fds, j, 10000) <= 0) + { + i = -1; /* something is wrong */ + break; + } + for (i = 0; i < j; i++) + if ((fds[i].revents & POLLOUT) != 0) + { + int soe = 0; + socklen_t soel = sizeof(int); + if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, &soe, &soel) == -1 || soe != 0) + { + /* connect failed, kill socket */ + for (j = 0; j < nurls; j++) + if (socks[j] == fds[i].fd) + { + close(socks[j]); + socks[j] = -1; + } + i = j + 1; + break; + } + break; /* horray! */ + } + if (i == j + 1) + continue; + if (i == j) + i = -1; /* something is wrong, no bit was set */ + break; + } + /* now i contains the fastest fd index */ + if (i >= 0) + { + for (j = 0; j < nurls; j++) + if (socks[j] == fds[i].fd) + break; + if (j != 0) + { + char *url0 = urls[0]; + urls[0] = urls[j]; + urls[j] = url0; + } + } + for (i = j = 0; i < nurls; i++) + if (socks[i] >= 0) + close(socks[i]); + free(socks); + free(fds); +} diff --git a/examples/solv/fastestmirror.h b/examples/solv/fastestmirror.h new file mode 100644 index 0000000..53251ef --- /dev/null +++ b/examples/solv/fastestmirror.h @@ -0,0 +1,2 @@ +extern void findfastest(char **urls, int nurls); + diff --git a/examples/solv/fileconflicts.c b/examples/solv/fileconflicts.c new file mode 100644 index 0000000..2d45bc4 --- /dev/null +++ b/examples/solv/fileconflicts.c @@ -0,0 +1,81 @@ +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_rpmdb.h" +#include "pool_fileconflicts.h" + +#include "fileconflicts.h" + +struct fcstate { + FILE **newpkgsfps; + Queue *checkq; + int newpkgscnt; + void *rpmstate; +}; + +static void * +fileconflict_cb(Pool *pool, Id p, void *cbdata) +{ + struct fcstate *fcstate = cbdata; + Solvable *s; + Id rpmdbid; + int i; + FILE *fp; + + s = pool_id2solvable(pool, p); + if (pool->installed && s->repo == pool->installed) + { + if (!s->repo->rpmdbid) + return 0; + rpmdbid = s->repo->rpmdbid[p - s->repo->start]; + if (!rpmdbid) + return 0; + return rpm_byrpmdbid(fcstate->rpmstate, rpmdbid); + } + for (i = 0; i < fcstate->newpkgscnt; i++) + if (fcstate->checkq->elements[i] == p) + break; + if (i == fcstate->newpkgscnt) + return 0; + fp = fcstate->newpkgsfps[i]; + if (!fp) + return 0; + rewind(fp); + return rpm_byfp(fcstate->rpmstate, fp, pool_solvable2str(pool, s)); +} + +int +checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts) +{ + struct fcstate fcstate; + int i; + + printf("Searching for file conflicts\n"); + queue_init(conflicts); + fcstate.rpmstate = rpm_state_create(pool, pool_get_rootdir(pool)); + fcstate.newpkgscnt = newpkgs; + fcstate.checkq = checkq; + fcstate.newpkgsfps = newpkgsfps; + pool_findfileconflicts(pool, checkq, newpkgs, conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &fileconflict_cb, &fcstate); + fcstate.rpmstate = rpm_state_free(fcstate.rpmstate); + if (conflicts->count) + { + printf("\n"); + for (i = 0; i < conflicts->count; i += 6) + { + 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; +} + +#endif diff --git a/examples/solv/fileconflicts.h b/examples/solv/fileconflicts.h new file mode 100644 index 0000000..e3f31e7 --- /dev/null +++ b/examples/solv/fileconflicts.h @@ -0,0 +1,2 @@ +extern int checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts); + diff --git a/examples/solv/fileprovides.c b/examples/solv/fileprovides.c new file mode 100644 index 0000000..2654ab6 --- /dev/null +++ b/examples/solv/fileprovides.c @@ -0,0 +1,94 @@ +#include +#include +#include + +#include "pool.h" +#include "repo.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" + +#include "fileprovides.h" + +static void +rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_inst) +{ + Repo *repo; + Repodata *data; + Map providedids; + Queue fileprovidesq; + int i, j, n; + struct repoinfo *cinfo; + + map_init(&providedids, pool->ss.nstrings); + queue_init(&fileprovidesq); + for (i = 0; i < addedfileprovides->count; i++) + MAPSET(&providedids, addedfileprovides->elements[i]); + FOR_REPOS(i, repo) + { + /* make sure all repodatas but the first are extensions */ + if (repo->nrepodata < 2) + continue; + cinfo = repo->appdata; + if (!cinfo) + continue; /* cmdline */ + if (cinfo->incomplete) + continue; + data = repo_id2repodata(repo, 1); + if (data->loadcallback) + continue; + for (j = 2; j < repo->nrepodata; j++) + { + Repodata *edata = repo_id2repodata(repo, j); + if (!edata->loadcallback) + break; + } + if (j < repo->nrepodata) + continue; /* found a non-extension repodata, can't rewrite */ + if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) + { + if (repo == pool->installed && addedfileprovides_inst) + { + for (j = 0; j < addedfileprovides->count; j++) + MAPCLR(&providedids, addedfileprovides->elements[j]); + for (j = 0; j < addedfileprovides_inst->count; j++) + MAPSET(&providedids, addedfileprovides_inst->elements[j]); + } + n = 0; + for (j = 0; j < fileprovidesq.count; j++) + if (MAPTST(&providedids, fileprovidesq.elements[j])) + n++; + if (repo == pool->installed && addedfileprovides_inst) + { + for (j = 0; j < addedfileprovides_inst->count; j++) + MAPCLR(&providedids, addedfileprovides_inst->elements[j]); + for (j = 0; j < addedfileprovides->count; j++) + MAPSET(&providedids, addedfileprovides->elements[j]); + if (n == addedfileprovides_inst->count) + continue; /* nothing new added */ + } + else if (n == addedfileprovides->count) + continue; /* nothing new added */ + } + repodata_set_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, repo == pool->installed && addedfileprovides_inst ? addedfileprovides_inst : addedfileprovides); + repodata_internalize(data); + writecachedrepo(cinfo, 0, data); + } + queue_free(&fileprovidesq); + map_free(&providedids); +} + +void +addfileprovides(Pool *pool) +{ + Queue addedfileprovides; + Queue addedfileprovides_inst; + + queue_init(&addedfileprovides); + queue_init(&addedfileprovides_inst); + pool_addfileprovides_queue(pool, &addedfileprovides, &addedfileprovides_inst); + if (addedfileprovides.count || addedfileprovides_inst.count) + rewrite_repos(pool, &addedfileprovides, &addedfileprovides_inst); + queue_free(&addedfileprovides); + queue_free(&addedfileprovides_inst); +} diff --git a/examples/solv/fileprovides.h b/examples/solv/fileprovides.h new file mode 100644 index 0000000..1069d5a --- /dev/null +++ b/examples/solv/fileprovides.h @@ -0,0 +1 @@ +void addfileprovides(Pool *pool); diff --git a/examples/solv/mirror.c b/examples/solv/mirror.c new file mode 100644 index 0000000..52dc5ef --- /dev/null +++ b/examples/solv/mirror.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +#include "pool.h" +#include "util.h" +#include "fastestmirror.h" + +#include "mirror.h" + +char * +findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep) +{ + char buf[4096], *bp, *ep; + char **urls = 0; + int nurls = 0; + int i; + + if (chksumtypep) + *chksumtypep = 0; + while((bp = fgets(buf, sizeof(buf), fp)) != 0) + { + while (*bp == ' ' || *bp == '\t') + bp++; + if (chksumtypep && !*chksumtypep && !strncmp(bp, "", 20)) + { + bp += 20; + if (solv_hex2bin((const char **)&bp, chksump, 32) == 32) + *chksumtypep = REPOKEY_TYPE_SHA256; + continue; + } + if (strncmp(bp, "'); + if (!bp) + continue; + bp++; + ep = strstr(bp, "repodata/repomd.xml"); + if (!ep) + continue; + *ep = 0; + if (strncmp(bp, "http", 4)) + continue; + urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15); + urls[nurls++] = strdup(bp); + } + if (nurls) + { + if (nurls > 1) + findfastest(urls, nurls > 5 ? 5 : nurls); + bp = urls[0]; + urls[0] = 0; + for (i = 0; i < nurls; i++) + solv_free(urls[i]); + solv_free(urls); + ep = strchr(bp, '/'); + if ((ep = strchr(ep + 2, '/')) != 0) + { + *ep = 0; + printf("[using mirror %s]\n", bp); + *ep = '/'; + } + return bp; + } + return 0; +} + +char * +findmirrorlisturl(FILE *fp) +{ + char buf[4096], *bp, *ep; + int i, l; + char **urls = 0; + int nurls = 0; + + while((bp = fgets(buf, sizeof(buf), fp)) != 0) + { + while (*bp == ' ' || *bp == '\t') + bp++; + if (!*bp || *bp == '#') + continue; + l = strlen(bp); + while (l > 0 && (bp[l - 1] == ' ' || bp[l - 1] == '\t' || bp[l - 1] == '\n')) + bp[--l] = 0; + if ((ep = strstr(bp, "url=")) != 0) + bp = ep + 4; + urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15); + urls[nurls++] = strdup(bp); + } + if (nurls) + { + if (nurls > 1) + findfastest(urls, nurls > 5 ? 5 : nurls); + bp = urls[0]; + urls[0] = 0; + for (i = 0; i < nurls; i++) + solv_free(urls[i]); + solv_free(urls); + ep = strchr(bp, '/'); + if ((ep = strchr(ep + 2, '/')) != 0) + { + *ep = 0; + printf("[using mirror %s]\n", bp); + *ep = '/'; + } + return bp; + } + return 0; +} diff --git a/examples/solv/mirror.h b/examples/solv/mirror.h new file mode 100644 index 0000000..ed85a39 --- /dev/null +++ b/examples/solv/mirror.h @@ -0,0 +1,2 @@ +char *findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep); +char *findmirrorlisturl(FILE *fp); diff --git a/examples/solv/patchjobs.c b/examples/solv/patchjobs.c new file mode 100644 index 0000000..929a203 --- /dev/null +++ b/examples/solv/patchjobs.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "evr.h" +#include "solver.h" + +void +add_patchjobs(Pool *pool, Queue *job) +{ + Id p, pp; + int pruneyou = 0; + Map installedmap, multiversionmap; + Solvable *s; + + map_init(&multiversionmap, 0); + map_init(&installedmap, pool->nsolvables); + solver_calculate_multiversionmap(pool, job, &multiversionmap); + if (pool->installed) + { + FOR_REPO_SOLVABLES(pool->installed, p, s) + MAPSET(&installedmap, p); + } + + /* install all patches */ + for (p = 1; p < pool->nsolvables; p++) + { + const char *type; + int r; + Id p2; + + s = pool->solvables + p; + if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0) + continue; + FOR_PROVIDES(p2, pp, s->name) + { + Solvable *s2 = pool->solvables + p2; + if (s2->name != s->name) + continue; + r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); + if (r < 0 || (r == 0 && p > p2)) + break; + } + if (p2) + continue; + type = solvable_lookup_str(s, SOLVABLE_PATCHCATEGORY); + if (type && !strcmp(type, "optional")) + continue; + r = solvable_trivial_installable_map(s, &installedmap, 0, &multiversionmap); + if (r == -1) + continue; + if (solvable_lookup_bool(s, UPDATE_RESTART) && r == 0) + { + if (!pruneyou++) + queue_empty(job); + } + else if (pruneyou) + continue; + queue_push2(job, SOLVER_SOLVABLE, p); + } + map_free(&installedmap); + map_free(&multiversionmap); +} diff --git a/examples/solv/patchjobs.h b/examples/solv/patchjobs.h new file mode 100644 index 0000000..52edcbe --- /dev/null +++ b/examples/solv/patchjobs.h @@ -0,0 +1,2 @@ +extern void add_patchjobs(Pool *pool, Queue *job); + diff --git a/examples/solv/repoinfo.c b/examples/solv/repoinfo.c new file mode 100644 index 0000000..6273972 --- /dev/null +++ b/examples/solv/repoinfo.c @@ -0,0 +1,289 @@ +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) +#include "repo_rpmdb.h" +#endif +#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) || defined(MAGEIA) +#include "repoinfo_config_yum.h" +#endif +#if defined(DEBIAN) +#include "repoinfo_config_debian.h" +#endif +#if defined(MANDRIVA) +#include "repoinfo_config_urpmi.h" +#endif + +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) +#include "repoinfo_system_rpm.h" +#endif +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) +#include "repoinfo_system_debian.h" +#endif + +#ifdef ENABLE_RPMMD +#include "repoinfo_type_rpmmd.h" +#endif +#ifdef ENABLE_SUSEREPO +#include "repoinfo_type_susetags.h" +#endif +#ifdef ENABLE_DEBIAN +#include "repoinfo_type_debian.h" +#endif +#ifdef ENABLE_MDKREPO +#include "repoinfo_type_mdk.h" +#endif + +static int +repoinfos_sort_cmp(const void *ap, const void *bp) +{ + const struct repoinfo *a = ap; + const struct repoinfo *b = bp; + return strcmp(a->alias, b->alias); +} + +void +sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos) +{ + qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), repoinfos_sort_cmp); +} + +void +free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos) +{ + int i, j; + for (i = 0; i < nrepoinfos; i++) + { + struct repoinfo *cinfo = repoinfos + i; + solv_free(cinfo->name); + solv_free(cinfo->alias); + solv_free(cinfo->path); + solv_free(cinfo->metalink); + solv_free(cinfo->mirrorlist); + solv_free(cinfo->baseurl); + for (j = 0; j < cinfo->ncomponents; j++) + solv_free(cinfo->components[j]); + solv_free(cinfo->components); + } + solv_free(repoinfos); +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) + yum_substitute((Pool *)0, 0); /* free data */ +#endif +} + +struct repoinfo * +read_repoinfos(Pool *pool, int *nrepoinfosp) +{ + struct repoinfo *repoinfos = 0; +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) + repoinfos = read_repoinfos_yum(pool, nrepoinfosp); +#endif +#if defined(MANDRIVA) + repoinfos = read_repoinfos_urpmi(pool, nrepoinfosp); +#endif +#if defined(DEBIAN) + repoinfos = read_repoinfos_debian(pool, nrepoinfosp); +#endif + return repoinfos; +} + +int +read_installed_repo(struct repoinfo *cinfo, Pool *pool) +{ + int r = 1; + cinfo->type = TYPE_INSTALLED; + cinfo->repo = repo_create(pool, "@System"); + cinfo->repo->appdata = cinfo; +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + r = read_installed_rpm(cinfo); +#endif +#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; +} + +int +is_cmdline_package(const char *filename) +{ + int l = strlen(filename); +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + if (l > 4 && !strcmp(filename + l - 4, ".rpm")) + return 1; +#endif +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + if (l > 4 && !strcmp(filename + l - 4, ".deb")) + return 1; +#endif + return 0; +} + +Id +add_cmdline_package(Repo *repo, const char *filename) +{ +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + return repo_add_rpm(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE); +#endif +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + return repo_add_deb(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE); +#endif + return 0; +} + +void +commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp) +{ +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + commit_transactionelement_rpm(pool, type, p, fp); +#endif +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + commit_transactionelement_debian(pool, type, p, fp); +#endif +} + +void +add_ext_keys(Repodata *data, Id handle, const char *ext) +{ + static Id langtags[] = { + SOLVABLE_SUMMARY, REPOKEY_TYPE_STR, + SOLVABLE_DESCRIPTION, REPOKEY_TYPE_STR, + SOLVABLE_EULA, REPOKEY_TYPE_STR, + SOLVABLE_MESSAGEINS, REPOKEY_TYPE_STR, + SOLVABLE_MESSAGEDEL, REPOKEY_TYPE_STR, + SOLVABLE_CATEGORY, REPOKEY_TYPE_ID, + 0, 0 + }; + if (!strcmp(ext, "DL")) + { + repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOSITORY_DELTAINFO); + repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_FLEXARRAY); + } + else if (!strcmp(ext, "FL")) + { + repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_FILELIST); + repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY); + } + else if (!strcmp(ext, "DU")) + { + repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_DISKUSAGE); + repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRNUMNUMARRAY); + } + else + { + Pool *pool = data->repo->pool; + int i; + for (i = 0; langtags[i]; i += 2) + { + repodata_add_idarray(data, handle, REPOSITORY_KEYS, pool_id2langid(pool, langtags[i], ext, 1)); + repodata_add_idarray(data, handle, REPOSITORY_KEYS, langtags[i + 1]); + } + } +} + +int +load_stub(Pool *pool, Repodata *data, void *dp) +{ + struct repoinfo *cinfo = data->repo->appdata; + switch (cinfo->type) + { +#ifdef ENABLE_SUSEREPO + case TYPE_SUSETAGS: + return susetags_load_ext(data->repo, data); +#endif +#ifdef ENABLE_RPMMD + case TYPE_RPMMD: + return repomd_load_ext(data->repo, data); +#endif +#ifdef ENABLE_MDKREPO + case TYPE_MDK: + return mdk_load_ext(data->repo, data); +#endif + default: + /* debian does not have any ext data yet */ + return 0; + } +} + +void +read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) +{ + Repo *repo; + int i; + Pool *sigpool = 0; + + for (i = 0; i < nrepoinfos; i++) + { + struct repoinfo *cinfo = repoinfos + i; + if (!cinfo->enabled) + continue; + + repo = repo_create(pool, cinfo->alias); + cinfo->repo = repo; + repo->appdata = cinfo; + repo->priority = 99 - cinfo->priority; + + 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; + } + + switch (cinfo->type) + { +#ifdef ENABLE_RPMMD + case TYPE_RPMMD: + repomd_load(cinfo, &sigpool); + break; +#endif +#ifdef ENABLE_SUSEREPO + case TYPE_SUSETAGS: + susetags_load(cinfo, &sigpool); + break; +#endif +#ifdef ENABLE_DEBIAN + case TYPE_DEBIAN: + debian_load(cinfo, &sigpool); + break; +#endif +#ifdef ENABLE_MDKREPO + case TYPE_MDK: + mdk_load(cinfo, &sigpool); + break; +#endif + default: + printf("unsupported repo '%s': skipped\n", cinfo->alias); + repo_free(repo, 1); + cinfo->repo = 0; + break; + } +#ifdef SUSE + if (cinfo->repo) + repo_add_autopattern(cinfo->repo, 0); +#endif + } + if (sigpool) + pool_free(sigpool); +} + diff --git a/examples/solv/repoinfo.h b/examples/solv/repoinfo.h new file mode 100644 index 0000000..04f94b7 --- /dev/null +++ b/examples/solv/repoinfo.h @@ -0,0 +1,53 @@ +struct repoinfo { + Repo *repo; + + int type; + char *alias; + char *name; + int enabled; + int autorefresh; + char *baseurl; + char *metalink; + char *mirrorlist; + char *path; + int pkgs_gpgcheck; + int repo_gpgcheck; + int priority; + int keeppackages; + int metadata_expire; + char **components; + int ncomponents; + int cookieset; + unsigned char cookie[32]; + int extcookieset; + unsigned char extcookie[32]; + int incomplete; +}; + +#define TYPE_UNKNOWN 0 +#define TYPE_SUSETAGS 1 +#define TYPE_RPMMD 2 +#define TYPE_PLAINDIR 3 +#define TYPE_DEBIAN 4 +#define TYPE_MDK 5 + +#define TYPE_INSTALLED 16 +#define TYPE_CMDLINE 17 + +#define METADATA_EXPIRE (60 * 15) + +extern void sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos); +extern void free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos); +extern void read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos); +extern struct repoinfo *read_repoinfos(Pool *pool, int *nrepoinfosp); + +extern int read_installed_repo(struct repoinfo *cinfo, Pool *pool); + +extern int is_cmdline_package(const char *filename); +extern Id add_cmdline_package(Repo *repo, const char *filename); + +extern void commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp); + +extern void add_ext_keys(Repodata *data, Id handle, const char *ext); +extern int load_stub(Pool *pool, Repodata *data, void *dp); + diff --git a/examples/solv/repoinfo_cache.c b/examples/solv/repoinfo_cache.c new file mode 100644 index 0000000..ec4fe57 --- /dev/null +++ b/examples/solv/repoinfo_cache.c @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "repo_solv.h" +#include "repo_write.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" + +#define COOKIE_IDENT "1.1" + +#define SOLVCACHE_PATH "/var/cache/solv" + +static char *userhome; + +void +set_userhome() +{ + userhome = getenv("HOME"); + if (userhome && userhome[0] != '/') + userhome = 0; +} + +void +calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out) +{ + char buf[4096]; + Chksum *h = solv_chksum_create(chktype); + int l; + + solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT)); + while ((l = fread(buf, 1, sizeof(buf), fp)) > 0) + solv_chksum_add(h, buf, l); + rewind(fp); + solv_chksum_free(h, out); +} + +void +calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out) +{ + Chksum *h = solv_chksum_create(chktype); + solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT)); + if (cookie) + solv_chksum_add(h, cookie, 32); + solv_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev)); + solv_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino)); + solv_chksum_add(h, &stb->st_size, sizeof(stb->st_size)); + solv_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime)); + solv_chksum_free(h, out); +} + +char * +calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc) +{ + char *q, *p; + int l; + if (!forcesystemloc && userhome && getuid()) + p = pool_tmpjoin(repo->pool, userhome, "/.solvcache/", 0); + else + p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", 0); + l = strlen(p); + p = pool_tmpappend(repo->pool, p, repo->name, 0); + if (repoext) + { + p = pool_tmpappend(repo->pool, p, "_", repoext); + p = pool_tmpappend(repo->pool, p, ".solvx", 0); + } + else + p = pool_tmpappend(repo->pool, p, ".solv", 0); + q = p + l; + if (*q == '.') + *q = '_'; + for (; *q; q++) + if (*q == '/') + *q = '_'; + return p; +} + +int +usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark) +{ + Repo *repo = cinfo->repo; + FILE *fp; + unsigned char *cookie = repoext ? cinfo->extcookie : (cinfo->cookieset ? cinfo->cookie : 0); + unsigned char mycookie[32]; + unsigned char myextcookie[32]; + int flags; + int forcesystemloc; + + if (repoext && !cinfo->extcookieset) + return 0; /* huh? */ + forcesystemloc = mark & 2 ? 0 : 1; + if (mark < 2 && userhome && getuid()) + { + /* first try home location */ + int res = usecachedrepo(cinfo, repoext, mark | 2); + if (res) + return res; + } + mark &= 1; + if (!(fp = fopen(calc_cachepath(repo, repoext, forcesystemloc), "r"))) + return 0; + if (!repoext && !cinfo->cookieset && cinfo->autorefresh && cinfo->metadata_expire != -1) + { + struct stat stb; /* no cookie set yet, check cache expiry time */ + if (fstat(fileno(fp), &stb) || time(0) - stb.st_mtime >= cinfo->metadata_expire) + { + fclose(fp); + return 0; + } + } + if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1) + { + fclose(fp); + return 0; + } + if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)) != 0) + { + fclose(fp); + return 0; + } + if (cinfo->type != TYPE_INSTALLED && !repoext) + { + if (fseek(fp, -sizeof(mycookie) * 2, SEEK_END) || fread(myextcookie, sizeof(myextcookie), 1, fp) != 1) + { + fclose(fp); + return 0; + } + } + rewind(fp); + + flags = 0; + if (repoext) + { + flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; + if (strcmp(repoext, "DL") != 0) + flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */ + } + if (repo_add_solv(repo, fp, flags)) + { + fclose(fp); + return 0; + } + if (cinfo->type != TYPE_INSTALLED && !repoext) + { + memcpy(cinfo->cookie, mycookie, sizeof(mycookie)); + cinfo->cookieset = 1; + memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie)); + cinfo->extcookieset = 1; + } + if (mark) + futimens(fileno(fp), 0); /* try to set modification time */ + fclose(fp); + return 1; +} + +static void +switchtowritten(struct repoinfo *cinfo, const char *repoext, Repodata *repodata, char *tmpl) +{ + Repo *repo = cinfo->repo; + FILE *fp; + int i; + + if (!repoext && repodata) + return; /* rewrite case, don't bother for the added fileprovides */ + for (i = repo->start; i < repo->end; i++) + if (repo->pool->solvables[i].repo != repo) + break; + if (i < repo->end) + return; /* not a simple block */ + /* switch to just saved repo to activate paging and save memory */ + fp = fopen(tmpl, "r"); + if (!fp) + return; + if (!repoext) + { + /* main repo */ + repo_empty(repo, 1); + if (repo_add_solv(repo, fp, SOLV_ADD_NO_STUBS)) + { + /* oops, no way to recover from here */ + fprintf(stderr, "internal error\n"); + exit(1); + } + } + else + { + int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; + /* make sure repodata contains complete repo */ + /* (this is how repodata_write saves it) */ + repodata_extend_block(repodata, repo->start, repo->end - repo->start); + repodata->state = REPODATA_LOADING; + if (strcmp(repoext, "DL") != 0) + flags |= REPO_LOCALPOOL; + repo_add_solv(repo, fp, flags); + repodata->state = REPODATA_AVAILABLE; /* in case the load failed */ + } + fclose(fp); +} + +void +writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata) +{ + Repo *repo = cinfo->repo; + FILE *fp; + int fd; + char *tmpl, *cachedir; + + if (cinfo->incomplete || (repoext && !cinfo->extcookieset) || (!repoext && !cinfo->cookieset)) + return; + cachedir = userhome && getuid() ? pool_tmpjoin(repo->pool, userhome, "/.solvcache", 0) : SOLVCACHE_PATH; + if (access(cachedir, W_OK | X_OK) != 0 && mkdir(cachedir, 0755) == 0) + printf("[created %s]\n", cachedir); + /* use dupjoin instead of tmpjoin because tmpl must survive repo_write */ + tmpl = solv_dupjoin(cachedir, "/", ".newsolv-XXXXXX"); + fd = mkstemp(tmpl); + if (fd < 0) + { + free(tmpl); + return; + } + fchmod(fd, 0444); + if (!(fp = fdopen(fd, "w"))) + { + close(fd); + unlink(tmpl); + free(tmpl); + return; + } + + if (!repodata) + repo_write(repo, fp); + else if (repoext) + repodata_write(repodata, fp); + else + { + int oldnrepodata = repo->nrepodata; + repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata; /* XXX: do this right */ + repo_write(repo, fp); + repo->nrepodata = oldnrepodata; + } + + if (!repoext && cinfo->type != TYPE_INSTALLED) + { + if (!cinfo->extcookieset) + { + /* create the ext cookie and append it */ + /* we just need some unique ID */ + struct stat stb; + if (fstat(fileno(fp), &stb)) + memset(&stb, 0, sizeof(stb)); + calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->cookie, cinfo->extcookie); + cinfo->extcookieset = 1; + } + if (fwrite(cinfo->extcookie, 32, 1, fp) != 1) + { + fclose(fp); + unlink(tmpl); + free(tmpl); + return; + } + } + /* append our cookie describing the metadata state */ + if (fwrite(repoext ? cinfo->extcookie : cinfo->cookie, 32, 1, fp) != 1) + { + fclose(fp); + unlink(tmpl); + free(tmpl); + return; + } + if (fclose(fp)) + { + unlink(tmpl); + free(tmpl); + return; + } + + switchtowritten(cinfo, repoext, repodata, tmpl); + + if (!rename(tmpl, calc_cachepath(repo, repoext, 0))) + unlink(tmpl); + free(tmpl); +} + diff --git a/examples/solv/repoinfo_cache.h b/examples/solv/repoinfo_cache.h new file mode 100644 index 0000000..cc74715 --- /dev/null +++ b/examples/solv/repoinfo_cache.h @@ -0,0 +1,12 @@ + +struct repoinfo; +struct stat; + +extern void set_userhome(void); +extern char *calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc); +extern void calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out); +extern void calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out); + +extern int usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark); +extern void writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata); + diff --git a/examples/solv/repoinfo_config_debian.c b/examples/solv/repoinfo_config_debian.c new file mode 100644 index 0000000..b369970 --- /dev/null +++ b/examples/solv/repoinfo_config_debian.c @@ -0,0 +1,127 @@ +#ifdef DEBIAN + +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" + +#include "repoinfo.h" +#include "repoinfo_config_debian.h" + + + +struct repoinfo * +read_repoinfos_debian(Pool *pool, int *nrepoinfosp) +{ + FILE *fp; + char buf[4096]; + char buf2[4096]; + int l; + char *kp, *url, *distro; + struct repoinfo *repoinfos = 0, *cinfo; + int nrepoinfos = 0; + DIR *dir = 0; + struct dirent *ent; + + fp = fopen("/etc/apt/sources.list", "r"); + while (1) + { + if (!fp) + { + if (!dir) + { + dir = opendir("/etc/apt/sources.list.d"); + if (!dir) + break; + } + if ((ent = readdir(dir)) == 0) + { + closedir(dir); + break; + } + if (ent->d_name[0] == '.') + continue; + l = strlen(ent->d_name); + if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0) + continue; + snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name); + if (!(fp = fopen(buf, "r"))) + continue; + } + while(fgets(buf2, sizeof(buf2), fp)) + { + l = strlen(buf2); + if (l == 0) + continue; + while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t')) + buf2[--l] = 0; + kp = buf2; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp || *kp == '#') + continue; + if (strncmp(kp, "deb", 3) != 0) + continue; + kp += 3; + if (*kp != ' ' && *kp != '\t') + continue; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + url = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + distro = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); + cinfo = repoinfos + nrepoinfos++; + memset(cinfo, 0, sizeof(*cinfo)); + cinfo->baseurl = strdup(url); + cinfo->alias = solv_dupjoin(url, "/", distro); + cinfo->name = strdup(distro); + cinfo->type = TYPE_DEBIAN; + cinfo->enabled = 1; + cinfo->autorefresh = 1; + cinfo->repo_gpgcheck = 1; + cinfo->metadata_expire = METADATA_EXPIRE; + while (*kp) + { + char *compo; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + break; + compo = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + cinfo->components = solv_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15); + cinfo->components[cinfo->ncomponents++] = strdup(compo); + } + } + fclose(fp); + fp = 0; + } + *nrepoinfosp = nrepoinfos; + return repoinfos; +} + +#endif diff --git a/examples/solv/repoinfo_config_debian.h b/examples/solv/repoinfo_config_debian.h new file mode 100644 index 0000000..64b3eb6 --- /dev/null +++ b/examples/solv/repoinfo_config_debian.h @@ -0,0 +1 @@ +extern struct repoinfo *read_repoinfos_debian(Pool *pool, int *nrepoinfosp); diff --git a/examples/solv/repoinfo_config_urpmi.c b/examples/solv/repoinfo_config_urpmi.c new file mode 100644 index 0000000..a79ea9b --- /dev/null +++ b/examples/solv/repoinfo_config_urpmi.c @@ -0,0 +1,106 @@ +#if defined(MANDRIVA) || defined(MAGEIA) + +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" + +#include "repoinfo.h" +#include "repoinfo_config_urpmi.h" + + +#define URPMI_CFG "/etc/urpmi/urpmi.cfg" + + +struct repoinfo * +read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp) +{ + char buf[4096], *bp, *arg; + FILE *fp; + int l, insect = 0; + struct repoinfo *cinfo = 0; + struct repoinfo *repoinfos = 0; + int nrepoinfos = 0; + + if ((fp = fopen(URPMI_CFG, "r")) == 0) + { + *nrepoinfosp = 0; + return 0; + } + while (fgets(buf, sizeof(buf), fp)) + { + l = strlen(buf); + while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t')) + buf[--l] = 0; + bp = buf; + while (l && (*bp == ' ' || *bp == '\t')) + { + l--; + bp++; + } + if (!l || *bp == '#') + continue; + if (!insect && bp[l - 1] == '{') + { + insect++; + bp[--l] = 0; + if (l > 0) + { + while (l && (bp[l - 1] == ' ' || bp[l - 1] == '\t')) + bp[--l] = 0; + } + if (l) + { + char *bbp = bp, *bbp2 = bp; + /* unescape */ + while (*bbp) + { + if (*bbp == '\\' && bbp[1]) + bbp++; + *bbp2++ = *bbp++; + } + *bbp2 = 0; + repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); + cinfo = repoinfos + nrepoinfos++; + memset(cinfo, 0, sizeof(*cinfo)); + cinfo->alias = strdup(bp); + cinfo->type = TYPE_MDK; + cinfo->autorefresh = 1; + cinfo->priority = 99; + cinfo->enabled = 1; + cinfo->metadata_expire = METADATA_EXPIRE; + } + continue; + } + if (insect && *bp == '}') + { + insect--; + cinfo = 0; + continue; + } + if (!insect || !cinfo) + continue; + if ((arg = strchr(bp, ':')) != 0) + { + *arg++ = 0; + while (*arg == ' ' || *arg == '\t') + arg++; + if (!*arg) + arg = 0; + } + if (strcmp(bp, "ignore") == 0) + cinfo->enabled = 0; + if (strcmp(bp, "mirrorlist") == 0) + cinfo->mirrorlist = solv_strdup(arg); + if (strcmp(bp, "with-dir") == 0) + cinfo->path = solv_strdup(arg); + } + fclose(fp); + *nrepoinfosp = nrepoinfos; + return repoinfos; +} + +#endif diff --git a/examples/solv/repoinfo_config_urpmi.h b/examples/solv/repoinfo_config_urpmi.h new file mode 100644 index 0000000..bb7374f --- /dev/null +++ b/examples/solv/repoinfo_config_urpmi.h @@ -0,0 +1,2 @@ +extern struct repoinfo *read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp); + diff --git a/examples/solv/repoinfo_config_yum.c b/examples/solv/repoinfo_config_yum.c new file mode 100644 index 0000000..efccf1e --- /dev/null +++ b/examples/solv/repoinfo_config_yum.c @@ -0,0 +1,233 @@ +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_rpmdb.h" + +#include "repoinfo.h" +#include "repoinfo_config_yum.h" + + +#if defined(FEDORA) || defined(MAGEIA) +# define REPOINFO_PATH "/etc/yum.repos.d" +#endif +#ifdef SUSE +# define REPOINFO_PATH "/etc/zypp/repos.d" +#endif + +char * +yum_substitute(Pool *pool, char *line) +{ + char *p, *p2; + static char *releaseevr; + static char *basearch; + + if (!line) + { + solv_free(releaseevr); + releaseevr = 0; + solv_free(basearch); + basearch = 0; + return 0; + } + p = line; + while ((p2 = strchr(p, '$')) != 0) + { + if (!strncmp(p2, "$releasever", 11)) + { + if (!releaseevr) + { + void *rpmstate; + Queue q; + + queue_init(&q); + rpmstate = rpm_state_create(pool, pool_get_rootdir(pool)); + rpm_installedrpmdbids(rpmstate, "Providename", "system-release", &q); + if (q.count) + { + void *handle; + char *p; + handle = rpm_byrpmdbid(rpmstate, q.elements[0]); + releaseevr = handle ? rpm_query(handle, SOLVABLE_EVR) : 0; + if (releaseevr && (p = strchr(releaseevr, '-')) != 0) + *p = 0; + } + rpm_state_free(rpmstate); + queue_free(&q); + if (!releaseevr) + { + fprintf(stderr, "no installed package provides 'system-release', cannot determine $releasever\n"); + exit(1); + } + } + *p2 = 0; + p = pool_tmpjoin(pool, line, releaseevr, p2 + 11); + p2 = p + (p2 - line); + line = p; + p = p2 + strlen(releaseevr); + continue; + } + if (!strncmp(p2, "$basearch", 9)) + { + if (!basearch) + { + struct utsname un; + if (uname(&un)) + { + perror("uname"); + exit(1); + } + basearch = strdup(un.machine); + if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86")) + basearch[1] = '3'; + } + *p2 = 0; + p = pool_tmpjoin(pool, line, basearch, p2 + 9); + p2 = p + (p2 - line); + line = p; + p = p2 + strlen(basearch); + continue; + } + p = p2 + 1; + } + return line; +} + +struct repoinfo * +read_repoinfos_yum(Pool *pool, int *nrepoinfosp) +{ + const char *reposdir = REPOINFO_PATH; + char buf[4096]; + char buf2[4096], *kp, *vp, *kpe; + DIR *dir; + FILE *fp; + struct dirent *ent; + int l, rdlen; + struct repoinfo *repoinfos = 0, *cinfo; + int nrepoinfos = 0; + + rdlen = strlen(reposdir); + dir = opendir(reposdir); + if (!dir) + { + *nrepoinfosp = 0; + return 0; + } + while ((ent = readdir(dir)) != 0) + { + if (ent->d_name[0] == '.') + continue; + l = strlen(ent->d_name); + if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0) + continue; + snprintf(buf, sizeof(buf), "%s/%s", reposdir, ent->d_name); + if ((fp = fopen(buf, "r")) == 0) + { + perror(buf); + continue; + } + cinfo = 0; + while(fgets(buf2, sizeof(buf2), fp)) + { + l = strlen(buf2); + if (l == 0) + continue; + while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t')) + buf2[--l] = 0; + kp = buf2; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp || *kp == '#') + continue; + if (strchr(kp, '$')) + kp = yum_substitute(pool, kp); + if (*kp == '[') + { + vp = strrchr(kp, ']'); + if (!vp) + continue; + *vp = 0; + repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); + cinfo = repoinfos + nrepoinfos++; + memset(cinfo, 0, sizeof(*cinfo)); + cinfo->alias = strdup(kp + 1); + cinfo->type = TYPE_RPMMD; + cinfo->autorefresh = 1; + cinfo->priority = 99; +#if !defined(FEDORA) && !defined(MAGEIA) + cinfo->repo_gpgcheck = 1; +#endif + cinfo->metadata_expire = METADATA_EXPIRE; + continue; + } + if (!cinfo) + continue; + vp = strchr(kp, '='); + if (!vp) + continue; + for (kpe = vp - 1; kpe >= kp; kpe--) + if (*kpe != ' ' && *kpe != '\t') + break; + if (kpe == kp) + continue; + vp++; + while (*vp == ' ' || *vp == '\t') + vp++; + kpe[1] = 0; + if (!strcmp(kp, "name")) + cinfo->name = strdup(vp); + else if (!strcmp(kp, "enabled")) + cinfo->enabled = *vp == '0' ? 0 : 1; + else if (!strcmp(kp, "autorefresh")) + cinfo->autorefresh = *vp == '0' ? 0 : 1; + else if (!strcmp(kp, "gpgcheck")) + cinfo->pkgs_gpgcheck = *vp == '0' ? 0 : 1; + else if (!strcmp(kp, "repo_gpgcheck")) + cinfo->repo_gpgcheck = *vp == '0' ? 0 : 1; + else if (!strcmp(kp, "baseurl")) + cinfo->baseurl = strdup(vp); + else if (!strcmp(kp, "mirrorlist")) + { + if (strstr(vp, "metalink")) + cinfo->metalink = strdup(vp); + else + cinfo->mirrorlist = strdup(vp); + } + else if (!strcmp(kp, "path")) + { + if (vp && strcmp(vp, "/") != 0) + cinfo->path = strdup(vp); + } + else if (!strcmp(kp, "type")) + { + if (!strcmp(vp, "yast2")) + cinfo->type = TYPE_SUSETAGS; + else if (!strcmp(vp, "rpm-md")) + cinfo->type = TYPE_RPMMD; + else if (!strcmp(vp, "plaindir")) + cinfo->type = TYPE_PLAINDIR; + else if (!strcmp(vp, "mdk")) + cinfo->type = TYPE_MDK; + else + cinfo->type = TYPE_UNKNOWN; + } + else if (!strcmp(kp, "priority")) + cinfo->priority = atoi(vp); + else if (!strcmp(kp, "keeppackages")) + cinfo->keeppackages = *vp == '0' ? 0 : 1; + } + fclose(fp); + cinfo = 0; + } + closedir(dir); + *nrepoinfosp = nrepoinfos; + return repoinfos; +} + +#endif diff --git a/examples/solv/repoinfo_config_yum.h b/examples/solv/repoinfo_config_yum.h new file mode 100644 index 0000000..d7cb4f7 --- /dev/null +++ b/examples/solv/repoinfo_config_yum.h @@ -0,0 +1,2 @@ +extern char *yum_substitute(Pool *pool, char *line); +extern struct repoinfo *read_repoinfos_yum(Pool *pool, int *nrepoinfosp); diff --git a/examples/solv/repoinfo_download.c b/examples/solv/repoinfo_download.c new file mode 100644 index 0000000..f5ba8b9 --- /dev/null +++ b/examples/solv/repoinfo_download.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "solv_xfopen.h" + +#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 +opentmpfile() +{ + char tmpl[100]; + int fd; + + strcpy(tmpl, "/var/tmp/solvXXXXXX"); + fd = mkstemp(tmpl); + if (fd < 0) + { + perror("mkstemp"); + exit(1); + } + unlink(tmpl); + return fd; +} + +int +verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype) +{ + char buf[1024]; + const unsigned char *sum; + Chksum *h; + int l; + + h = solv_chksum_create(chksumtype); + if (!h) + { + printf("%s: unknown checksum type\n", file); + return 0; + } + while ((l = read(fd, buf, sizeof(buf))) > 0) + solv_chksum_add(h, buf, l); + lseek(fd, 0, SEEK_SET); + l = 0; + sum = solv_chksum_get(h, &l); + if (memcmp(sum, chksum, l)) + { + printf("%s: checksum mismatch\n", file); + solv_chksum_free(h, 0); + return 0; + } + solv_chksum_free(h, 0); + return 1; +} + +FILE * +curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete) +{ + FILE *fp; + pid_t pid; + int fd; + int status; + char url[4096]; + const char *baseurl = cinfo->baseurl; + + if (!baseurl) + { + if (!cinfo->metalink && !cinfo->mirrorlist) + return 0; + if (file != cinfo->metalink && file != cinfo->mirrorlist) + { + unsigned char mlchksum[32]; + Id mlchksumtype = 0; + fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0); + if (!fp) + return 0; + if (cinfo->metalink) + cinfo->baseurl = findmetalinkurl(fp, mlchksum, &mlchksumtype); + else + cinfo->baseurl = findmirrorlisturl(fp); + fclose(fp); + if (!cinfo->baseurl) + return 0; +#if defined(FEDORA) || defined(MAGEIA) + if (strchr(cinfo->baseurl, '$')) + { + char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl); + free(cinfo->baseurl); + cinfo->baseurl = strdup(b); + } +#endif + if (!chksumtype && mlchksumtype && !strcmp(file, "repodata/repomd.xml")) + { + chksumtype = mlchksumtype; + chksum = mlchksum; + } + return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete); + } + snprintf(url, sizeof(url), "%s", file); + } + else + { + const char *path = cinfo->path && strcmp(cinfo->path, "/") != 0 ? cinfo->path : ""; + int l = strlen(baseurl); + int pl = strlen(path); + const char *sep = l && baseurl[l - 1] == '/' ? "" : "/"; + const char *psep = pl && cinfo->path[pl - 1] == '/' ? "" : "/"; + snprintf(url, sizeof(url), "%s%s%s%s%s", baseurl, sep, path, psep, file); + } + fd = opentmpfile(); + // printf("url: %s\n", url); + if ((pid = fork()) == (pid_t)-1) + { + perror("fork"); + exit(1); + } + if (pid == 0) + { + if (fd != 1) + { + dup2(fd, 1); + close(fd); + } + execlp("curl", "curl", "-f", "-s", "-L", url, (char *)0); + perror("curl"); + _exit(0); + } + status = 0; + while (waitpid(pid, &status, 0) != pid) + ; + if (lseek(fd, 0, SEEK_END) == 0 && (!status || !chksumtype)) + { + /* empty file */ + close(fd); + return 0; + } + lseek(fd, 0, SEEK_SET); + if (status) + { + printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status); + if (markincomplete) + cinfo->incomplete = 1; + close(fd); + return 0; + } + if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype)) + { + if (markincomplete) + cinfo->incomplete = 1; + close(fd); + return 0; + } + fcntl(fd, F_SETFD, FD_CLOEXEC); + if (uncompress) + { + if (solv_xfopen_iscompressed(file) < 0) + { + printf("%s: unsupported compression\n", file); + if (markincomplete) + cinfo->incomplete = 1; + close(fd); + return 0; + } + fp = solv_xfopen_fd(file, fd, "r"); + } + else + fp = fdopen(fd, "r"); + if (!fp) + close(fd); + return fp; +} + +FILE * +downloadpackage(Solvable *s, const char *loc) +{ + const unsigned char *chksum; + Id chksumtype; + struct repoinfo *cinfo = s->repo->appdata; + +#ifdef ENABLE_SUSEREPO + if (cinfo->type == TYPE_SUSETAGS) + { + const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR); + loc = pool_tmpjoin(s->repo->pool, datadir ? datadir : "suse", "/", loc); + } +#endif + chksumtype = 0; + chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype); + return curlfopen(cinfo, loc, 0, chksum, chksumtype, 0); +} + +int +downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool) +{ + FILE *sigfp; + sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0); + if (!sigfp) + { + printf(" unsigned, skipped\n"); + return 0; + } + if (!*sigpool) + *sigpool = read_sigs(); + if (!checksig(*sigpool, fp, sigfp)) + { + printf(" checksig failed, skipped\n"); + fclose(sigfp); + return 0; + } + fclose(sigfp); + return 1; +} + diff --git a/examples/solv/repoinfo_download.h b/examples/solv/repoinfo_download.h new file mode 100644 index 0000000..2dfeaa0 --- /dev/null +++ b/examples/solv/repoinfo_download.h @@ -0,0 +1,7 @@ +int verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype); + +FILE *curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete); + +FILE *downloadpackage(Solvable *s, const char *loc); +int downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool); + diff --git a/examples/solv/repoinfo_system_debian.c b/examples/solv/repoinfo_system_debian.c new file mode 100644 index 0000000..f01be60 --- /dev/null +++ b/examples/solv/repoinfo_system_debian.c @@ -0,0 +1,108 @@ +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_deb.h" +#include "transaction.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_system_debian.h" + +static void +rundpkg(const char *arg, const char *name, int dupfd3, const char *rootdir) +{ + pid_t pid; + int status; + + if ((pid = fork()) == (pid_t)-1) + { + perror("fork"); + exit(1); + } + if (pid == 0) + { + if (!rootdir) + rootdir = "/"; + if (dupfd3 != -1 && dupfd3 != 3) + { + dup2(dupfd3, 3); + close(dupfd3); + } + if (dupfd3 != -1) + fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ + if (strcmp(arg, "--install") == 0) + execlp("dpkg", "dpkg", "--install", "--root", rootdir, "--force", "all", name, (char *)0); + else + execlp("dpkg", "dpkg", "--remove", "--root", rootdir, "--force", "all", name, (char *)0); + perror("dpkg"); + _exit(0); + } + while (waitpid(pid, &status, 0) != pid) + ; + if (status) + { + printf("dpkg failed\n"); + exit(1); + } +} + +int +read_installed_debian(struct repoinfo *cinfo) +{ + struct stat stb; + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + + memset(&stb, 0, sizeof(stb)); + printf("dpgk database:"); + if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/dpkg/status"), &stb)) + memset(&stb, 0, sizeof(stb)); + calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 0)) + { + printf(" cached\n"); + return 1; + } + if (repo_add_debdb(repo, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); + return 0; + } + repo_internalize(repo); + writecachedrepo(cinfo, 0, 0); + return 1; +} + +void +commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp) +{ + Solvable *s = pool_id2solvable(pool, p); + const char *rootdir = pool_get_rootdir(pool); + + switch(type) + { + case SOLVER_TRANSACTION_ERASE: + rundpkg("--remove", pool_id2str(pool, s->name), 0, rootdir); + break; + case SOLVER_TRANSACTION_INSTALL: + case SOLVER_TRANSACTION_MULTIINSTALL: + rewind(fp); + lseek(fileno(fp), 0, SEEK_SET); + rundpkg("--install", "/dev/fd/3", fileno(fp), rootdir); + break; + default: + break; + } +} + +#endif diff --git a/examples/solv/repoinfo_system_debian.h b/examples/solv/repoinfo_system_debian.h new file mode 100644 index 0000000..c0e2b29 --- /dev/null +++ b/examples/solv/repoinfo_system_debian.h @@ -0,0 +1,2 @@ +int read_installed_debian(struct repoinfo *cinfo); +void commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp); diff --git a/examples/solv/repoinfo_system_rpm.c b/examples/solv/repoinfo_system_rpm.c new file mode 100644 index 0000000..b556afc --- /dev/null +++ b/examples/solv/repoinfo_system_rpm.c @@ -0,0 +1,164 @@ +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA)) + +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "repo_rpmdb.h" +#if defined(ENABLE_SUSEREPO) && defined(SUSE) +#include "repo_products.h" +#endif +#if defined(ENABLE_APPDATA) +#include "repo_appdata.h" +#endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif +#include "transaction.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_system_rpm.h" + +#ifdef SUSE +# define PRODUCTS_PATH "/etc/products.d" +#endif +#ifdef ENABLE_APPDATA +# define APPDATA_PATH "/usr/share/metainfo" +# define APPDATA_LEGACY_PATH "/usr/share/appdata" +#endif + +static void +runrpm(const char *arg, const char *name, int dupfd3, const char *rootdir) +{ + pid_t pid; + int status; + + if ((pid = fork()) == (pid_t)-1) + { + perror("fork"); + exit(1); + } + if (pid == 0) + { + if (!rootdir) + rootdir = "/"; + if (dupfd3 != -1 && dupfd3 != 3) + { + dup2(dupfd3, 3); + close(dupfd3); + } + if (dupfd3 != -1) + fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ + if (strcmp(arg, "-e") == 0) + execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); + else + execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); + perror("rpm"); + _exit(0); + } + while (waitpid(pid, &status, 0) != pid) + ; + if (status) + { + printf("rpm failed\n"); + exit(1); + } +} + +int +read_installed_rpm(struct repoinfo *cinfo) +{ + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + FILE *ofp = 0; + struct stat stb; + + memset(&stb, 0, sizeof(stb)); + printf("rpm database:"); + if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/rpm/Packages"), &stb)) + memset(&stb, 0, sizeof(stb)); + calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 0)) + { + printf(" cached\n"); + return 1; + } + printf(" reading\n"); +#if defined(ENABLE_SUSEREPO) && defined(PRODUCTS_PATH) + if (repo_add_products(repo, PRODUCTS_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + fprintf(stderr, "product reading failed: %s\n", pool_errstr(pool)); + return 0; + } +#endif +#if defined(ENABLE_APPDATA) && defined(APPDATA_PATH) + if (repo_add_appdata_dir(repo, APPDATA_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + 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)) + { + fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); + return 0; + } + if (ofp) + fclose(ofp); + repo_internalize(repo); +#ifdef SUSE + repo_add_autopattern(repo, 0); +#endif + writecachedrepo(cinfo, 0, 0); + return 1; +} + +void +commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp) +{ + Solvable *s = pool_id2solvable(pool, p); + const char *rootdir = pool_get_rootdir(pool); + const char *evr, *evrp, *nvra; + + switch(type) + { + case SOLVER_TRANSACTION_ERASE: + if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start]) + break; + /* strip epoch from evr */ + evr = evrp = pool_id2str(pool, s->evr); + while (*evrp >= '0' && *evrp <= '9') + evrp++; + if (evrp > evr && evrp[0] == ':' && evrp[1]) + evr = evrp + 1; + nvra = pool_tmpjoin(pool, pool_id2str(pool, s->name), "-", evr); + nvra = pool_tmpappend(pool, nvra, ".", pool_id2str(pool, s->arch)); + runrpm("-e", nvra, -1, rootdir); /* too bad that --querybynumber doesn't work */ + break; + case SOLVER_TRANSACTION_INSTALL: + case SOLVER_TRANSACTION_MULTIINSTALL: + rewind(fp); + lseek(fileno(fp), 0, SEEK_SET); + runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp), rootdir); + break; + default: + break; + } +} + +#endif diff --git a/examples/solv/repoinfo_system_rpm.h b/examples/solv/repoinfo_system_rpm.h new file mode 100644 index 0000000..db63a8d --- /dev/null +++ b/examples/solv/repoinfo_system_rpm.h @@ -0,0 +1,2 @@ +int read_installed_rpm(struct repoinfo *cinfo); +void commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp); diff --git a/examples/solv/repoinfo_type_debian.c b/examples/solv/repoinfo_type_debian.c new file mode 100644 index 0000000..7a15ff4 --- /dev/null +++ b/examples/solv/repoinfo_type_debian.c @@ -0,0 +1,202 @@ +#ifdef ENABLE_DEBIAN + +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "repo_deb.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_download.h" +#include "repoinfo_type_debian.h" + +static const char * +debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep) +{ + char buf[4096]; + Id chksumtype; + unsigned char *chksum; + Id curchksumtype; + int l, compl; + char *ch, *fn, *bp; + char *filename; + static char *basearch; + char *binarydir; + int lbinarydir; + + if (!basearch) + { + struct utsname un; + if (uname(&un)) + { + perror("uname"); + exit(1); + } + basearch = strdup(un.machine); + if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86")) + basearch[1] = '3'; + } + binarydir = solv_dupjoin("binary-", basearch, "/"); + lbinarydir = strlen(binarydir); + compl = strlen(comp); + rewind(fp); + curchksumtype = 0; + filename = 0; + chksum = solv_malloc(32); + chksumtype = 0; + while(fgets(buf, sizeof(buf), fp)) + { + l = strlen(buf); + if (l == 0) + continue; + while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t')) + buf[--l] = 0; + if (!strncasecmp(buf, "MD5Sum:", 7)) + { + curchksumtype = REPOKEY_TYPE_MD5; + continue; + } + if (!strncasecmp(buf, "SHA1:", 5)) + { + curchksumtype = REPOKEY_TYPE_SHA1; + continue; + } + if (!strncasecmp(buf, "SHA256:", 7)) + { + curchksumtype = REPOKEY_TYPE_SHA256; + continue; + } + if (!curchksumtype) + continue; + bp = buf; + if (*bp++ != ' ') + { + curchksumtype = 0; + continue; + } + ch = bp; + while (*bp && *bp != ' ' && *bp != '\t') + bp++; + if (!*bp) + continue; + *bp++ = 0; + while (*bp == ' ' || *bp == '\t') + bp++; + while (*bp && *bp != ' ' && *bp != '\t') + bp++; + if (!*bp) + continue; + while (*bp == ' ' || *bp == '\t') + bp++; + fn = bp; + if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/') + continue; + bp += compl + 1; + if (strncmp(bp, binarydir, lbinarydir)) + continue; + bp += lbinarydir; + if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz")) + { + unsigned char curchksum[32]; + int curl; + if (filename && !strcmp(bp, "Packages")) + continue; + curl = solv_chksum_len(curchksumtype); + if (!curl || (chksumtype && solv_chksum_len(chksumtype) > curl)) + continue; + if (solv_hex2bin((const char **)&ch, curchksum, sizeof(curchksum)) != curl) + continue; + solv_free(filename); + filename = strdup(fn); + chksumtype = curchksumtype; + memcpy(chksum, curchksum, curl); + } + } + free(binarydir); + if (filename) + { + fn = solv_dupjoin("/", filename, 0); + solv_free(filename); + filename = solv_dupjoin("dists/", cinfo->name, fn); + solv_free(fn); + } + if (!chksumtype) + chksum = solv_free(chksum); + *chksump = chksum; + *chksumtypep = chksumtype; + return filename; +} + +int +debian_load(struct repoinfo *cinfo, Pool **sigpoolp) +{ + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + const char *filename; + const unsigned char *filechksum; + Id filechksumtype; + FILE *fp, *fpr; + int j; + + printf("debian repo '%s':", cinfo->alias); + fflush(stdout); + filename = solv_dupjoin("dists/", cinfo->name, "/Release"); + if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0) + { + printf(" no Release file\n"); + free((char *)filename); + cinfo->incomplete = 1; + return 0; + } + solv_free((char *)filename); + if (cinfo->repo_gpgcheck) + { + filename = solv_dupjoin("dists/", cinfo->name, "/Release.gpg"); + if (!downloadchecksig(cinfo, fpr, filename, sigpoolp)) + { + fclose(fpr); + solv_free((char *)filename); + cinfo->incomplete = 1; + return 0; + } + solv_free((char *)filename); + } + calc_cookie_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 1)) + { + printf(" cached\n"); + fclose(fpr); + return 1; + } + printf(" fetching\n"); + for (j = 0; j < cinfo->ncomponents; j++) + { + if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype))) + { + printf("[component %s not found]\n", cinfo->components[j]); + continue; + } + if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_debpackages(repo, fp, 0)) + { + printf("component %s: %s\n", cinfo->components[j], pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } + solv_free((char *)filechksum); + solv_free((char *)filename); + } + fclose(fpr); + writecachedrepo(cinfo, 0, 0); + return 1; +} + +#endif diff --git a/examples/solv/repoinfo_type_debian.h b/examples/solv/repoinfo_type_debian.h new file mode 100644 index 0000000..3dfc827 --- /dev/null +++ b/examples/solv/repoinfo_type_debian.h @@ -0,0 +1,2 @@ +extern int debian_load(struct repoinfo *cinfo, Pool **sigpoolp); + diff --git a/examples/solv/repoinfo_type_mdk.c b/examples/solv/repoinfo_type_mdk.c new file mode 100644 index 0000000..69287b3 --- /dev/null +++ b/examples/solv/repoinfo_type_mdk.c @@ -0,0 +1,220 @@ +#ifdef ENABLE_MDKREPO + +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "repo_mdk.h" +#include "solv_xfopen.h" + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_download.h" +#include "repoinfo_type_mdk.h" + +static int +mdk_find(const char *md5sums, const char *what, unsigned char *chksum) +{ + const char *sp, *ep; + int wl = strlen(what); + for (sp = md5sums; (ep = strchr(sp, '\n')) != 0; sp = ep + 1) + { + int l = ep - sp; + if (l <= 34) + continue; + if (sp[32] != ' ' || sp[33] != ' ') + continue; + if (wl != l - 34 || strncmp(what, sp + 34, wl) != 0) + continue; + if (solv_hex2bin(&sp, chksum, 16) != 16) + continue; + return 1; + } + return 0; +} + +static char * +slurp(FILE *fp) +{ + int l, ll; + char *buf = 0; + int bufl = 0; + + for (l = 0; ; l += ll) + { + if (bufl - l < 4096) + { + bufl += 4096; + 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; + break; + } + } + return buf; +} + +int +mdk_load_ext(Repo *repo, Repodata *data) +{ + struct repoinfo *cinfo = repo->appdata; + const char *type, *ext, *filename; + const unsigned char *filechksum; + Id filechksumtype; + int r = 0; + FILE *fp; + + type = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE); + if (strcmp(type, "filelists") != 0) + return 0; + ext = "FL"; + printf("[%s:%s", repo->name, ext); + if (usecachedrepo(cinfo, ext, 0)) + { + printf(" cached]\n"); fflush(stdout); + return 1; + } + printf(" fetching]\n"); fflush(stdout); + filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION); + filechksumtype = 0; + filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype); + if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0) + return 0; + r = repo_add_mdk_info(repo, fp, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL); + fclose(fp); + if (r) + { + printf("%s\n", pool_errstr(repo->pool)); + return 0; + } + writecachedrepo(cinfo, ext, 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) +{ + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + Repodata *data; + const char *compression; + FILE *fp, *cfp; + char *md5sums; + unsigned char probe[5]; + unsigned char md5[16]; + + printf("mdk repo '%s':", cinfo->alias); + fflush(stdout); + if ((fp = curlfopen(cinfo, "media_info/MD5SUM", 0, 0, 0, 0)) == 0) + { + printf(" no media_info/MD5SUM file\n"); + cinfo->incomplete = 1; + return 0; + } + calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 1)) + { + printf(" cached\n"); + fclose(fp); + return 1; + } + md5sums = slurp(fp); + fclose(fp); + printf(" fetching\n"); + if (!mdk_find(md5sums, "synthesis.hdlist.cz", md5)) + { + solv_free(md5sums); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + if ((fp = curlfopen(cinfo, "media_info/synthesis.hdlist.cz", 0, md5, REPOKEY_TYPE_MD5, 1)) == 0) + { + solv_free(md5sums); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + /* probe compression */ + if (fread(probe, 5, 1, fp) != 1) + { + fclose(fp); + solv_free(md5sums); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + if (probe[0] == 0xfd && memcmp(probe + 1, "7zXZ", 4) == 0) + compression = "synthesis.hdlist.xz"; + else + compression = "synthesis.hdlist.gz"; + lseek(fileno(fp), 0, SEEK_SET); + cfp = solv_xfopen_fd(compression, dup(fileno(fp)), "r"); + fclose(fp); + fp = cfp; + if (!fp) + { + solv_free(md5sums); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + if (repo_add_mdk(repo, fp, REPO_NO_INTERNALIZE)) + { + printf("synthesis.hdlist.cz: %s\n", pool_errstr(pool)); + fclose(fp); + solv_free(md5sums); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + fclose(fp); + /* add info, could do this on demand, but always having the summary is nice */ + if (mdk_find(md5sums, "info.xml.lzma", md5)) + { + if ((fp = curlfopen(cinfo, "media_info/info.xml.lzma", 1, md5, REPOKEY_TYPE_MD5, 1)) != 0) + { + if (repo_add_mdk_info(repo, fp, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES)) + { + printf("info.xml.lzma: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } + } + repo_internalize(repo); + data = repo_add_repodata(repo, 0); + /* setup on-demand loading of filelist data */ + if (mdk_find(md5sums, "files.xml.lzma", md5)) + { + 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); + writecachedrepo(cinfo, 0, 0); + repodata_create_stubs(repo_last_repodata(repo)); + return 1; +} + +#endif diff --git a/examples/solv/repoinfo_type_mdk.h b/examples/solv/repoinfo_type_mdk.h new file mode 100644 index 0000000..e98bc48 --- /dev/null +++ b/examples/solv/repoinfo_type_mdk.h @@ -0,0 +1,3 @@ +extern int mdk_load(struct repoinfo *cinfo, Pool **sigpoolp); +extern int mdk_load_ext(Repo *repo, Repodata *data); + diff --git a/examples/solv/repoinfo_type_rpmmd.c b/examples/solv/repoinfo_type_rpmmd.c new file mode 100644 index 0000000..7828379 --- /dev/null +++ b/examples/solv/repoinfo_type_rpmmd.c @@ -0,0 +1,214 @@ +#ifdef ENABLE_RPMMD + +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "repo_rpmmd.h" +#include "repo_deltainfoxml.h" +#include "repo_updateinfoxml.h" +#include "repo_repomdxml.h" +#ifdef ENABLE_APPDATA +#include "repo_appdata.h" +#endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_download.h" +#include "repoinfo_type_rpmmd.h" + + + +static const char * +repomd_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep) +{ + Pool *pool = repo->pool; + Dataiterator di; + const char *filename; + + filename = 0; + *chksump = 0; + *chksumtypep = 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); + *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, REPOSITORY_REPOMD_CHECKSUM, chksumtypep); + } + dataiterator_free(&di); + if (filename && !*chksumtypep) + { + printf("no %s file checksum!\n", what); + filename = 0; + } + return filename; +} + +static void +repomd_add_ext(Repo *repo, Repodata *data, const char *what, const char *ext) +{ + Id chksumtype, handle; + const unsigned char *chksum; + const char *filename; + + filename = repomd_find(repo, what, &chksum, &chksumtype); + if (!filename && !strcmp(what, "deltainfo")) + filename = repomd_find(repo, "prestodelta", &chksum, &chksumtype); + if (!filename) + return; + handle = repodata_new_handle(data); + 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 +repomd_load_ext(Repo *repo, Repodata *data) +{ + const char *filename, *repomdtype; + char ext[3]; + FILE *fp; + struct repoinfo *cinfo; + const unsigned char *filechksum; + Id filechksumtype; + int r = 0; + + cinfo = repo->appdata; + repomdtype = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE); + if (!repomdtype) + return 0; + if (!strcmp(repomdtype, "filelists")) + strcpy(ext, "FL"); + else if (!strcmp(repomdtype, "deltainfo")) + strcpy(ext, "DL"); + else + return 0; + printf("[%s:%s", repo->name, ext); + if (usecachedrepo(cinfo, ext, 0)) + { + printf(" cached]\n"); fflush(stdout); + return 1; + } + printf(" fetching]\n"); fflush(stdout); + filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION); + filechksumtype = 0; + filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype); + if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0) + return 0; + if (!strcmp(ext, "FL")) + r = repo_add_rpmmd(repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL); + else if (!strcmp(ext, "DL")) + r = repo_add_deltainfoxml(repo, fp, REPO_USE_LOADING); + fclose(fp); + if (r) + { + printf("%s\n", pool_errstr(repo->pool)); + return 0; + } + if (cinfo->extcookieset) + writecachedrepo(cinfo, ext, data); + return 1; +} + +int +repomd_load(struct repoinfo *cinfo, Pool **sigpoolp) +{ + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + Repodata *data; + const char *filename; + const unsigned char *filechksum; + Id filechksumtype; + FILE *fp; + + printf("rpmmd repo '%s':", cinfo->alias); + fflush(stdout); + if ((fp = curlfopen(cinfo, "repodata/repomd.xml", 0, 0, 0, 0)) == 0) + { + printf(" no repomd.xml file\n"); + cinfo->incomplete = 1; + return 0; + } + calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 1)) + { + printf(" cached\n"); + fclose(fp); + return 1; + } + if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "repodata/repomd.xml.asc", sigpoolp)) + { + fclose(fp); + cinfo->incomplete = 1; + return 0; + } + if (repo_add_repomdxml(repo, fp, 0)) + { + printf("repomd.xml: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + fclose(fp); + return 0; + } + fclose(fp); + printf(" fetching\n"); + filename = repomd_find(repo, "primary", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_rpmmd(repo, fp, 0, 0)) + { + printf("primary: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } + if (cinfo->incomplete) + return 0; /* hopeless */ + + filename = repomd_find(repo, "updateinfo", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_updateinfoxml(repo, fp, 0)) + { + printf("updateinfo: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } + +#ifdef ENABLE_APPDATA + filename = repomd_find(repo, "appdata", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + printf("appdata: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + 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); + writecachedrepo(cinfo, 0, 0); + repodata_create_stubs(repo_last_repodata(repo)); + return 1; +} + +#endif diff --git a/examples/solv/repoinfo_type_rpmmd.h b/examples/solv/repoinfo_type_rpmmd.h new file mode 100644 index 0000000..275dfc1 --- /dev/null +++ b/examples/solv/repoinfo_type_rpmmd.h @@ -0,0 +1,2 @@ +extern int repomd_load_ext(Repo *repo, Repodata *data); +extern int repomd_load(struct repoinfo *cinfo, Pool **sigpoolp); diff --git a/examples/solv/repoinfo_type_susetags.c b/examples/solv/repoinfo_type_susetags.c new file mode 100644 index 0000000..af933af --- /dev/null +++ b/examples/solv/repoinfo_type_susetags.c @@ -0,0 +1,281 @@ +#ifdef ENABLE_SUSEREPO + +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "chksum.h" +#include "repo_content.h" +#include "repo_susetags.h" +#ifdef ENABLE_APPDATA +#include "repo_appdata.h" +#endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_download.h" +#include "repoinfo_type_susetags.h" + +/* susetags helpers */ + +static const char * +susetags_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep) +{ + Pool *pool = repo->pool; + Dataiterator di; + const char *filename; + + filename = 0; + *chksump = 0; + *chksumtypep = 0; + dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, what, SEARCH_STRING); + dataiterator_prepend_keyname(&di, SUSETAGS_FILE); + if (dataiterator_step(&di)) + { + dataiterator_setpos_parent(&di); + *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, chksumtypep); + filename = what; + } + dataiterator_free(&di); + if (filename && !*chksumtypep) + { + printf("no %s file checksum!\n", what); + filename = 0; + } + return filename; +} + +static void +susetags_add_ext(Repo *repo, Repodata *data) +{ + Pool *pool = repo->pool; + Dataiterator di; + char ext[3]; + Id handle, filechksumtype; + const unsigned char *filechksum; + + dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, 0, 0); + dataiterator_prepend_keyname(&di, SUSETAGS_FILE); + while (dataiterator_step(&di)) + { + if (strncmp(di.kv.str, "packages.", 9) != 0) + continue; + if (!strcmp(di.kv.str + 9, "gz")) + continue; + if (!di.kv.str[9] || !di.kv.str[10] || (di.kv.str[11] && di.kv.str[11] != '.')) + continue; + ext[0] = di.kv.str[9]; + ext[1] = di.kv.str[10]; + ext[2] = 0; + if (!strcmp(ext, "en")) + continue; + if (!susetags_find(repo, di.kv.str, &filechksum, &filechksumtype)) + continue; + handle = repodata_new_handle(data); + repodata_set_str(data, handle, SUSETAGS_FILE_NAME, di.kv.str); + if (filechksumtype) + repodata_set_bin_checksum(data, handle, SUSETAGS_FILE_CHECKSUM, filechksumtype, filechksum); + add_ext_keys(data, handle, ext); + repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle); + } + dataiterator_free(&di); +} + +int +susetags_load_ext(Repo *repo, Repodata *data) +{ + const char *filename, *descrdir; + Id defvendor; + char ext[3]; + FILE *fp; + struct repoinfo *cinfo; + const unsigned char *filechksum; + Id filechksumtype; + int flags; + + cinfo = repo->appdata; + filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME); + if (!filename) + return 0; + /* susetags load */ + ext[0] = filename[9]; + ext[1] = filename[10]; + ext[2] = 0; + printf("[%s:%s", repo->name, ext); + if (usecachedrepo(cinfo, ext, 0)) + { + printf(" cached]\n"); fflush(stdout); + return 1; + } + printf(" fetching]\n"); fflush(stdout); + defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); + descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); + if (!descrdir) + descrdir = "suse/setup/descr"; + filechksumtype = 0; + filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype); + if ((fp = curlfopen(cinfo, pool_tmpjoin(repo->pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 0)) == 0) + return 0; + flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; + if (strcmp(ext, "DL") != 0) + flags |= REPO_LOCALPOOL; + if (repo_add_susetags(repo, fp, defvendor, ext, flags)) + { + fclose(fp); + printf("%s\n", pool_errstr(repo->pool)); + return 0; + } + fclose(fp); + writecachedrepo(cinfo, ext, data); + return 1; +} + +int +susetags_load(struct repoinfo *cinfo, Pool **sigpoolp) +{ + Repo *repo = cinfo->repo; + Pool *pool = repo->pool; + Repodata *data; + const char *filename; + const unsigned char *filechksum; + Id filechksumtype; + FILE *fp; + const char *descrdir; + int defvendor; + + printf("susetags repo '%s':", cinfo->alias); + fflush(stdout); + descrdir = 0; + defvendor = 0; + if ((fp = curlfopen(cinfo, "content", 0, 0, 0, 0)) == 0) + { + printf(" no content file\n"); + cinfo->incomplete = 1; + return 0; + } + calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie); + cinfo->cookieset = 1; + if (usecachedrepo(cinfo, 0, 1)) + { + printf(" cached\n"); + fclose(fp); + return 1; + } + if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "content.asc", sigpoolp)) + { + fclose(fp); + cinfo->incomplete = 1; + return 0; + } + if (repo_add_content(repo, fp, 0)) + { + printf("content: %s\n", pool_errstr(pool)); + fclose(fp); + cinfo->incomplete = 1; + return 0; + } + fclose(fp); + defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); + descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); + if (!descrdir) + descrdir = "suse/setup/descr"; + filename = susetags_find(repo, "packages.gz", &filechksum, &filechksumtype); + if (!filename) + filename = susetags_find(repo, "packages", &filechksum, &filechksumtype); + if (!filename) + { + printf(" no packages file entry, skipped\n"); + cinfo->incomplete = 1; + return 0; + } + printf(" fetching\n"); + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) == 0) + { + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES)) + { + printf("packages: %s\n", pool_errstr(pool)); + fclose(fp); + cinfo->incomplete = 1; + return 0; /* hopeless */ + } + fclose(fp); + /* add default language */ + filename = susetags_find(repo, "packages.en.gz", &filechksum, &filechksumtype); + if (!filename) + filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype); + if (filename) + { + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES)) + { + printf("packages.en: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } + } + filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype); + if (filename) + { + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0) + { + char pbuf[256]; + while (fgets(pbuf, sizeof(pbuf), fp)) + { + int l = strlen(pbuf); + FILE *fp2; + if (l && pbuf[l - 1] == '\n') + pbuf[--l] = 0; + if (!*pbuf || *pbuf == '.' || strchr(pbuf, '/') != 0) + continue; + filename = susetags_find(repo, pbuf, &filechksum, &filechksumtype); + if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE)) + { + printf("%s: %s\n", pbuf, pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp2); + } + } + fclose(fp); + } + } +#ifdef ENABLE_APPDATA + filename = susetags_find(repo, "appdata.xml.gz", &filechksum, &filechksumtype); + if (!filename) + filename = susetags_find(repo, "appdata.xml", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + printf("appdata: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } +#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); + repodata_create_stubs(repo_last_repodata(repo)); + return 1; +} + +#endif diff --git a/examples/solv/repoinfo_type_susetags.h b/examples/solv/repoinfo_type_susetags.h new file mode 100644 index 0000000..2ad5778 --- /dev/null +++ b/examples/solv/repoinfo_type_susetags.h @@ -0,0 +1,2 @@ +extern int susetags_load_ext(Repo *repo, Repodata *data); +extern int susetags_load(struct repoinfo *cinfo, Pool **sigpoolp); diff --git a/examples/solv/solv.c b/examples/solv/solv.c new file mode 100644 index 0000000..3deb1a0 --- /dev/null +++ b/examples/solv/solv.c @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2009-2015, SUSE LLC. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* solv, a little software installer demoing the sat solver library */ + +/* things it does: + * - understands globs for package names / dependencies + * - understands .arch suffix + * - installation of commandline packages + * - repository data caching + * - on demand loading of secondary repository data + * - gpg and checksum verification + * - file conflicts + * - deltarpm support + * - fastestmirror implementation + * + * things available in the library but missing from solv: + * - vendor policy loading + * - multi version handling + */ + +#include +#include +#include +#include + +#include "pool.h" +#include "poolarch.h" +#include "evr.h" +#include "selection.h" +#include "repo.h" +#include "solver.h" +#include "solverdebug.h" +#include "transaction.h" +#include "testcase.h" +#ifdef SUSE +#include "repo_autopattern.h" +#endif + +#include "repoinfo.h" +#include "repoinfo_cache.h" +#include "repoinfo_download.h" + +#if defined(ENABLE_RPMDB) +#include "fileprovides.h" +#include "fileconflicts.h" +#include "deltarpm.h" +#endif +#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA) +#include "patchjobs.h" +#endif + +void +setarch(Pool *pool) +{ + struct utsname un; + if (uname(&un)) + { + perror("uname"); + exit(1); + } + pool_setarch(pool, un.machine); +} + + +int +yesno(const char *str, int other) +{ + char inbuf[128], *ip; + + for (;;) + { + printf("%s", str); + fflush(stdout); + *inbuf = 0; + if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) + { + printf("Abort.\n"); + exit(1); + } + while (*ip == ' ' || *ip == '\t') + ip++; + if (*ip == 'q') + { + printf("Abort.\n"); + exit(1); + } + if (*ip == 'y' || *ip == 'n' || *ip == other) + return *ip == 'n' ? 0 : *ip; + } +} + +#ifdef SUSE +static Id +nscallback(Pool *pool, void *data, Id name, Id evr) +{ +#if 0 + if (name == NAMESPACE_LANGUAGE) + { + if (!strcmp(pool_id2str(pool, evr), "ja")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "de")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en_US")) + return 1; + } +#endif + return 0; +} +#endif + +#ifdef SUSE +static void +showdiskusagechanges(Transaction *trans) +{ + DUChanges duc[4]; + int i; + + /* XXX: use mountpoints here */ + memset(duc, 0, sizeof(duc)); + duc[0].path = "/"; + duc[1].path = "/usr/share/man"; + duc[2].path = "/sbin"; + duc[3].path = "/etc"; + transaction_calc_duchanges(trans, duc, 4); + for (i = 0; i < 4; i++) + printf("duchanges %s: %lld K %lld inodes\n", duc[i].path, duc[i].kbytes, duc[i].files); +} +#endif + +static Id +find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) +{ + const char *rp; + int i; + + for (rp = name; *rp; rp++) + if (*rp <= '0' || *rp >= '9') + break; + if (!*rp) + { + /* repo specified by number */ + int rnum = atoi(name); + for (i = 0; i < nrepoinfos; i++) + { + struct repoinfo *cinfo = repoinfos + i; + if (!cinfo->enabled || !cinfo->repo) + continue; + if (--rnum == 0) + return cinfo->repo->repoid; + } + } + else + { + /* repo specified by alias */ + Repo *repo; + FOR_REPOS(i, repo) + { + if (!strcasecmp(name, repo->name)) + return repo->repoid; + } + } + return 0; +} + +#define MODE_LIST 0 +#define MODE_INSTALL 1 +#define MODE_ERASE 2 +#define MODE_UPDATE 3 +#define MODE_DISTUPGRADE 4 +#define MODE_VERIFY 5 +#define MODE_PATCH 6 +#define MODE_INFO 7 +#define MODE_REPOLIST 8 +#define MODE_SEARCH 9 + +void +usage(int r) +{ + fprintf(stderr, "Usage: solv COMMAND